<!--{{{-->
<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>>
[[Grolog Colloquium]], speaker: Partrick Girard
See [[Grolog Colloquium]] of Rohit Parikh
PCCP seminar, Philosophy Dept.
[[Groningen-Amsterdam Dynamic Seminar]] session in Groningen, starts at 14h
[[Grolog Colloquium]], speaker: Catarina Dutilh -Novaes
[[Grolog Colloquium]]
[[Grolog Colloquium]], speaker: Ram Ramanujam
[[Grolog Colloquium]]
[[Grolog Colloquium]], speaker: Eric Pacuit
[[Grolog Colloquium]]
PCCP seminar, Philosophy Dept.
[[Groningen-Amsterdam Dynamic Seminar]]
SOFT, seminar on formal topics, philosophy department, time t.b.a.
PCCP seminar, philosophy dept.
Symposium Philosophy Dept.
[[Grolog Colloquium]], speaker: Catarina Dutilh Novaes
PCCP seminar Philosophy Dept.
SOFT, seminar on formal topics, philosophy department, 15h15.
[[Grolog Colloquium]], speaker: francesca poggiolesi 
See [[Grolog Colloquium]] of Hans van Ditmarsch
** Seminar on Formal Topics (SOFT) 
from 13.30 to 15.00, in room beta, Philosophy Dept. RUG
[[Dynamic seminar|http://www.illc.uva.nl/lgc/seminar/?p=408]] in Amsterdam, 14h
This notebook attempts to capture the essence of a [["kinkless" GTD system|http://www.kinkless.com]] using TiddlyWiki. It is using the <<gtdVersion>> version of the GTD plugins, by Tom Otvos, and is based on version <<version>> of the [[TiddlyWiki|http://www.tiddlywiki.com]] stand-alone wiki project, by Jeremy Ruston. For customization info, see [[GTD TiddlyWiki|http://groups.google.com/group/GTD-TiddlyWiki]] and [[TiddlyWikiDev|http://www.tiddlywiki.com/dev/]].
Contact us via email at: grolog {at} ai.rug.nl. 
!Welcome to version 1.3.0 of d-cubed

This is a minor update to the previous 1.2 release of d-cubed, providing compatibility with the latest (2.4.1 as of this writing) version of TiddlyWiki. This release does not introduce any new features beyond the greatly expanded capabilities of TiddlyWiki itself. It does fix several minor bugs, including:
* fix if two contexts are open, and action in first context is complete, then other context will not show next action correctly
* no longer rely on NewerTiddlerPlugin in GTDMenu, avoiding compatibility bugs
* removed obsolete plugins, including TWUpdate and NewerTiddlerPlugin
* updated GTDMenu to include sliders for "reference" and "someday" tiddlers
''Important note to upgraders:'' Because of the changes to TiddlyWiki, it is not possible to upgrade to this new version from version 1.2 using the normal UpdateApplication you are familiar with. Indeed, the only way to get this new version is to start with an empty d-cubed document, and import your projects, actions, and contexts from your existing d-cubed document. If you are reading this tiddler, you have taken the first step! For the full upgrade procedure, please read [[Upgrading from version 1.2]].

----
If you are a regular user of d-cubed and would like contribute in some way, there is now a "tip jar" available. Just click on the button below:

<html>
<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
<input type="hidden" name="cmd" value="_s-xclick">
<input type="image" src="https://www.paypal.com/en_US/i/btn/x-click-but21.gif" border="0" name="submit" alt="Make payments with PayPal - it's fast, free and secure!">
<img alt="" border="0" src="https://www.paypal.com/en_US/i/scr/pixel.gif" width="1" height="1">
<input type="hidden" name="encrypted" value="-----BEGIN PKCS7-----MIIHRwYJKoZIhvcNAQcEoIIHODCCBzQCAQExggEwMIIBLAIBADCBlDCBjjELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRQwEgYDVQQKEwtQYXlQYWwgSW5jLjETMBEGA1UECxQKbGl2ZV9jZXJ0czERMA8GA1UEAxQIbGl2ZV9hcGkxHDAaBgkqhkiG9w0BCQEWDXJlQHBheXBhbC5jb20CAQAwDQYJKoZIhvcNAQEBBQAEgYArqELycEhlEeU4Ikv7/arlOM92IKDYe4nhYuHcGQlAg7wtuL0XiBzeUog47f9Bh6mOch2fYU739g1LRdmPCGXFC+/FUhiHtC0WzzoM9Ze5brDxX55ZMRYcSW8r+F/+8f1fbjQLKQOweWzfB87c9atRjhIivYizx582Z10qJEN3uDELMAkGBSsOAwIaBQAwgcQGCSqGSIb3DQEHATAUBggqhkiG9w0DBwQIWXCtKBKQVOqAgaApYeMrVxuoRQ/0OILmlaCiziXXCg0VMf39lT6qFy12dsom2u/b56rCay/s/vyWzdDZgpdV3wUqChgTrHIjaaJUIQ15ITyskbYDDWMMEwp5f5UEy6Y/fDtugF7sGknAvEL+G6QtQv8su4Nlqu1EWOptSlvuuPokBBwKM6J2elMzds4x1ug/9L7WAheCNKXP1bR+VOskaCKnT71m23cfyceHoIIDhzCCA4MwggLsoAMCAQICAQAwDQYJKoZIhvcNAQEFBQAwgY4xCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEUMBIGA1UEChMLUGF5UGFsIEluYy4xEzARBgNVBAsUCmxpdmVfY2VydHMxETAPBgNVBAMUCGxpdmVfYXBpMRwwGgYJKoZIhvcNAQkBFg1yZUBwYXlwYWwuY29tMB4XDTA0MDIxMzEwMTMxNVoXDTM1MDIxMzEwMTMxNVowgY4xCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEUMBIGA1UEChMLUGF5UGFsIEluYy4xEzARBgNVBAsUCmxpdmVfY2VydHMxETAPBgNVBAMUCGxpdmVfYXBpMRwwGgYJKoZIhvcNAQkBFg1yZUBwYXlwYWwuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDBR07d/ETMS1ycjtkpkvjXZe9k+6CieLuLsPumsJ7QC1odNz3sJiCbs2wC0nLE0uLGaEtXynIgRqIddYCHx88pb5HTXv4SZeuv0Rqq4+axW9PLAAATU8w04qqjaSXgbGLP3NmohqM6bV9kZZwZLR/klDaQGo1u9uDb9lr4Yn+rBQIDAQABo4HuMIHrMB0GA1UdDgQWBBSWn3y7xm8XvVk/UtcKG+wQ1mSUazCBuwYDVR0jBIGzMIGwgBSWn3y7xm8XvVk/UtcKG+wQ1mSUa6GBlKSBkTCBjjELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRQwEgYDVQQKEwtQYXlQYWwgSW5jLjETMBEGA1UECxQKbGl2ZV9jZXJ0czERMA8GA1UEAxQIbGl2ZV9hcGkxHDAaBgkqhkiG9w0BCQEWDXJlQHBheXBhbC5jb22CAQAwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOBgQCBXzpWmoBa5e9fo6ujionW1hUhPkOBakTr3YCDjbYfvJEiv/2P+IobhOGJr85+XHhN0v4gUkEDI8r2/rNk1m0GA8HKddvTjyGw/XqXa+LSTlDYkqI8OwR8GEYj4efEtcRpRYBxV8KxAW93YDWzFGvruKnnLbDAF6VR5w/cCMn5hzGCAZowggGWAgEBMIGUMIGOMQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExFjAUBgNVBAcTDU1vdW50YWluIFZpZXcxFDASBgNVBAoTC1BheVBhbCBJbmMuMRMwEQYDVQQLFApsaXZlX2NlcnRzMREwDwYDVQQDFAhsaXZlX2FwaTEcMBoGCSqGSIb3DQEJARYNcmVAcGF5cGFsLmNvbQIBADAJBgUrDgMCGgUAoF0wGAYJKoZIhvcNAQkDMQsGCSqGSIb3DQEHATAcBgkqhkiG9w0BCQUxDxcNMDcwMjEzMjIyODI4WjAjBgkqhkiG9w0BCQQxFgQUT2cBzuxL2aED6PhQaLoEbTd+PEYwDQYJKoZIhvcNAQEBBQAEgYAZfdUgTGt3yxXci0obaP0sP7CmwzdmlqYu92W24sITRc1j/+gNvyqLpCtRkRHFT0FFZqqukwopZPE4/VCM496TqcVaQMXZAi9jVyrniLA3BEKY8VCrLYqW3pnf87TLfLOe9Y65FlT3Sx4EKwLCNIhYwojgx6lZXo+TNVCWhMBmHQ==-----END PKCS7-----
">
</form>
</html>
No pressure, no obligation, but thank you if you do!

//This tiddler will only open automatically the first time you run d-cubed after an update. After that, you can freely delete it, or save it for future reference. If this is a new d-cubed document, it may not go away until after you edit DefaultTiddlers.//
! Next actions for active contexts
<<gtdActionList @>>
To make this system operate more efficiently, you should periodically archive completed projects and actions. When a project or action is archived, it is merely tagged in a special way to get it "out of sight", but all the information in the project and action tiddlers is preserved. This is important if you need to go back and find something. Click one of these buttons to view the current <<tag project-archive>> or <<tag action-archive>>.

** Click <<gtdArchive archive>> if you would like to archive all completed projects and actions now.
** Click <<gtdArchive unarchive>> if you would like to unarchive all previously archived projects and actions now.

If you are sure that you do not want to retain archived projects and actions, you can purge them completely from the system. //Once these archived items are removed, the only way they can be put back in is through manual importing or copy/paste.// ''For your safety, your file will be saved and a backup file will be automatically generated before an archive purge is performed.''

** Click <<gtdArchive purge>> if you would like to purge your archive now.
/***
|Name|CalendarPlugin|
|Source|http://www.TiddlyTools.com/#CalendarPlugin|
|Version|2008.06.17|
|Author|Eric Shulman|
|Original Author|SteveRumsby|
|License|unknown|
|~CoreVersion|2.1|
|Type|plugin|
|Requires||
|Overrides||
|Options|##Configuration|
|Description|display monthly and yearly calendars|

NOTE: For enhanced date display (including popups), you must also install [[DatePlugin]]
!!!!!Usage:
<<<
|{{{<<calendar>>}}}|Produce a full-year calendar for the current year|
|{{{<<calendar year>>}}}|Produce a full-year calendar for the given year|
|{{{<<calendar year month>>}}}|Produce a one-month calendar for the given month and year|
|{{{<<calendar thismonth>>}}}|Produce a one-month calendar for the current month|
|{{{<<calendar lastmonth>>}}}|Produce a one-month calendar for last month|
|{{{<<calendar nextmonth>>}}}|Produce a one-month calendar for next month|
<<<
!!!!!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
<<<
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 section:
***/
//{{{
version.extensions.calendar = { major: 0, minor: 7, revision: 0, date: new Date(2008, 6, 17)};

if(config.options.txtCalFirstDay == undefined)
  config.options.txtCalFirstDay = 0;
if(config.options.txtCalStartOfWeekend == undefined)
  config.options.txtCalStartOfWeekend = 5;
if(config.options.chkDisplayWeekNumbers == undefined)//wn**
  config.options.chkDisplayWeekNumbers = false;
if(config.options.chkDisplayWeekNumbers)
  config.options.txtCalFirstDay = 0;
if(config.options.txtWeekNumberDisplayFormat == undefined)//wn**
  config.options.txtWeekNumberDisplayFormat = "w0WW";
if(config.options.txtWeekNumberLinkFormat == undefined)//wn**
  config.options.txtWeekNumberLinkFormat = "YYYY-w0WW";

config.macros.calendar = {};
config.macros.calendar.monthnames = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
config.macros.calendar.daynames = ["M", "T", "W", "T", "F", "S", "S"];
config.macros.calendar.todaybg = "#ccccff";
config.macros.calendar.weekendbg = "#c0c0c0";
config.macros.calendar.monthbg = "#e0e0e0";
config.macros.calendar.holidaybg = "#ffc0c0";
config.macros.calendar.journalDateFmt = "DD MMM YYYY";
config.macros.calendar.monthdays = [ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
config.macros.calendar.holidays = [ ]; // Not sure this is required anymore - use reminders instead
//}}}
//{{{
function calendarIsHoliday(date) // Is the given date a holiday?
{
	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", null, null, null);
	var today = new Date();
	var year = today.getYear();
	if (year<1900) year+=1900;

 	// get format for journal link by reading from SideBarOptions (ELS 5/29/06 - based on suggestion by Martin Budden)
	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]; }

	if (params[0] == "thismonth") {
		cacheReminders(new Date(year, today.getMonth(), 1, 0, 0), 31);
		createCalendarOneMonth(tbody, year, today.getMonth());
	} 
	else if (params[0] == "lastmonth") {
		var month = today.getMonth()-1; if (month==-1) { month=11; year--; }
		cacheReminders(new Date(year, month, 1, 0, 0), 31);
		createCalendarOneMonth(tbody, year, month);
	}
	else if (params[0] == "nextmonth") {
		var month = today.getMonth()+1; if (month>11) { month=0; year++; }
		cacheReminders(new Date(year, month, 1, 0, 0), 31);
		createCalendarOneMonth(tbody, year, month);
	} else {
		if (params[0]) year = params[0];
		if(params[1]) {
			cacheReminders(new Date(year, params[1]-1, 1, 0, 0), 31);
			createCalendarOneMonth(tbody, year, params[1]-1);
		} else {
			cacheReminders(new Date(year, 0, 1, 0, 0), 366);
			createCalendarYear(tbody, year);
		}
	}
	window.reminderCacheForCalendar = null;
}
//}}}
//{{{
//This global variable is used to store reminders that have been cached
//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", null, null, null);
	createCalendarMonthHeader(calendar, row, config.macros.calendar.monthnames[mon] + " " + year, true, year, mon);
	row = createTiddlyElement(calendar, "tr", null, null, null);
	createCalendarDayHeader(row, 1);
	createCalendarDayRowsSingle(calendar, year, mon);
}
//}}}
//{{{
function createCalendarMonth(calendar, year, mon)
{
	var row = createTiddlyElement(calendar, "tr", null, null, null);
	createCalendarMonthHeader(calendar, row, config.macros.calendar.monthnames[mon] + " " + year, false, year, mon);
	row = createTiddlyElement(calendar, "tr", null, null, null);
	createCalendarDayHeader(row, 1);
	createCalendarDayRowsSingle(calendar, year, mon);
}
//}}}
//{{{
function createCalendarYear(calendar, year)
{
	var row;
	row = createTiddlyElement(calendar, "tr", null, null, null);
	var back = createTiddlyElement(row, "td", null, null, null);
	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", null, null, null);
	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", null, null, null);
	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", null, null, null);
	createCalendarDayHeader(row, 3);
	createCalendarDayRows(cal, year, mon);
}
//}}}
//{{{
function createCalendarMonthHeader(cal, row, name, nav, year, mon)
{
	var month;
	if (nav) {
		var back = createTiddlyElement(row, "td", null, null, null);
		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 = 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", null, null, null);
		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 = 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", null, null, null);//wn**
	}
	for(i = 0; i < col; i++)
		createTiddlyElement(row, "td", null, null, null);
	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", null, null, null);
		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 2005.10.30: use <<date>> macro's showDate() function to create popup
			// ELS 5/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++;
	}
}
//}}}
//{{{
// We've clicked on a day in a calendar - create a suitable pop-up of options.
// The pop-up should contain:
//  * a link to create a new entry for that date
//  * a link to create a new reminder for that date
//  * an <hr>
//  * the list of reminders for that date
// NOTE: The following code is only used when [[DatePlugin]] is not present
function onClickCalendarDate(e)
{
	var button = this;
	var date = button.getAttribute("title");
	var dat = new Date(date.substr(6,4), date.substr(3,2)-1, date.substr(0, 2));

	date = dat.formatString(config.macros.calendar.journalDateFmt);
	var popup = createTiddlerPopup(this);
	popup.appendChild(document.createTextNode(date));
	var newReminder = function() {
		var t = store.getTiddlers(date);
		displayTiddler(null, date, 2, null, null, false, false);
		if(t) {
			document.getElementById("editorBody" + date).value += "\n<<reminder day:" + dat.getDate() +
				" month:" + (dat.getMonth()+1) + " year:" + (dat.getYear()+1900) + " title: >>";
		} else {
			document.getElementById("editorBody" + date).value = "<<reminder day:" + dat.getDate() +
				" month:" + (dat.getMonth()+1) +" year:" + (dat.getYear()+1900) + " title: >>";
		}
		return false; // consume click
	};
	var link = createTiddlyButton(popup, "New reminder", null, newReminder); 
	popup.appendChild(document.createElement("hr"));
	var t = findTiddlersWithReminders(dat, [0,14], null, 1);
	for(var i = 0; i < t.length; i++) {
		link = createTiddlyLink(popup, t[i].tiddler, false);
		link.appendChild(document.createTextNode(t[i].tiddler));
	}
	return false; // consume click
}
//}}}
//{{{
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", null, null, null);
	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", null, null, null);
		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", null, null, null);
	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", null, null, null);
		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");
//}}}
These configuration options enable you to customize the default behaviour of this wiki. They are saved locally as cookies, just like other TiddlyWiki configuration options. Note that in some cases, you will need to reload the document for the changes to take effect.

!!Action display settings
This value, if specified, is a semi-colon-delimited list of tags that are used to prioritize projects and actions for those projects. If left blank, the single priority tag "important" is used to sort projects. Otherwise, the specified tags are used in the listed order of importance, the first tag being most important (you will need to reload the document to see your change):
<<option txtGTDProjectPriorities>>

This value, if specified, is the number of days to keep completed actions in context and review action lists (leave blank to show all unarchived, completed actions):
<<option txtGTDActionAging>>

!!Magic tags
The following tag is used for the "reference" context, used to identify tiddlers that show up in the [[Reference]] list: 
<<option txtGTDReferenceContext>>

The following tag is used for the "someday-maybe" context, used to identify tiddlers that show up in the [[Someday-Maybe]] list:
<<option txtGTDSomedayContext>>

The following tag is used for the "unfiled" context, used to tag actions when the context is not known (such as orphaned actions from a deleted context):
<<option txtGTDUnfiledContext>>

!!Miscellaneous functionality
<<option chkGTDLazyAutoSave>> Use this checkbox to enable or disable "lazy" autosaving of changes to your document. If turned on, then the autosave will fire every <<option txtGTDLazyAutoSaveInterval>> seconds.
/***
|Name|CoreTweaks|
|Source|http://www.TiddlyTools.com/#CoreTweaks|
|Version|n/a|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.2.4|
|Type|plugin|
|Requires||
|Overrides|various|
|Description|a small collection of overrides to TW core functions|
This tiddler contains some quick tweaks and modifications to TW core functions to provide minor changes in standard features or behavior.  It is hoped that some of these tweaks may be incorporated into later versions of the TW core, so that these adjustments will be available without needing these add-on definitions. ''Note: the changes contained in this tiddler are generally applicable for the current version of TiddlyWiki (<<version>>)./% Please view [[CoreTweaksArchive]] for tweaks and modifications that may be used with earlier versions of TiddlyWiki.%/''

To install //all// of these tweaks, import (or copy/paste) this tiddler into your document.  To include only //some// of the tweaks, you can edit the imported tiddler to remove the tweaks that you don't want.  Alternatively, you could copy/paste a few selected tweaks from this tiddler into a tiddler that you create in your own document.  Be certain to tag that tiddler with<<tag systemConfig>> (i.e., a plugin tiddler) and then save-and-reload for the tweaks to take effect.
***/
/***
!!! Ticketed Tweaks
***/
// // {{groupbox small{
/***
!!FireFox3 Import bug: "browse" button replacement
http://trac.tiddlywiki.org/ticket/683 - OPEN
see also http://trac.tiddlywiki.org/ticket/604 - cross-platform askForFilename()
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.
***/
//{{{
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; 
}
//}}}
// // }}}
// // {{groupbox small{
/***
!!cross-platform askForFilename()
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.persistentDescriptor;
	}
	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()); }
}
//}}}
// // }}}
// // {{groupbox small{
/***
!!#story:... paramifier
http://trac.tiddlywiki.org/ticket/676 - OPEN
scan the specified 'story' tiddler content for embedded links, rather than simply parsing the content as a space-separated bracketed list.  This allows links from ''any'' tiddler to be used as a story, regardless of other wiki-syntax contained in that tiddler.  If specified tiddler is a shadow, fallback to using parseParams() to extract the list of links.
***/
//{{{
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);
	}
};
//}}}
// // }}}
// // {{groupbox small{
/***
!!Loose links (case-folded/space-folded wiki words)
http://trac.tiddlywiki.org/ticket/664 - OPEN
This tweak matches 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
>{{{usage: <<option chkLooseLinks>>}}}
***/
//{{{
if (!config.options.chkLooseLinks)
	config.options.chkLooseLinks=false; // default to standard behavior
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 target=title.toLowerCase().replace(/\s/g,"");
	var tids=store.getTiddlers("title");
	for (var t=0; t<tids.length; t++) {
		if (tids[t].title.toLowerCase().replace(/\s/g,"")==target) {
			var i=getTiddlyLinkInfo(tids[t].title,className);
			btn.setAttribute("tiddlyLink",tids[t].title);
			btn.title=i.subTitle;
			btn.className=i.classes;
			break;
		}
	}
	return btn;
}
//}}}
// // }}}
// // {{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]);
};
//}}}
// // }}}
// // {{groupbox small{
// // http://trac.tiddlywiki.org/ticket/637 - OPEN
// // 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^^
// // Tiddler link tooltip date format:
// // {{stretch{<<option txtTiddlerLinkTooltipDate>>}}}
//{{{
config.messages.tiddlerLinkTooltip="%0 - %1, %2 (%3 bytes)";
config.messages.tiddlerLinkTooltipDate="DDD, MMM DDth YYYY 0hh12:0mm AM";

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

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;
	return config.options.txtTiddlerLinkTootip.format([this.title,modifier,modified,this.text.length]);
};
//}}}
// // }}}
// // {{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);
}
//}}}
// // }}}
// // {{groupbox small{
// // http://trac.tiddlywiki.org/ticket/609 - OPEN (separators)
// // http://trac.tiddlywiki.org/ticket/610 - OPEN (wikify tiddler/slice/section content)
// // These tweaks extend the {{{<<toolbar>>}}} macro to permit use of "|" as separators, as well as recognizing references to tiddlernames, slices, or sections and rendering their content inline within the toolbar
// // ''see [[ToolbarCommands]] for examples of how these features can be used''
//{{{
merge(config.macros.toolbar,{
	separator: "|"
	});
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
			case '!':  // ELS - SEPARATOR (alternative for use in tiddler slices)
				createTiddlyText(place,this.separator); // ELS
				break; // ELS
			case '>':
				var btn = createTiddlyButton(place,this.moreLabel,this.morePrompt,config.macros.toolbar.onClickMore);
				addClass(btn,"moreCommand");
				var e = createTiddlyElement(place,"span",null,"moreCommand");
				e.style.display = "none";
				place = e;
				break;
			default:
				var theClass = "";
				switch(c.substr(0,1)) {
					case "+":
						theClass = "defaultCommand";
						c = c.substr(1);
						break;
					case "-":
						theClass = "cancelCommand";
						c = c.substr(1);
						break;
				}
				if(c in config.commands)
					this.createCommand(place,c,tiddler,theClass);
				else { // ELS - WIKIFY TIDDLER/SLICE/SECTION
					if (c.substr(0,1)=="~") c=c.substr(1); // ignore leading ~
					var txt=store.getTiddlerText(c);
					if (txt) {
						txt=txt.replace(/^\n*/,"").replace(/\n*$/,""); // trim any leading/trailing newlines
						txt=txt.replace(/^\{\{\{\n/,"").replace(/\n\}\}\}$/,""); // trim PRE format wrapper if any
						wikify(txt,createTiddlyElement(place,"span"),null,tiddler);
					}
				} // ELS - end WIKIFY CONTENT
				break;
		}
	}
};
//}}}
// // }}}
// // {{groupbox small{
// // http://trac.tiddlywiki.org/ticket/608 - OPEN
// // This tweak extends the {{{<<toolbar>>}}} macro to make the ">" (more) a //toggle// between more/less with the additional toolbar commands displayed on a separate line.
//{{{
merge(config.macros.toolbar,{
	moreLabel: 'more',
	morePrompt: "Show additional commands",
	lessLabel: 'less',
	lessPrompt: "Hide additional commands"
});
config.macros.toolbar.onClickMore = function(ev)
{
	var e = this.nextSibling;
	var showing=e.style.display=="block";
	e.style.display = showing?"none":"block";
	this.innerHTML=showing?config.macros.toolbar.moreLabel:config.macros.toolbar.lessLabel;
	this.title=showing?config.macros.toolbar.morePrompt:config.macros.toolbar.lessPrompt;
	return false;
};
//}}}
// // }}}
// // {{groupbox small{
// // http://trac.tiddlywiki.org/ticket/607 - OPEN
// // 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(" "));
}
//}}}
// // }}}
// // {{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;
};
}
//}}}
// // }}}
// // {{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;
}
//}}}
// // }}}
// // {{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;
}
//}}}
// // }}}
// // {{groupbox small{
// // http://trac.tiddlywiki.org/ticket/444 - OPEN
// // 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.
//{{{
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")):null;
	window.place=place;
	window.coreTweaks_invokeMacro.apply(this,arguments);
}
//}}}
// // }}}
// // {{groupbox small{
// // http://trac.tiddlywiki.org/ticket/401 - CLOSED: WON'T FIX
// // This tweak allows definition of an optional [[PageTitle]] 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)
//{{{
window.coreTweaks_getPageTitle=window.getPageTitle;
window.getPageTitle=function() { 
	var txt=wikifyPlain("PageTitle"); if (txt.length) return txt;
	return window.coreTweaks_getPageTitle.apply(this,arguments);
}
store.addNotification("PageTitle",refreshPageTitle); // so title stays in sync with tiddler changes
//}}}
// // }}}
// // {{groupbox small{
// // http://trac.tiddlywiki.org/ticket/67 - OPEN
// // The "missing links" list includes items contained within "quoted" text (i.e., content that will not render as wiki-syntax, and so CANNOT create any tiddler links, even if the quoted text matches valid link syntax).  This tweak removes content contained between certain delimiters before scanning tiddler source for possible links.
/***
Delimiters include:
{{{
/%...%/
{{{...}}}
"""..."""
<nowiki>...</nowiki>
<html>...</html>
<script>...</script>
}}}
***/
//{{{
Tiddler.prototype.coreTweaks_changed = Tiddler.prototype.changed;
Tiddler.prototype.changed = function()
{
	var savedtext=this.text;
	// remove 'quoted' text before scanning tiddler source
	this.text=this.text.replace(/\/%((?:.|\n)*?)%\//g,""); // /%...%/
	this.text=this.text.replace(/\{{3}((?:.|\n)*?)\}{3}/g,""); // {{{...}}}
	this.text=this.text.replace(/"{3}((?:.|\n)*?)"{3}/g,""); // """..."""
	this.text=this.text.replace(/\<nowiki\>((?:.|\n)*?)\<\/nowiki\>/g,""); // <nowiki>...</nowiki>
	this.text=this.text.replace(/\<html\>((?:.|\n)*?)\<\/html\>/g,""); // <html>...</html>
	this.text=this.text.replace(/\<script((?:.|\n)*?)\<\/script\>/g,""); // <script>...</script>
	this.coreTweaks_changed.apply(this,arguments);
	// restore quoted text to tiddler source
	this.text=savedtext;
};
//}}}
// // }}}
/***
!!! Fixed in current release (TW<<version>>)
***/
// // {{groupbox small{
// // calculate version number for conditional inclusion of tweaks below...
//{{{
var ver=version.major+version.minor/10+version.revision/100;
//}}}
// // }}}
// // {{groupbox small{
/***
!!#filter:"..." paramifier
http://trac.tiddlywiki.org/ticket/678 - FIXED IN TW241
displays all tiddlers that match any filter criteria (including tag-matching), using the {{{store.filterTiddlers()}}} syntax.  Note use of double-quotes to enclose value to ensure that square-brackets within filter syntax are passed through for processing.
***/
//{{{
if (ver<2.41) {
config.paramifiers.filter = {
	onstart: function(v) {
		var tagged = store.filterTiddlers(v);
		story.displayTiddlers(null,tagged,null,false,null);
	}
};
}
//}}}
// // }}}
// // {{groupbox small{
/***
!!#tag:... paramifier
http://trac.tiddlywiki.org/ticket/677 - FIXED IN TW241
use {{{store.filterTiddlers()}}} instead of {{{store.getTaggedTiddlers()}}}.  This permits enhanced tag-matching logic (such as boolean expression processing provided by [[MatchTagsPlugin]]) to be used, e.g., {{{#tag:"tag1 OR (tag2 AND NOT tag3)"}}}, instead of simply matching a single tag value.
***/
//{{{
if (ver<2.41) {
config.paramifiers.tag = {
	onstart: function(v) {
		var tagged = store.filterTiddlers("[tag["+v+"]]");
		story.displayTiddlers(null,tagged,null,false,null);
	}
};
}
//}}}
// // }}}
// // {{groupbox small{
/***
!!#recent:... paramifier
http://trac.tiddlywiki.org/ticket/675 - FIXED IN TW241
automatically display the N most recently changed tiddlers.  N is, of course, an integer number.  If N=0 (or is not a numeric value), the regular [[DefaultTiddlers]] will be displayed.
***/
//{{{
if (ver<2.41) {
config.paramifiers.recent= {
	onstart: function(v) {
		var titles=[];
		var tids=store.getTiddlers("modified","excludeLists").reverse();
		for (var t=0; t<v && t<tids.length; t++) titles.push(tids[t].title);
		story.displayTiddlers(null,titles); 
	}
};
}
//}}}
// // }}}
// // {{groupbox small{
// // http://trac.tiddlywiki.org/ticket/635 - FIXED IN TW241
// // When using backstage>import "browse" button, resulting URL is improperly formed with "file://" prefix instead of "file:///" prefix.  This causes errors when using Firefox 3 (beta) or when running under Windows Vista OS.
// // http://trac.tiddlywiki.org/ticket/638 - FIXED IN TW241
// // When entering text directly into path/file field, each keystroke is displayed and then discarded, preventing manual entry of path/file.
// // http://trac.tiddlywiki.org/ticket/639 - FIXED IN TW241
// // Pressing "enter" from URL or Browse input field immediately reloads the current document.  Instead, it should trigger the "open" button for the import wizard (if a URL has been entered)
//{{{
if (ver<2.41) {
// #635 and #638
config.macros.importTiddlers.onBrowseChange = function(e)
{
	var wizard = new Wizard(this);
	var fileInput = wizard.getElement("txtPath");
	fileInput.value = config.macros.importTiddlers.getURLFromLocalPath(this.value); // #635
	var serverType = wizard.getElement("selTypes");
	serverType.value = "file";
	return true; // #638
};
// #635 - fixup local path/file to form absolute URL reference
config.macros.importTiddlers.getURLFromLocalPath = function(v)
{
	if (!v||!v.length) return v;
	v=v.replace(/\\/g,"/"); // use "/" for cross-platform consistency
	var t=v.split(":"); p=t[1]||t[0]; // remove drive letter (if any)
	if (t[1] && (t[0]=="http"||t[0]=="https"||t[0]=="file")) { // input is already a URL
		var u=v;
	} else if (p.substr(0,1)=="/") { // path is absolute, add protocol+domain+extra slash (if drive letter)
		var u=document.location.protocol+"//"+document.location.hostname+(t[1]?"/":"")+v;
	} else { // path is relative, add current document protocol+domain+path
		var c=document.location.href.replace(/\\/g,"/");
		var pos=c.lastIndexOf("/"); if (pos!=-1) c=c.substr(0,pos); // remove filename
		var u=c+"/"+p;
	}
	return u;
}
// #639 - prevent form action and click "open" button if ENTER is pressed
config.macros.importTiddlers.coreTweaks_restart = config.macros.importTiddlers.restart;
config.macros.importTiddlers.restart = function(wizard)
{
	config.macros.importTiddlers.coreTweaks_restart.apply(this,arguments);
	wizard.formElem.action="javascript:;"
	wizard.formElem.onsubmit=function() {
		if (this.txtPath.value.length)
			this.lastChild.firstChild.onclick();  // press "open" button
	}
};
}
//}}}
// // }}}
// // {{groupbox small{
// // http://trac.tiddlywiki.org/ticket/623 - FIXED IN TW241
/***
This tweak allows date format strings to contain backslash-quoted characters that bypass date format replacement.  This allows sequences such as "s\s", "m\m" or "a\m" to be used so that "ss", "mm" or "am" can appears as literal text within journal titles or other date-formatted values.

For example:
>{{{<<today "withhold less hummingbirds - YYYY.0MM.0DD 0hh:0mm:0ss">>}}}
>results in: <<today "withhold less hummingbirds - YYYY.0MM.0DD 0hh:0mm:0ss">>
while:
>{{{<<today "with\hold les\s hum\mingbirds - YYYY.0MM.0DD 0hh:0mm:0ss">>}}}
>results in: <<today "with\hold les\s hum\mingbirds - YYYY.0MM.0DD 0hh:0mm:0ss">>
***/
//{{{
if (ver<2.41) {
Date.prototype.coreTweaks_formatString = Date.prototype.formatString;
Date.prototype.formatString = function(template) {
	var t = Date.prototype.coreTweaks_formatString.apply(this,arguments);
	t = t.replace(/\\/g,""); // strip backslashes used to quote formats
	return t;
};
}
//}}}
// // }}}
// // {{groupbox small{
// // http://trac.tiddlywiki.org/ticket/578 - FIXED IN TW240
// // This tweak trims any leading whitespace/newline and the trailing newline from tiddler sections
//{{{
if (ver<2.4) {
TiddlyWiki.prototype.coreTweaks_getTiddlerText = TiddlyWiki.prototype.getTiddlerText;
TiddlyWiki.prototype.getTiddlerText = function(title,defaultText)
{
	var r=TiddlyWiki.prototype.coreTweaks_getTiddlerText.apply(this,arguments);
	if (r&&title.indexOf(config.textPrimitives.sectionSeparator)!=-1)
		r=r.replace(/^[ \t]*\n/,"").replace(/\n$/,""); // trim any leading/trailing newlines
	return r;
};
}
//}}}
// // }}}
// // {{groupbox small{
// // http://trac.tiddlywiki.org/ticket/541 - FIXED IN TW240
// // This tweak adds a conditional check to the core's 'open' paramifier, so that when the document is viewed in readOnly mode, non-existent tiddlers specified using a permalink/permaview (i.e. "#TiddlerName" in the document URL) will not be displayed as an empty tiddler (which shows the "double-click to create" default text).
//{{{
if (ver<2.4) {
config.paramifiers.open = { 
onstart: function(v) { 
		if(!readOnly || store.tiddlerExists(v) || store.isShadowTiddler(v)) 
			story.displayTiddler("bottom",v,null,false,null); 
	} 
}; 
}
//}}}
// // }}}
// // {{groupbox small{
// // http://trac.tiddlywiki.org/ticket/470 - FIXED IN TW240
// // This tweak lets you set an alternative initial focus field when editing a tiddler (default field is "text")
// // Enter initial focus field name: <<option txtEditorFocus>> (//usage:// {{{<<option txtEditorFocus>>}}})
//{{{
if (ver<2.4) {
config.commands.editTiddler.coreTweaks_handler = config.commands.editTiddler.handler;
config.commands.editTiddler.handler = function(event,src,title)
{
	if (config.options.txtEditorFocus==undefined) config.options.txtEditorFocus="text";
	this.coreTweaks_handler.apply(this,arguments);
	story.focusTiddler(title,config.options.txtEditorFocus);
	return false;
};
}
//}}}
// // }}}
// // {{groupbox small{
// // http://trac.tiddlywiki.org/ticket/468 - FIXED IN TW240
// // This tweak extends the core's {{{<<tag>>}}} macro to accept additional parameters for specifying alternative label and tooltip text for the tag popup "button" link (i.e., "`PrettyTags").  Based on a suggestion by ~PBee.
//{{{
// hijack tag handler()
if (ver<2.4) {
config.macros.tag.CoreTweaks_handler=config.macros.tag.handler;
config.macros.tag.handler = function(place,macroName,params)
{
	this.CoreTweaks_handler.apply(this,arguments);
	var btn=place.lastChild;
	if (params[1]) btn.innerHTML=params[1];
	if (params[2]) btn.title=params[2];
}
}
//}}}
// // }}}
// // {{groupbox small{
// // http://trac.tiddlywiki.org/ticket/320 - FIXED IN TW240
// // This tweak updates the core's forceReflow() function to fix a Firefox rendering problem, whereby the contents of the a tiddler editor text area can be incorrectly displayed (overlapping other content) when more than one tiddler is in edit mode.
//{{{
if (ver<2.4) {
function forceReflow()
{
	if(config.browser.isGecko) {
		setStylesheet("body {top:-0px;margin-top:0px;}");
		setTimeout('setStylesheet("")',1); // invoke async to bypass browser optimization
	}
}
}
//}}}
// // }}}
// // {{groupbox small{
// // http://trac.tiddlywiki.org/ticket/42 - FIXED IN TW240
// // This tweak adjusts the left position of a TW popup so that it won't overlap with the browser window's vertical scrollbar, when present.
//{{{
if (ver<2.4) {
Popup.place = function(root,popup,offset)
{
	if(!offset) var offset = {x:0, y:0};
	var rootLeft = findPosX(root);
	var rootTop = findPosY(root);
	var rootHeight = root.offsetHeight;
	var popupLeft = rootLeft + offset.x;
	var popupTop = rootTop + rootHeight + offset.y;
	var winWidth = findWindowWidth();
	if(popup.offsetWidth > winWidth*0.75)
		popup.style.width = winWidth*0.75 + "px";
	var popupWidth = popup.offsetWidth;
	// ELS: leave space for vertical scrollbar
	var scrollWidth=winWidth-document.body.offsetWidth;
	if(popupLeft+popupWidth > winWidth-scrollWidth-1)
		popupLeft = winWidth-popupWidth-scrollWidth-1;
	popup.style.left = popupLeft + "px";
	popup.style.top = popupTop + "px";
	popup.style.display = "block";
};
}
//}}}
// // }}}
/***
!!!Unticketed Tweaks
***/
// // {{groupbox small{
/***
!!#animate:... paramifier
http://trac.tiddlywiki.org/ticket/TBD - TBD
This tweak provides a paramifier to turn on/off animation
***/
//{{{
config.paramifiers.animate= {
	onstart: function(v) {
		config.options.chkAnimate=eval(v);
	}
};
//}}}
// // }}}
// // {{groupbox small{
// // This tweak adds an optional 'sortby' parameter to the {{{<<tag tagname label tip sortby>>}}} macro, as well as the {{{<<allTags excludeTag sortby>>}}} macro used to generate the sidebar contents 'tags' list.  Specify the field on which the contents of each tag popup is to be sorted, with a "+" or "-" prefix to indicate ascending/descending order, respectively.

// // Example: {{{<<tag systemConfig "plugins" "list plugins by date, most recent first" "-modified">>}}}
// // Try it: <<tag systemConfig "plugins" "list plugins by date, most recent first" "-modified">>

// // Similarly, to change the sort order used by the popups from all tags shown in the sidebar contents, edit the [[TagTags]] shadow tiddler and enter: {{{<<allTags excludeLists -modified>>}}}

//{{{
// hijack tag handler() to add 'sortby' attribute to tag button
config.macros.tag.CoreTweaksSortTags_handler=config.macros.tag.handler;
config.macros.tag.handler = function(place,macroName,params)
{
	this.CoreTweaksSortTags_handler.apply(this,arguments);
	var btn=place.lastChild;
	if (params[3]) btn.setAttribute("sortby",params[3]);
}

// TWEAK <<allTags>> macro to add 'sortby' attribute to each tag button
var fn=config.macros.allTags.handler;
var lines=fn.toString().split("\n");
lines.splice(lines.length-2,0,['if(params[1]) btn.setAttribute("sortby",params[1]);']);
fn=lines.join("\n");
eval("config.macros.allTags.handler="+fn);

// TWEAK event handler for clicking on a tiddler tag to use 'sortby' attribute
var fn=onClickTag;
fn=fn.toString().replace(
	/store.getTaggedTiddlers\(tag\);/g,
	'store.getTaggedTiddlers(tag);'
	+'var sortby=this.getAttribute("sortby");'
	+'if(sortby&&sortby.length) store.sortTiddlers(tagged,sortby);'
);
eval(fn);

//}}}
// // }}}
// // {{groupbox small{
// // This HIJACK 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.).  Based on a suggestion from Sitaram Chamarty.
//{{{
window.coreWikify = wikify;
window.wikify = function(source,output,highlightRegExp,tiddler)
{
	if (source) arguments[0]=source.replace(/\\\\\n/mg,"<br>");
	coreWikify.apply(this,arguments);
}
//}}}
// // }}}
/***
|Name|[[DatePlugin]]|
|Source|http://www.TiddlyTools.com/#DatePlugin|
|Documentation|http://www.TiddlyTools.com/#DatePluginInfo|
|Version|2.7.1|
|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
<<<
2009.05.31 [2.7.1] in addRemindersToPopup(), 'new reminder....' command now uses {{{<<newTiddler>>}}} macro.  Also, general code reduction/cleanup.
|please see [[DatePluginInfo]] for additional revision details|
2005.10.30 [0.9.0] pre-release
<<<
!!!!!Code
***/
//{{{
version.extensions.DatePlugin= {major: 2, minor: 7, revision: 1, date: new Date(2009,5,31)};

config.macros.date = {
	format: 'YYYY.0MM.0DD', // default date display format
	linkformat: 'YYYY.0MM.0DD', // 'dated tiddler' link format
	linkedbg: '#babb1e', // 'babble'
	todaybg: '#ffab1e', // 'fable'
	weekendbg: '#c0c0c0', // 'cocoa'
	holidaybg: '#ffaace', // 'face'
	createdbg: '#bbeeff', // 'beef'
	modifiedsbg: '#bbeeff', // 'beef'
	remindersbg: '#c0ffee', // 'coffee'
	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);

	// 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 = linkto;
	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;

	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));
	if (!config.options.chkDatePopupHideCreated)
		addCreatedsToPopup(p,this.date,this.format);
	if (!config.options.chkDatePopupHideChanged)
		addModifiedsToPopup(p,this.date,this.format);
	if (!config.options.chkDatePopupHideTagged)
		addTaggedToPopup(p,this.date,this.linkformat);
	if (!config.options.chkDatePopupHideReminders)
		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.macros.date.createds) config.macros.date.createds=indexCreateds();
	return (config.macros.date.createds[date.formatString('YYYY0MM0DD')]!=undefined);
}

function addCreatedsToPopup(p,when,format)
{
	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.macros.date.modifieds) config.macros.date.modifieds = indexModifieds();
	return (config.macros.date.modifieds[date.formatString('YYYY0MM0DD')]!=undefined);
}

function addModifiedsToPopup(p,when,format)
{
	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
{
	return store.getTaggedTiddlers(date.formatString(format)).length>0;
}

function addTaggedToPopup(p,when,format)
{
	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 (window.reminderCacheForCalendar)
		return window.reminderCacheForCalendar[date]; // use calendar cache
	if (!config.macros.date.reminders)
		config.macros.date.reminders = indexReminders(date,90); // create a 90-day leadtime reminder cache
	return (config.macros.date.reminders[date]);
}

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

	var indent = String.fromCharCode(160)+String.fromCharCode(160);
	var reminders=findTiddlersWithReminders(when, [0,31],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.6.0|
|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
//}}}

// // 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);
}
//}}}
[[Grolog Colloquium]]
/***
|Name|ExportTiddlersPlugin|
|Source|http://www.TiddlyTools.com/#ExportTiddlersPlugin|
|Documentation|http://www.TiddlyTools.com/#ExportTiddlersPluginInfo|
|Version|2.7.0|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|plugin|
|Requires||
|Overrides||
|Description|select and extract tiddlers from your ~TiddlyWiki documents and save them to a separate file|
ExportTiddlersPlugin lets you select and extract tiddlers from your ~TiddlyWiki documents using interactive control panel lets you specify a destination, and then select which tiddlers to export. Tiddler data can be output as complete, stand-alone TiddlyWiki documents, or just the selected tiddlers ("~PureStore" format -- smaller files!) that can be imported directly into another ~TiddlyWiki, or as an ~RSS-compatible XML file that can be published for RSS syndication.
!!!!!Documentation
>see [[ExportTiddlersPluginInfo]]
!!!!!Inline control panel (live):
><<exportTiddlers inline>>
!!!!!Revisions
<<<
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
|please see [[ExportTiddlersPluginInfo]] for additional revision details|
2005.10.09 [0.0.0] development started
<<<
!!!!!Code
***/
//{{{
// version
version.extensions.exportTiddlers = {major: 2, minor: 7, revision: 0, date: new Date(2008,5,27)};

// 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");
}

// macro handler
config.macros.exportTiddlers = {
	label: "export tiddlers",
	prompt: "Copy selected tiddlers to an export document",
	newdefault: "export.html",
	datetimefmt: "0MM/0DD/YYYY 0hh:0mm:0ss" // for "filter date/time" edit fields
};

config.macros.exportTiddlers.handler = function(place,macroName,params) {
	if (params[0]!="inline")
		{ createTiddlyButton(place,this.label,this.prompt,onClickExportMenu); return; }
	var panel=createExportPanel(place);
	panel.style.position="static";
	panel.style.display="block";
}

function createExportPanel(place) {
	var panel=document.getElementById("exportPanel");
	if (panel) { panel.parentNode.removeChild(panel); }
	setStylesheet(config.macros.exportTiddlers.css,"exportTiddlers");
	panel=createTiddlyElement(place,"span","exportPanel",null,null)
	panel.innerHTML=config.macros.exportTiddlers.html;
	exportInitFilter();
	refreshExportList(0);
	var fn=document.getElementById("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+config.macros.exportTiddlers.newdefault;
	}
	return panel;
}

function onClickExportMenu(e)
{
	if (!e) var e = window.event;
	var parent=resolveTarget(e).parentNode;
	var panel = document.getElementById("exportPanel");
	if (panel==undefined || panel.parentNode!=parent)
		panel=createExportPanel(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") { // update list and set focus when panel is made visible
		refreshExportList(0);
		var fn=document.getElementById("exportFilename"); fn.focus(); fn.select();
	}
	e.cancelBubble = true;
	if (e.stopPropagation) e.stopPropagation();
	return(false);
}
//}}}

// // IE needs explicit scoping for functions called by browser events
//{{{
window.onClickExportMenu=onClickExportMenu;
window.onClickExportButton=onClickExportButton;
window.exportShowFilterFields=exportShowFilterFields;
window.refreshExportList=refreshExportList;
//}}}

// // CSS for floating export control panel
//{{{
config.macros.exportTiddlers.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;\
}\
#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; }\
#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%; }\
';
//}}}

// // HTML for export control panel interface
//{{{
config.macros.exportTiddlers.html = '\
<!-- target path/file  -->\
<div>\
export to path/filename:<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=window.promptForExportFilename(this); if (fn.length) this.previousSibling.value=fn; ">\
</div>\
\
<!-- output format -->\
<div>\
output file format:\
<select id="exportFormat" size=1>\
<option value="TW">TiddlyWiki document (includes core code)</option>\
<option value="DIV">TiddlyWiki "PureStore" file (tiddler data only)</option>\
<option value="XML">XML (for RSS newsfeed)</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="onClickExportButton(this)" title="select all tiddlers">\
		&nbsp;all&nbsp;</a>\
	<a href="JavaScript:;" id="exportSelectChanges"\
		onclick="onClickExportButton(this)" title="select tiddlers changed since last save">\
		&nbsp;changes&nbsp;</a> \
	<a href="JavaScript:;" id="exportSelectOpened"\
		onclick="onClickExportButton(this)" title="select tiddlers currently being displayed">\
		&nbsp;opened&nbsp;</a> \
	<a href="JavaScript:;" id="exportSelectRelated"\
		onclick="onClickExportButton(this)" title="select all tiddlers related (by link or transclusion) to the currently selected tiddlers">\
		&nbsp;related&nbsp;</a> \
	<a href="JavaScript:;" id="exportToggleFilter"\
		onclick="onClickExportButton(this)" title="show/hide selection filter">\
		&nbsp;filter&nbsp;</a>  \
</td><td align="right">\
	<a href="JavaScript:;" id="exportListSmaller"\
		onclick="onClickExportButton(this)" title="reduce list size">\
		&nbsp;&#150;&nbsp;</a>\
	<a href="JavaScript:;" id="exportListLarger"\
		onclick="onClickExportButton(this)" title="increase list size">\
		&nbsp;+&nbsp;</a>\
</td></tr></table>\
<select id="exportList" multiple size="10" style="margin-bottom:5px;"\
	onchange="refreshExportList(this.selectedIndex)">\
</select><br>\
</div><!--box-->\
\
<!-- 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="onClickExportButton(this)" title="hide selection filter">hide</a>\
</td></tr></table>\
<div class="box">\
<input type="checkbox" class="chk" id="exportFilterStart" value="1"\
	onclick="exportShowFilterFields(this)"> starting date/time<br>\
<table cellpadding="0" cellspacing="0"><tr valign="center"><td width="50%">\
	<select size=1 id="exportFilterStartBy" onchange="exportShowFilterFields(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="site">SiteDate</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="document.getElementById(\'exportFilterStartBy\').value=\'other\';">\
</td></tr></table>\
<input type="checkbox" class="chk" id="exportFilterEnd" value="1"\
	onclick="exportShowFilterFields(this)"> ending date/time<br>\
<table cellpadding="0" cellspacing="0"><tr valign="center"><td width="50%">\
	<select size=1 id="exportFilterEndBy" onchange="exportShowFilterFields(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="site">SiteDate</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="document.getElementById(\'exportFilterEndBy\').value=\'other\';">\
</td></tr></table>\
<input type="checkbox" class="chk" id=exportFilterTags value="1"\
	onclick="exportShowFilterFields(this)"> match tags<br>\
<input type="text" id="exportTags" onfocus="this.select()">\
<input type="checkbox" class="chk" id=exportFilterText value="1"\
	onclick="exportShowFilterFields(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="onClickExportButton(this)"\
	id="exportFilter" value="apply filter">\
<input type=button class="btn4" onclick="onClickExportButton(this)"\
	id="exportStart" value="export tiddlers">\
<input type=button class="btn4" onclick="onClickExportButton(this)"\
	id="exportDelete" value="delete tiddlers">\
<input type=button class="btn4" onclick="onClickExportButton(this)"\
	id="exportClose" value="close">\
</div><!--center-->\
';
//}}}

// // initialize interface

// // exportInitFilter()
//{{{
function exportInitFilter() {
	// start date
	document.getElementById("exportFilterStart").checked=false;
	document.getElementById("exportStartDate").value="";
	// end date
	document.getElementById("exportFilterEnd").checked=false;
	document.getElementById("exportEndDate").value="";
	// tags
	document.getElementById("exportFilterTags").checked=false;
	document.getElementById("exportTags").value="";
	// text
	document.getElementById("exportFilterText").checked=false;
	document.getElementById("exportText").value="";
	// show/hide filter input fields
	exportShowFilterFields();
}
//}}}

// // exportShowFilterFields(which)
//{{{
function exportShowFilterFields(which) {
	var show;

	show=document.getElementById('exportFilterStart').checked;
	document.getElementById('exportFilterStartBy').style.display=show?"block":"none";
	document.getElementById('exportStartDate').style.display=show?"block":"none";
	var val=document.getElementById('exportFilterStartBy').value;
	document.getElementById('exportStartDate').value
		=getFilterDate(val,'exportStartDate').formatString(config.macros.exportTiddlers.datetimefmt);
	 if (which && (which.id=='exportFilterStartBy') && (val=='other'))
		document.getElementById('exportStartDate').focus();

	show=document.getElementById('exportFilterEnd').checked;
	document.getElementById('exportFilterEndBy').style.display=show?"block":"none";
	document.getElementById('exportEndDate').style.display=show?"block":"none";
	var val=document.getElementById('exportFilterEndBy').value;
	document.getElementById('exportEndDate').value
		=getFilterDate(val,'exportEndDate').formatString(config.macros.exportTiddlers.datetimefmt);
	 if (which && (which.id=='exportFilterEndBy') && (val=='other'))
		document.getElementById('exportEndDate').focus();

	show=document.getElementById('exportFilterTags').checked;
	document.getElementById('exportTags').style.display=show?"block":"none";

	show=document.getElementById('exportFilterText').checked;
	document.getElementById('exportText').style.display=show?"block":"none";
}
//}}}

// // onClickExportButton(which): control interactions
//{{{
function onClickExportButton(which)
{
	// DEBUG alert(which.id);
	var theList=document.getElementById('exportList'); if (!theList) return;
	var count = 0;
	var total = store.getTiddlers('title').length;
	switch (which.id)
		{
		case 'exportFilter':
			count=filterExportList();
			var panel=document.getElementById('exportFilterPanel');
			if (count==-1) { panel.style.display='block'; break; }
			document.getElementById("exportStart").disabled=(count==0);
			document.getElementById("exportDelete").disabled=(count==0);
			clearMessage(); displayMessage("filtered "+formatExportMessage(count,total));
			if (count==0) { alert("No tiddlers were selected"); panel.style.display='block'; }
			break;
		case 'exportStart':
			exportTiddlers();
			break;
		case 'exportDelete':
			exportDeleteTiddlers();
			break;
		case 'exportHideFilter':
		case 'exportToggleFilter':
			var panel=document.getElementById('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;
			}
			document.getElementById("exportStart").disabled=(count==0);
			document.getElementById("exportDelete").disabled=(count==0);
			clearMessage(); displayMessage(formatExportMessage(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;
			}
			document.getElementById("exportStart").disabled=(count==0);
			document.getElementById("exportDelete").disabled=(count==0);
			clearMessage(); displayMessage(formatExportMessage(count,count));
			break;
		case 'exportSelectOpened':
			for (var t = 0; t < theList.options.length; t++) theList.options[t].selected=false;
			var tiddlerDisplay = document.getElementById("tiddlerDisplay"); // for TW2.1-
			if (!tiddlerDisplay) tiddlerDisplay = document.getElementById("storyDisplay"); // for TW2.2+
			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;
				}
			}
			document.getElementById("exportStart").disabled=(count==0);
			document.getElementById("exportDelete").disabled=(count==0);
			clearMessage(); displayMessage(formatExportMessage(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);
			clearMessage(); displayMessage(formatExportMessage(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':
			document.getElementById('exportPanel').style.display='none';
			break;
		}
}
//}}}

// // promptForFilename(msg,path,file) uses platform/browser specific functions to get local filespec
//{{{
window.promptForExportFilename=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=config.macros.exportTiddlers.newdefault;
	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='html';
			picker.defaultString=file;
			picker.appendFilters(nsIFilePicker.filterAll|nsIFilePicker.filterText|nsIFilePicker.filterHTML);
			if (picker.show()!=nsIFilePicker.returnCancel) var result=picker.file.persistentDescriptor;
		}
		catch(e) { alert('error during local file access: '+e.toString()) }
	}
	else { // IE
		try { // 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;
}
//}}}

// // list display
//{{{
function formatExportMessage(count,total)
{
	var txt=total+' tiddler'+((total!=1)?'s':'')+" - ";
	txt += (count==0)?"none":(count==total)?"all":count;
	txt += " selected for export";
	return txt;
}

function refreshExportList(selectedIndex)
{
	var theList  = document.getElementById("exportList");
	var sort;
	if (!theList) return;
	// get the sort order
	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
	document.getElementById("exportStart").disabled=(count==0);
	document.getElementById("exportDelete").disabled=(count==0);
	// show selection count
	var tiddlers = store.getTiddlers('title');
	if (theList.options.length) { clearMessage(); displayMessage(formatExportMessage(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
	document.getElementById("exportStart").disabled=true;
	document.getElementById("exportDelete").disabled=true;
	clearMessage(); displayMessage(formatExportMessage(0,tiddlers.length));
}
//}}}

// // list filtering
//{{{
function getFilterDate(val,id)
{
	var result=0;
	switch (val) {
		case 'site':
			var timestamp=store.getTiddlerText("SiteDate");
			if (!timestamp) timestamp=document.lastModified;
			result=new Date(timestamp);
			break;
		case 'file':
			result=new Date(document.lastModified);
			break;
		case 'other':
			result=new Date(document.getElementById(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;
	}
	// DEBUG alert('getFilterDate('+val+','+id+')=='+result+"\nnow="+now);
	return result;
}

function filterExportList()
{
	var theList  = document.getElementById("exportList"); if (!theList) return -1;

	var filterStart=document.getElementById("exportFilterStart").checked;
	var val=document.getElementById("exportFilterStartBy").value;
	var startDate=getFilterDate(val,'exportStartDate');

	var filterEnd=document.getElementById("exportFilterEnd").checked;
	var val=document.getElementById("exportFilterEndBy").value;
	var endDate=getFilterDate(val,'exportEndDate');

	var filterTags=document.getElementById("exportFilterTags").checked;
	var tags=document.getElementById("exportTags").value;

	var filterText=document.getElementById("exportFilterText").checked;
	var text=document.getElementById("exportText").value;

	if (!(filterStart||filterEnd||filterTags||filterText)) {
		alert("Please set the selection filter");
		document.getElementById('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, set up conditional expression
	if (filterTags) {
		var all = store.getTags(); // get list of all tags
		for (var i=0; i<all.length; i++) all[i]=all[i][0]; // remove tag counts
		// convert "tag1 AND ( tag2 OR NOT tag3 )"
		// into javascript expression containing regexp tests:
		// "/\~tag1\~/.test(...) && ( /\~tag2\~/.test(...) || ! /\~tag2\~/.test(...) )"
		var c=tags;
		c = c.replace(/[\[\]]/g,""); // remove [[...]] quoting around tagvalues
		// change AND/OR/NOT/parens to javascript operators and delimit terms with "~"
		c = c.replace(/\sand\s/ig,"~&&~");
		c = c.replace(/\sor\s/ig,"~||~");
		c = c.replace(/(\s)?not([\s\(])/ig,"~!~$2");
		c = c.replace(/([\(\)])/ig,"~$1~");
		// change existing tags to regexp tests and non-existing tags to "false"
		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
			terms[i]=!all.contains(t)?"false":("/\\~"+t+"\\~/.test(tiddlertags)");
		}
		c=terms.join(" ");
	}
	function matchTags(t,c) {
		if (!c||!c.trim().length) return false;
		// assemble tags from tiddler into string "~tag1~tag2~tag3~"
		var tiddlertags = "~"+t.tags.join("~")+"~";
		// eval string against boolean test expression
		try { if(eval(c)) return true; }
		catch(e) { displayMessage(e.toString()); }
		return false;
	}
	
	// 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 && !matchTags(tiddler,c))
		|| (filterText && (tiddler.text.indexOf(text)==-1) && (tiddler.title.indexOf(text)==-1)))
			sel=false;
		opt.selected=sel;
		count+=sel?1:0;
		total++;
	}
	return count;
}
//}}}

// // OUTPUT FORMATTING AND FILE I/O
//{{{
function exportTWHeader()
{
	// get the TiddlyWiki core code source
	var sourcefile=getLocalPath(document.location.href);
	var source=loadFile(sourcefile);
	if(source==null) { alert(config.messages.cantSaveError); return null; }
	// reset existing HTML source markup
	source=updateMarkupBlock(source,"PRE-HEAD");
	source=updateMarkupBlock(source,"POST-HEAD");
	source=updateMarkupBlock(source,"PRE-BODY");
	source=updateMarkupBlock(source,"POST-BODY");
	// find store area
	var posOpeningDiv=source.indexOf(startSaveArea);
	var posClosingDiv=source.lastIndexOf(endSaveArea);
	if((posOpeningDiv==-1)||(posClosingDiv==-1))
		{ alert(config.messages.invalidFileError.format([sourcefile])); return; }
	// return everything up to store area
	return source.substr(0,posOpeningDiv+startSaveArea.length);
}

function exportTWFooter()
{
	// get the TiddlyWiki core code source
	var sourcefile=getLocalPath(document.location.href);
	var source=loadFile(sourcefile);
	if(source==null) { alert(config.messages.cantSaveError); return null; }
	// reset existing HTML source markup
	source=updateMarkupBlock(source,"PRE-HEAD");
	source=updateMarkupBlock(source,"POST-HEAD");
	source=updateMarkupBlock(source,"PRE-BODY");
	source=updateMarkupBlock(source,"POST-BODY");
	// find store area
	var posOpeningDiv=source.indexOf(startSaveArea);
	var posClosingDiv=source.lastIndexOf(endSaveArea);
	if((posOpeningDiv==-1)||(posClosingDiv==-1))
		{ alert(config.messages.invalidFileError.format([sourcefile])); return; }
	// return everything after store area
	return source.substr(posClosingDiv);
}

function exportDIVHeader()
{
	var out=[];
	var now = new Date();
	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 pver = version.extensions.exportTiddlers.major+"."
		+version.extensions.exportTiddlers.minor+"."+version.extensions.exportTiddlers.revision;
	out.push("<html><body>");
	out.push("<style type=\"text/css\">");
	out.push("#storeArea {display:block;margin:1em;}");
	out.push("#storeArea div");
	out.push("{padding:0.5em;margin:1em;border:2px solid black;height:10em;overflow:auto;}");
	out.push("#javascriptWarning");
	out.push("{width:100%;text-align:left;background-color:#eeeeee;padding:1em;}");
	out.push("</style>");
	out.push("<div id=\"javascriptWarning\">");
	out.push("TiddlyWiki export file<br>");
	out.push("Source"+": <b>"+convertUnicodeToUTF8(document.location.href)+"</b><br>");
	out.push("Title: <b>"+title+"</b><br>");
	out.push("Subtitle: <b>"+subtitle+"</b><br>");
	out.push("Created: <b>"+now.toLocaleString()+"</b> by <b>"+user+"</b><br>");
	out.push("TiddlyWiki "+twver+" / "+"ExportTiddlersPlugin "+pver+"<br>");
	out.push("Notes:<hr><pre>"+document.getElementById("exportNotes").value.replace(/\n/g,"<br>")+"</pre>");
	out.push("</div>");
	out.push("<div id=\"storeArea\">");
	return out;
}

function exportDIVFooter()
{
	return ["</div><!--POST-BODY-START-->\n<!--POST-BODY-END--></body></html>"];
}

function exportXMLHeader()
{
	var out=[];
	var now = new Date();
	var u = store.getTiddlerText("SiteUrl",null);
	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 pver = version.extensions.exportTiddlers.major+"."
		+version.extensions.exportTiddlers.minor+"."+version.extensions.exportTiddlers.revision;
	out.push("<" + "?xml version=\"1.0\"?" + ">");
	out.push("<rss version=\"2.0\">");
	out.push("<channel>");
	out.push("<title>" + title + "</title>");
	if(u) out.push("<link>" + convertUnicodeToUTF8(u.htmlEncode()) + "</link>");
	out.push("<description>" + subtitle + "</description>");
	out.push("<language>en-us</language>");
	out.push("<copyright>Copyright " + now.getFullYear() + " " + user + "</copyright>");
	out.push("<pubDate>" + now.toGMTString() + "</pubDate>");
	out.push("<lastBuildDate>" + now.toGMTString() + "</lastBuildDate>");
	out.push("<docs>http://blogs.law.harvard.edu/tech/rss</docs>");
	out.push("<generator>TiddlyWiki "+twver+" plus ExportTiddlersPlugin "+pver+"</generator>");
	return out;
}

function exportXMLFooter()
{
	return ["</channel></rss>"];
}

function exportData(target,list,fmt)
{
	function getData(s,f,t) { var r="";
		switch (f) {
			case "TW": r=s.getSaver().externalizeTiddler(s,t); break;
			case "DIV": r=t.title+"\n"+s.getSaver().externalizeTiddler(s,t); break;
			case "XML": r=t.saveToRss(store.getTiddlerText("SiteUrl","")); break;
		}
		return convertUnicodeToUTF8(r);
	}

	var out=[]; var tids=[];
	// get selected tiddlers
	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.title);
		out.push(getData(store,fmt,tid));
	}
	var count=out.length;
	// merge with existing tiddlers
	var text=loadFile(target);
	if (text && text.length) {
		var msg=target+"\nalready contains tiddler definitions.\n";
		msg+="\nPress OK to add new/revised tiddlers to current file contents.";
		msg+="\nPress Cancel to completely replace file contents";
		var remoteStore=new TiddlyWiki();
		if (remoteStore.importTiddlyWiki(text) && confirm(msg)) {
			var existing=remoteStore.getTiddlers("title");
			for (var i=0; i<existing.length; i++)
				if (!tids.contains(existing[i].title))
					out.push(getData(remoteStore,fmt,existing[i]));
			var msg="Merged %0 new/revised tiddlers and %1 existing tiddlers";
			displayMessage(msg.format([count,out.length-count]));
		}
	}
	return out;
}
//}}}

// // exportTiddlers(): output selected data to local file
//{{{
function exportTiddlers()
{
	clearMessage();
	var list  = document.getElementById("exportList"); if (!list) return;
	var fmt = document.getElementById("exportFormat").value;
	var target = document.getElementById("exportFilename").value.trim();
	if (!target.length) {
		displayMessage("A local target path/filename is required",target);
		return;
	}
	switch (fmt) {
		case "TW":	var head=exportTWHeader(); break;
		case "DIV":	var head=exportDIVHeader(); break;
		case "XML":	var head=exportXMLHeader(); break;
	}
	var theData=exportData(target,list,fmt);
	var c=theData.length;
	switch (fmt) {
		case "TW":	var foot=exportTWFooter(); break;
		case "DIV":	var foot=exportDIVFooter(); break;
		case "XML":	var foot=exportXMLFooter(); break;
	}
	var out=[]; var txt=out.concat(head,theData,foot).join("\n");
	var msg="An error occurred while saving to "+target;
	if (saveFile(target,txt)) msg=c+" tiddler"+((c!=1)?"s":"")+" written to "+target;
	displayMessage(msg,"file:///"+target);
}
//}}}

// // exportDeleteTiddlers(): delete selected tiddlers from file
//{{{
function exportDeleteTiddlers()
{
	var list=document.getElementById("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;
		if (tid.tags.contains("systemConfig"))
			if (!confirm("'"+tid.title+"' is tagged with 'systemConfig'.\n\nRemoving this tiddler may cause unexpected results.  Are you sure?"))
				continue;
		store.removeTiddler(tid.title);
		story.closeTiddler(tid.title);
	}
	store.resumeNotifications();
	alert(tids.length+" tiddlers deleted");
	refreshExportList(0); // reload listbox
	store.notifyAll(); // update page display
}
//}}}
[[Grolog Colloquium]] 

[[Groningen-Amsterdam Dynamic Seminar]]

+++[Event Calendar|Show a calendar]<<calendar thismonth>>===


[[Join the Mailinglist]]

[[People]]

[[Sponsors]]

[[About us]]
/***
|''Name:''|GTDPlugins|
|''Description:''|Plugin to support Getting Things Done|
|''Version:''|<<gtdVersion>>|
|''Date:''|October 27, 2008|
|''Source:''|http://www.dcubed.ca/|
|''Author:''|Tom Otvos|
|''CoreVersion:''|2.4|
|''Browser:''|Firefox 1.5+; InternetExplorer 6.0+; Safari 3.1+|
***/

/***
''Macros:''
*{{{<<gtdAction "}}}//title//{{{" "}}}//context list//{{{">>}}}
*{{{<<gtdActionList {"}}}//context list//{{{" | "*" | "@" {"all" | "noproject" | "projectonly"} }>>}}}
** //if no parameters are specified, current context or project is used//
** //specify "*" for actions across all projects, "@" for incomplete actions across all contexts (or "all" for all actions)//
** //use "projectonly" or "noproject" to filter actions by project association//
*{{{<<list tagged "}}}//tag list//{{{" {any | all}>>}}}
** //if no parameters are specified, all tags are necessary//
*{{{<<gtdActionCompleted>>}}}
*{{{<<gtdToggleTag>>}}}
*{{{<<gtdToggleState>>}}}
*{{{<<importUpdates "}}}//url//{{{" {updates | all} "}}}//buttonTitle//{{{" "}}}//buttonHelp//{{{" "}}}//loadTiddlers params...//{{{">>}}}
*{{{<<gtdArchive { archive | unarchive | purge }>>}}}

''Commands:''
*{{{newAction}}}
*{{{newProjectAction}}}
*{{{changeContext}}}
*{{{deleteAction}}}
*{{{deleteContext}}}
*{{{deleteProject}}}
*{{{deleteProjectAll}}}
*{{{projectify}}}

''Wiki formatting:''
*{{{..new action title|context}}}

***/
//{{{

version.extensions.GTDPlugins = {major: 1, minor: 3, revision: 0, patch: 0 };

var _GTD = {

	lazyAutoSave: 0,
	contextCache: null,
	usingProjectTags: true,
	projectPriorities: [],

	initialize: function ()
	{
		var d = new Date();

		if (config.options.txtGTDReferenceContext == undefined) config.options.txtGTDReferenceContext = "reference";
		if (config.options.txtGTDSomedayContext == undefined) config.options.txtGTDSomedayContext = "someday";
		if (config.options.txtGTDUnfiledContext == undefined) config.options.txtGTDUnfiledContext = "unfiled";
		if (config.options.txtGTDActionAging == undefined) config.options.txtGTDActionAging = "";
		if (config.options.chkGTDFancyStyle == undefined) config.options.chkGTDFancyStyle = true;
		if (config.options.chkGTDLazyAutoSave == undefined) config.options.chkGTDLazyAutoSave = true;
		if (config.options.txtGTDLazyAutoSaveInterval == undefined) config.options.txtGTDLazyAutoSaveInterval = "60";
		if (config.options.txtGTDProjectPriorities == undefined) config.options.txtGTDProjectPriorities = "";
		
		// some tricks to work when our script is loaded from an external file...
		if (!store) config.notifyTiddlers.push( {name: "GTDStyleSheet", notify: refreshStyles} );
		if (!store && config.options.chkGTDFancyStyle) config.notifyTiddlers.push( {name: "GTDTWStyleSheet", notify: refreshStyles} );
		if (!store) config.notifyTiddlers.push( {name: null, notify: _GTD.refreshActionViews} );
		
		this.setReviewUpdate();
		this.setLazyAutoSave();
		
		if (config.options.txtGTDProjectPriorities.length == 0)
			this.projectPriorities = [ "important" ];
		else
			this.projectPriorities = config.options.txtGTDProjectPriorities.split(';');
		
		if (!store) return;
		
		if ((version.major == 2 && version.minor < 1) || !store.tiddlerExists("d3 settings")) {
			// we force a changed() call on all projects, contexts, and actions, to enable them to set up their cross-references
			var tiddlers = [];
			tiddlers = tiddlers.concat(store.getTaggedTiddlers("project"), store.getTaggedTiddlers("context"), store.getTaggedTiddlers("action"));
			for (var i = 0; i < tiddlers.length; i++)
				tiddlers[i].changed();
			
			// if we have tiddler meta data, rebuild it
			if (version.major > 2 || version.minor > 0)
				this.rebuildMetaData();
		}
		else {
			this.initializeFromMetaData();
			this.usingProjectTags = false;
		}
		
		//store.addNotification("GTDStyleSheet", refreshStyles);
		//if (config.options.chkGTDFancyStyle) store.addNotification("GTDTWStyleSheet", refreshStyles);
		store.addNotification(null, _GTD.refreshActionViews);
		
		// force a display of release notes, if required
		var v = version.extensions.GTDPlugins;
		var releaseNotesTiddler = "About version " + v.major + '.' + v.minor + '.' + v.revision;
		if ((config.options.chkGTDReleaseNotes || config.options.chkGTDReleaseNotes == undefined) && store.tiddlerExists(releaseNotesTiddler)) {
			params = "open:\"" + releaseNotesTiddler + "\"";
			params = params.parseParams("open",null,false);
			config.options.chkGTDReleaseNotes = false;
			saveOptionCookie("chkGTDReleaseNotes");
		}

		if (version.major > 2 || version.minor > 0)
			pluginInfo.log.push('Initialized in ' + ((new Date()).getTime() - d.getTime()) + ' milliseconds');
	},
	
	rebuildMetaData: function()
	{
		pluginInfo.log.push('Rebuilding action metadata...');

		store.suspendNotifications();
		var tiddlers = store.getTaggedTiddlers("action");
		for (var i = 0; i < tiddlers.length; i++) {
			var t = tiddlers[i];
			store.setValue(t, "gtd");
			store.setValue(t, "gtd.context", t.gtdContextName);
			if (t.gtdProject) store.setValue(t, "gtd.project", t.gtdProject.title);
			if (t.gtdProject) store.setValue(t, "gtd.projectindex", t.gtdProject.gtdActions.indexOf(t));
			// booo...scary...strip out project tag
			if (t.gtdProject) t.tags.remove(t.gtdProject.title);
		}
		store.resumeNotifications();
			
		var tiddler = store.createTiddler("d3 conversion");
		var s = "Completed document conversion. Do not delete this tiddler unless you want to rebuild the action metadata.\n\nThis tiddler also contains document-specific preferences which, if deleted, will revert to default settings.";
		tiddler.assign("d3 settings", s, config.options.txtUserName, new Date(), ["excludeLists"]);
	},
	
	initializeFromMetaData: function()
	{
		var tiddlers = store.getTaggedTiddlers("action");
		// ??? one possible optimization is to sort action list by project, to avoid repeatedly fetching project tiddler
		for (var i = 0; i < tiddlers.length; i++) {
			var t = tiddlers[i];
			t.gtdActionName = store.getValue(t, "title");
			t.gtdActionDone = this.tiddlerHasTag(t, "done");
			t.gtdProjectName = store.getValue(t, "gtd.project");
			t.gtdContextName = store.getValue(t, "gtd.context");
			if (t.gtdProjectName) {
				t.gtdProject = store.getTiddler(t.gtdProjectName);
				if (t.gtdProject) {
					if (t.gtdProject.gtdActions == undefined) t.gtdProject.gtdActions = [];
					t.gtdProject.gtdActions.push(t);
				}
			}
		}
		
		tiddlers = store.getTaggedTiddlers("project");
		for (i = 0; i < tiddlers.length; i++) {
			t = tiddlers[i];
			if (t.gtdActions) {
				t.gtdActions.sort( 
					function(a,b) { var ai = parseInt(store.getValue(a, "gtd.projectindex")), bi = parseInt(store.getValue(b, "gtd.projectindex")); return (ai < bi) ? -1 : +1; }
				);
			}
			else
				t.gtdActions = [];
			this.setNextAction(t);
		}
		
		tiddlers = this.getCachedContexts();
		for (i = 0; i < tiddlers.length; i++)
			tiddlers[i].gtdContextName = tiddlers[i].title;
	},
	
	tiddlerHasTag: function (tiddler, tag)
	{
		if (typeof(tiddler) == "string") tiddler = store.getTiddler(tiddler);
		return tiddler.isTagged(tag);
	},
	
	tiddlerSwapTag: function (tiddler, oldTag, newTag)
	{
		for (var i = 0; i < tiddler.tags.length; i++)
			if (tiddler.tags[i] == oldTag) {
				tiddler.tags[i] = newTag;
				return true;
			}
		return false;
	},
	
	setExtendedValue: function (tiddler, name, value)
	{
		// this bottleneck safely sets an extended data value, quietly ignoring the request
		// if the setValue function is not available AND it disables notifications during
		// the setValue if it is defined
		
		if (version.major > 2 || version.minor > 0) {
			store.suspendNotifications();
			store.setValue(tiddler, name, value);
			store.resumeNotifications();
		}
	},
	
	tiddlerHasChanged: function (tiddler, doSave)
	{
		tiddler.changed();
		//story.setDirty(tiddler.title, true);
		store.setDirty(true);
		if (this.tiddlerHasTag(tiddler, 'context'))
			this.clearContextCache();
		if (doSave == undefined) doSave = true;
		if (doSave) tiddler.modified = new Date();
		if (config.options.chkAutoSave && doSave)
			saveChanges();
		else if (doSave)
			this.lazyAutoSave++;
	},
	
	tiddlerAgeInDays: function(tiddler)
	{
		var now = new Date();
		return (now.getTime() - tiddler.modified.getTime()) / 1000 / 86400;
	},
	
	filteredTags: function (tags, specialTags, filterTags)
	{
		var resultTags = [];
		specialTags = specialTags.concat(filterTags);
		for (var i = 0; i < tags.length; i++)
			if (!specialTags.contains(tags[i])) resultTags.push(tags[i]);
		return resultTags;
	},
	
	filteredActionTags: function (tags, filterTags)
	{
		return this.filteredTags(tags, [ "action", "done", "floating", "action-archive" ], filterTags);
	},
	
	filteredProjectTags: function (tags, filterTags)
	{
		return this.filteredTags(tags, [ "project", "done", "important", "project-archive" ], filterTags);
	},
	
	qualifiedProjectName: function(p)
	{
		var tags = this.filteredProjectTags(p.tags, []);
		var q = '';
		for (var i = 0; i < tags.length; i++)
			q += tags[i] + '.';
		return q + p.title;
	},
	
	toggleTag: function (tiddler, tag, toggle)
	{
		var tagIndex = -1;
		for (var i = 0; i < tiddler.tags.length; i++)
			if (tiddler.tags[i] == tag) {
				tagIndex = i;
				break;
			}
		
		if (toggle && tagIndex == -1) {
			tiddler.tags.push(tag);
		}
		else if (!toggle && tagIndex != -1) {
			tiddler.tags.splice(tagIndex, 1);
		}
	},
	
	getTiddlerElement: function (tiddler)
	{
		return document.getElementById(story.idPrefix + tiddler.title);
	},
	
	refreshActionViews: function (tiddler)
	{
		if (tiddler) {
			if (typeof(tiddler) == "string") tiddler = store.getTiddler(tiddler);
			if (tiddler) {
				// first refresh the action tiddler
				story.refreshTiddler(tiddler.title, null, true);
				// do not do anything else if we are not an action!
				// no, we still want to do review updates below, so only do the next bit for actions
				// if (!_GTD.tiddlerHasTag(tiddler, "action")) return;
				if (_GTD.tiddlerHasTag(tiddler, "action")) {
					// now refresh all tiddlers that are tags of the action, which should be the context and project
					// no...now use explicit reference to project/context
					//for (var i = 0; i < tiddler.tags.length; i++)
						// ...of course, we don't refresh action-specific state tags
					//	if (tiddler.tags[i] != "action" && tiddler.tags[i] != "done" && tiddler.tags[i] != "floating") {
					//		story.refreshTiddler(tiddler.tags[i], null, true);
					//	}
					if (tiddler.gtdProjectName && tiddler.gtdProjectName.length > 0) story.refreshTiddler(tiddler.gtdProjectName, null, true);
					// because an action change can affect multiple contexts (via next actions), the only way we can ensure that everything
					// gets updated is to refresh all the displayed contexts...hopefully, there won't be many open and DOM lookups fairly snappy
					// if (tiddler.gtdContextName && tiddler.gtdContextName.length > 0) story.refreshTiddler(tiddler.gtdContextName, null, true);
					_GTD.refreshAllContexts();
				}
				else if (_GTD.tiddlerHasTag(tiddler, "context"))
					_GTD.clearContextCache();
			}
		}
	
		var specialTiddlers = store.getTaggedTiddlers("review");
		for (var i = 0; i < specialTiddlers.length; i++)
			if (_GTD.tiddlerHasTag(specialTiddlers[i], "gtd")) {		// only update GTD review tiddlers, as an optimization
				// as a further optimization, we don't refresh tiddlers that aren't actually displayed, and make sure that
				// if they are displayed, they are in view mode, not edit mode
				var el = _GTD.getTiddlerElement(specialTiddlers[i]);
				if (el && el.getAttribute("template") == "reviewViewTemplate")
					story.refreshTiddler(specialTiddlers[i].title, null, true);
			}

	},
	
	appendProjectActionMarkup: function(projectTiddler, actionTitle, actionContext)
	{
		var actionInsertionPoint = -1, actionLeadin = "";
		
		var reActionWikitext = "^\\.{2}([^|\\n]+)(?:\\|?)(.*).*$";
		var reActionMacro = "(.*)<<gtdAction ((?:[^>]|(?:>(?!>)))*)>>.*$";
		var actionRe = new RegExp("(" + reActionWikitext + ")|(" + reActionMacro + ")", "mg");
		do {
			var formatMatch = actionRe.exec(projectTiddler.text);
			if (formatMatch) {
				actionLeadin = (formatMatch[1] ? "" : formatMatch[5]);
				actionInsertionPoint = actionRe.lastIndex;
			}
		} while(formatMatch);
		
		var actionProto = "\n" + actionLeadin + "<<gtdAction \"" + actionTitle + "\" \"" + actionContext + "\">>";
		if (actionInsertionPoint == -1)
			projectTiddler.text += actionProto;
		else
			projectTiddler.text = projectTiddler.text.substring(0, actionInsertionPoint) + actionProto + projectTiddler.text.substr(actionInsertionPoint);
		
		this.tiddlerHasChanged(projectTiddler);
		this.refreshActionViews(projectTiddler);
	},
	
	removeProjectAction: function(projectTiddler, actionTitle)
	{
		var reActionWikitext = "^(\\.{2})[ \\t]*(" + actionTitle + ")[ \\t]*((\\|.*\\n?)|(.*\\n?))";
		var reActionMacro = "(.*<<gtdAction [\"\']?)(" + actionTitle + ")([\"\']?\\s+(?:[^>]|(?:>(?!>)))*>>.*\\n?)";
		projectTiddler.text = projectTiddler.text.replace(new RegExp(reActionWikitext, "mg"), "");
		projectTiddler.text = projectTiddler.text.replace(new RegExp(reActionMacro, "mg"), "");
		projectTiddler.changed();
		story.refreshTiddler(projectTiddler.title, null, true);
	},
	
	setNextAction: function(project)
	{
		if (project.gtdActions == undefined) project.gtdActions = [];
		project.gtdNextAction = null;
		for (var i = 0; i < project.gtdActions.length; i++)
			if (!project.gtdActions[i].gtdActionDone) {
				project.gtdNextAction = project.gtdActions[i];
				project.gtdProjectDone = false;
				this.toggleTag(project, "done", project.gtdProjectDone);
				return;
			}
		// if we get here, project is currently complete
		if (project.gtdActions.length > 0) project.gtdProjectDone = true;
		this.toggleTag(project, "done", project.gtdProjectDone);
	},
	
	clearContextCache: function()
	{
		this.contextCache = null;
	},
	
	getCachedContexts: function()
	{
		if (!this.contextCache) this.contextCache = store.getTaggedTiddlers("context");
		return this.contextCache;
	},
	
	renameCachedContext: function(oldName, newName)
	{
		if (this.contextCache) {
			var index = this.contextCache.indexOf(oldName);
			if (index > -1) this.contextCache[index] = newName;
		}
	},
	
	findActionContext: function(action)
	{
		var context = null;
		
		var contexts = this.getCachedContexts();
		for (var i = 0; i < contexts.length; i++)
			if (_GTD.tiddlerHasTag(action, contexts[i].title)) {
				context = contexts[i].title;
				break;
			}
		
		return context;
	},
	
	refreshAllContexts: function()
	{
		var contexts = this.getCachedContexts();
		for (var i = 0; i < contexts.length; i++)
			story.refreshTiddler(contexts[i].title, null, true);
	},
	
	saveWithForcedBackup: function()
	{
		var saveBackups = config.options.chkSaveBackups;
		config.options.chkSaveBackups = true;
		saveChanges();
		config.options.chkSaveBackups = saveBackups;
	},
	
	isNextAction: function(actionTiddler)
	{
		if (actionTiddler.gtdProject && actionTiddler == actionTiddler.gtdProject.gtdNextAction)
			return true;
		return !actionTiddler.gtdActionDone && this.tiddlerHasTag(actionTiddler, "floating");
	},
	
	setReviewUpdate: function()
	{
		window._GTD = this;
		// having a subminute review update is overkill, but it would be nice to have semi-accurate
		// clock, so we can't have it be longer than a minute between updates
		//window.setTimeout('window._GTD.doReviewUpdate()', 60 * 1000);
		var d = new Date();
		window.setTimeout('window._GTD.doReviewUpdate()', (3600 - 60*d.getMinutes() - d.getSeconds()) * 1000);
	},
	
	doReviewUpdate: function()
	{
		this.refreshActionViews(null);
		this.setReviewUpdate();
	},
	
	setLazyAutoSave: function()
	{
		window._GTD = this;
		var interval = parseInt(config.options.txtGTDLazyAutoSaveInterval, 10);
		interval = isNaN(interval) ? 60 : interval.clamp(0, Number.MAX_VALUE);
		window.setTimeout('window._GTD.doLazyAutoSave()', interval * 1000);
	},
	
	doLazyAutoSave: function()
	{
		if (config.options.chkGTDLazyAutoSave && !config.options.chkAutoSave && (this.lazyAutoSave > 0 || store.isDirty())) {
			this.lazyAutoSave = 0;
			displayMessage('Autosaving changes...');
			saveChanges();
			if (typeof(gtdAutoSaveHook) == "function")
				gtdAutoSaveHook();
			window.setTimeout('clearMessage()', 5 * 1000);
		}
		this.setLazyAutoSave();
	},
	
	projectPriority: function(p)
	{
		var maxPriority = _GTD.projectPriorities.length;
		for (var i = 0; i < maxPriority; i++)
			if (_GTD.tiddlerHasTag(p, _GTD.projectPriorities[i])) return (maxPriority - i);
		return 0;
	},
	
	actionSorter: function(a,b)
	{
		// we now have an extended sort function to try and provide a more useful list of actions, esp. in a context view
		// ... the rule now is that project actions appear before non-project actions
		// ... if two actions have projects, and either project is tagged "important", it will appear first, otherwise actions are alphabetical by project
		// ... if two actions are from the same project, they appear in project action sequence, not alphabetically
		// ... all non-project actions continue to be sorted alphabetically
		
		if (a.gtdProject && b.gtdProject) {
			var aImportance = _GTD.projectPriority(a.gtdProject), bImportance = _GTD.projectPriority(b.gtdProject);
			if (a.gtdProject == b.gtdProject)
				return (a.gtdProject.gtdActions.indexOf(a) < b.gtdProject.gtdActions.indexOf(b)) ? -1 : +1;
			else if (aImportance != bImportance)
				return (aImportance > bImportance) ? -1 : +1;
			else
				return (a.gtdProject.title < b.gtdProject.title) ? -1 : +1;
		}
		else if (a.gtdProject)
			return -1;	// "a" has a project, "b" doesn't, so "a" comes first
		else if (b.gtdProject)
			return +1;	// "b" has a project, "a" doesn't, so "b" comes first
		else {
			var aImportance = _GTD.tiddlerHasTag(a, "important"), bImportance = _GTD.tiddlerHasTag(b, "important");
			if (aImportance && !bImportance)
				return -1;	// "a" is important, "b" is not, so "a" comes first
			else if (bImportance && !aImportance)
				return +1;	// "b" is important, "a" is not, so "a" comes first
			else
				return (a.title < b.title) ? -1 : +1;
		}
	},
	
	projectSorter: function(a,b) 
	{
		
		var aImportance = _GTD.projectPriority(a), bImportance = _GTD.projectPriority(b);
		if (aImportance != bImportance)
			return (aImportance > bImportance) ? -1 : +1;
		else
			return (a.title < b.title) ? -1 : +1;
	}
};

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

config.macros.list.tagged = {}
config.macros.list.tagged.innerHandler = function(tagList, allTags)
{
	var tiddlers = store.getTaggedTiddlers(tagList[0]);

	if (allTags) {
		var results = [];
		for (var i = 0; i < tiddlers.length; i++) {
			var tiddler = tiddlers[i], hasAllTags = true;
			for (var j = 1; hasAllTags && j < tagList.length; j++) {
				// hasAllTags &= _GTD.tiddlerHasTag(tiddler, tagList[j]);
				hasAllTags &= (tagList[j].charAt(0) == '-') ? !_GTD.tiddlerHasTag(tiddler, tagList[j].substr(1)) : _GTD.tiddlerHasTag(tiddler, tagList[j])
			}
			if (hasAllTags) results.push(tiddlers[i]);
		}
		return results;
	}
	else {
		for (var i = 1; i < tagList.length; i++) {
			var more = store.getTaggedTiddlers(tagList[i]);
			for (var j = 0; j < more.length; j++)
				tiddlers.pushUnique(more[j]);
		}
		return tiddlers;
	}
}
config.macros.list.tagged.handler = function(params) 
{
	var tags = params[1].readBracketedList();
	if (tags.length == 1) {
		if (config.options[tags[0]] == undefined)
			return store.getTaggedTiddlers(tags[0]);
		else
			return store.getTaggedTiddlers(config.options[tags[0]]);
	}
	else if (tags.length > 1) {
		var allTags = (params[2] == undefined || params[2] == 'all');
		var tiddlers = this.innerHandler(tags, allTags);
		tiddlers.sort(function (a,b) {if(a.title == b.title) return(0); else return (a.title < b.title) ? -1 : +1; });
		return tiddlers;
	}
}

config.macros.gtdActionList = {}
config.macros.gtdActionList.handler = function(place,macroName,params)
{
	var theList = createTiddlyElement(place, "ul", null, "gtdActionList");
	var parentTiddlerName = story.findContainingTiddler(place).getAttribute("tiddler");
	
	var allActions = (params[1] == "all");
	var noProjectActions = (params[1] == "noproject");
	var justProjectActions = (params[1] == "projectonly");
	var aging = parseInt(config.options.txtGTDActionAging, 10);
	aging = isNaN(aging) ? 0 : aging.clamp(0, Number.MAX_VALUE);
	
	if (params[0] == "*") {		// review actions for all projects
		var projects = store.getTaggedTiddlers("project");
		// do an importance sort on project list first, so they bubble to the top
		projects.sort(_GTD.projectSorter);
		for (var i = 0; i < projects.length; i++) {
			var project = projects[i];
			// filter projects that have been deferred
			if (_GTD.tiddlerHasTag(project, config.options.txtGTDSomedayContext)) continue;
			if (!allActions) {
				//var skipEmptyProject = true;
				//if (project.gtdActions != undefined && project.gtdActions.length > 0)
				//	for (var k = 0; skipEmptyProject && k < project.gtdActions.length; k++)
				//		skipEmptyProject = project.gtdActions[k].gtdActionDone;
				//if (skipEmptyProject) continue;
				if (project.gtdActions == undefined || project.gtdActions.length == 0 || project.gtdProjectDone) continue;
			}
			// this will present the actions in the same order as they appear in the project
			var theListItem = createTiddlyElement(theList, "li", null, "gtdActionListProject");
			createTiddlyLink(theListItem, project.title, true);
			if (project.gtdActions != undefined && project.gtdActions.length > 0) {
				var subList = createTiddlyElement(theList, "ul", null, "gtdActionList");
				for (var j = 0; j < project.gtdActions.length; j++) {
					var action = project.gtdActions[j];
					// if we are not displaying all actions, filter old completed actions (if specified)
					// if (!allActions && action.gtdActionDone && aging > 0 && _GTD.tiddlerAgeInDays(action) > aging) continue;
					// NEW! we are now filtering all completed actions unless we are displaying all actions
					if (!allActions && action.gtdActionDone) continue;
					var subListItem = createTiddlyElement(subList, "li");
					var el = config.macros.gtdAction.createActionElement(subListItem, action, project.title, action.tags);
				}
			}
		}
	}
	
	else if (params[0] == "@") {	// review actions for all contexts
		var contexts = _GTD.getCachedContexts();
		for (var i = 0; i < contexts.length; i++) {
			var context = contexts[i];
			var actions = config.macros.list.tagged.innerHandler([context.title, "action"], true);
			if (actions.length > 0) {
				var firstAction = true, theListItem, subList;
				actions.sort(_GTD.actionSorter);
				for (var j = 0; j < actions.length; j++) {
					var currentAction = actions[j];
					// special filtering by request...
					if (noProjectActions && currentAction.gtdProject) continue;
					if (justProjectActions && typeof(currentAction.gtdProject) == 'undefined') continue;
					// if we are not displaying all actions, filter completed actions and non-next project actions
					if (!allActions && (currentAction.gtdActionDone || (currentAction.gtdProject && !_GTD.isNextAction(currentAction)))) continue;
					// filter actions for projects that have been deferred
					if (currentAction.gtdProject && _GTD.tiddlerHasTag(currentAction.gtdProject, config.options.txtGTDSomedayContext)) continue;
					if (firstAction) {
						theListItem = createTiddlyElement(theList, "li", null, "gtdActionListContext");
						createTiddlyLink(theListItem, context.title, true);
						subList = createTiddlyElement(theList, "ul", null, "gtdActionList");
						firstAction = false;
					}
					var subListItem = createTiddlyElement(subList, "li");
					var el = config.macros.gtdAction.createActionElement(subListItem, currentAction, context.title, currentAction.tags);
				}
			}
		}
	}
	
	else {		// actions tagged by current tiddler name, or specified tag list as parameter
		var reviewMode = config.options['chkGTDActionListReviewMode' + escape(parentTiddlerName)];
		if (typeof(reviewMode) == 'undefined') reviewMode = false;
		
		// chain to our "tagged" list macro to get the tiddlers first
		var tags = (params.length == 0 || params[0] == "." ? [ parentTiddlerName ] : params[0].readBracketedList());
		tags.push("action");
		var results = config.macros.list.tagged.innerHandler(tags, true);
		results.sort(_GTD.actionSorter);
		for (var t = 0; t < results.length; t++) {
			var action = results[t];
			// special filtering by request...
			if (noProjectActions && action.gtdProject) continue;
			if (justProjectActions && typeof(action.gtdProject) == 'undefined') continue;
			if (action.gtdProject && _GTD.tiddlerHasTag(action.gtdProject, config.options.txtGTDSomedayContext)) continue;
			// if we are not displaying all actions, filter completed actions and non-next project actions
			if (reviewMode && !allActions && (action.gtdActionDone || (action.gtdProject && !_GTD.isNextAction(action)))) continue;
			// if we are not displaying all actions, filter old completed actions (if specified)
			if (!allActions && action.gtdActionDone && aging > 0 && _GTD.tiddlerAgeInDays(action) > aging) continue;
			var theListItem = createTiddlyElement(theList, "li");
			var el = config.macros.gtdAction.createActionElement(theListItem, action, parentTiddlerName, action.tags);
		}
	}
}

config.macros.gtdAction = {}
config.macros.gtdAction.createActionElement = function(place, actionTiddler, filterName, tags)
{
	if (typeof(actionTiddler) == "string") actionTiddler = store.getTiddler(actionTiddler);
	
	var actionElement = createTiddlyElement(place, "span", null, "gtdActionItem");
	
	// oddly, we barf when setting the checkbox type on an input if we use createTiddlyElement...
	var cb = document.createElement("input");
	cb.setAttribute("type", "checkbox");
	cb.setAttribute("actionTiddler", actionTiddler.title);
	cb.onclick = this.onClickDone;
	actionElement.appendChild(cb);
	cb.checked = actionTiddler.gtdActionDone;
	createTiddlyLink(actionElement, actionTiddler.title, true);
	actionElement.className = (actionTiddler.text ? "gtdActionWithContent" : "gtdActionWithoutContent");
	if (actionTiddler.gtdActionDone) actionElement.className += " gtdCompletedActionItem";
	if (_GTD.isNextAction(actionTiddler)) actionElement.className += " gtdNextActionItem";
	
	var filterTags = [], actionTags = [];
	if (actionTiddler.gtdProjectName && actionTiddler.gtdProjectName.length > 0)
		actionTags.push(actionTiddler.gtdProjectName);
	if (actionTiddler.gtdContextName && actionTiddler.gtdContextName.length > 0)
		actionTags.push(actionTiddler.gtdContextName);
	for (var i = 0; i < tags.length; i++) actionTags.pushUnique(tags[i]);
	if (filterName && filterName.length > 0) filterTags.pushUnique(filterName);
	
	actionTags = _GTD.filteredActionTags(actionTags, filterTags);
	if (actionTags.length > 0) {
		createTiddlyText(actionElement, " [ ");
		for (var i = 0; i < actionTags.length; i++) {
			if (i > 0) createTiddlyText(actionElement, ", ");
			createTiddlyLink(actionElement, actionTags[i], true, "actionCrossReference");
		}
		createTiddlyText(actionElement, " ]");
	}
	
	return actionElement;
}

config.macros.gtdAction.onClickDone = function(e)
{
	var tiddler = store.getTiddler(this.getAttribute("actionTiddler"));
	if (tiddler) {
		_GTD.toggleTag(tiddler, "done", this.checked);
		tiddler.gtdActionDone = this.checked;
		_GTD.tiddlerHasChanged(tiddler);
		_GTD.refreshActionViews(tiddler);
		if (this.checked && typeof(gtdActionDoneHook) == "function")
			gtdActionDoneHook(tiddler);
		if (tiddler.gtdActionDone && tiddler.gtdProject == undefined && confirm("This action is not a part of a project. Would you just like to delete it?")) {
			story.closeTiddler(tiddler.title, false, false);
			store.removeTiddler(tiddler.title);
		}
	}
	return true;
}

config.macros.gtdAction.handler = function(place,macroName,params)
{
	var title = params[0], tags;
	var parentTiddlerName = story.findContainingTiddler(place).getAttribute("tiddler");
	var tiddler = store.getTiddler(title);
	if (!tiddler) {
		// we should *never* get here now for project actions, but keep code in case project code
		// trips up, or we use this macro somewhere else
		this.createAction(title, parentTiddlerName, params[1]);
	}
	else
		// use actual tiddler tags, not macro param, in case context changed!
		tags = tiddler.tags;
	var action = this.createActionElement(place, title, parentTiddlerName, tags);
}

config.macros.gtdAction.createAction = function(title, projectTiddlerName, tagParams, extraTags)
{
	// var tags = ["action", parentTiddler];
	var action, tags = ["action"], fields = {};
	if (_GTD.usingProjectTags)
		tags.push(projectTiddlerName);
	if (typeof(tagParams) == "string") tags = tags.concat(tagParams.readBracketedList());
	if (typeof(extraTags) == "string") tags = tags.concat(extraTags.readBracketedList());
	var templateText = store.getTiddlerText("NewActionTemplate", config.views.wikified.defaultText.format([title]));
	if (_GTD.usingProjectTags)
		action = store.saveTiddler(title, title, templateText, config.options.txtUserName, new Date(), tags);
	else {
		fields["gtd.project"] = projectTiddlerName;
		action = store.saveTiddler(title, title, templateText, config.options.txtUserName, new Date(), tags, fields);
	}
	return action;
}

config.macros.gtdActionCompleted = {}
config.macros.gtdActionCompleted.handler = function(place,macroName,params)
{
	if (!readOnly) {
		var title = story.findContainingTiddler(place).getAttribute("tiddler");
		var tiddler = store.getTiddler(title);
		// oddly, we barf when setting the checkbox type on an input if we use createTiddlyElement...
		var cb = document.createElement("input");
		cb.setAttribute("type", "checkbox");
		cb.setAttribute("actionTiddler", title);
		cb.onclick = this.onClickDone;
		place.appendChild(cb);
		cb.checked = tiddler.gtdActionDone;
	}
}

config.macros.gtdActionCompleted.onClickDone = function(e)
{
	var tiddler = store.getTiddler(this.getAttribute("actionTiddler"));
	if (tiddler) {
		_GTD.toggleTag(tiddler, "done", this.checked);
		tiddler.gtdActionDone = this.checked;
		_GTD.tiddlerHasChanged(tiddler);
		_GTD.refreshActionViews(tiddler);
		if (this.checked && typeof(gtdActionDoneHook) == "function")
			gtdActionDoneHook(tiddler);
		if (tiddler.gtdActionDone && tiddler.gtdProject == undefined && confirm("This action is not a part of a project. Would you just like to delete it?")) {
			story.closeTiddler(tiddler.title, false, false);
			store.removeTiddler(tiddler.title);
		}
	}
	return true;
}

config.macros.gtdToggleTag = {}
config.macros.gtdToggleTag.handler = function(place,macroName,params)
{
	if (!readOnly) {
		var title = story.findContainingTiddler(place).getAttribute("tiddler");
		var tiddler = store.getTiddler(title);
		// oddly, we barf when setting the checkbox type on an input if we use createTiddlyElement...
		var cb = document.createElement("input");
		cb.setAttribute("type", "checkbox");
		cb.setAttribute("tiddler", title);
		cb.setAttribute("toggledTag", params[0]);
		cb.onclick = this.onClickDone;
		place.appendChild(cb);
		cb.checked = _GTD.tiddlerHasTag(tiddler, params[0]);
	}
}

config.macros.gtdToggleTag.onClickDone = function(e)
{
	var tiddler = store.getTiddler(this.getAttribute("tiddler"));
	if (tiddler) {
		_GTD.toggleTag(tiddler, this.getAttribute("toggledTag"), this.checked);
		_GTD.tiddlerHasChanged(tiddler);
		if (_GTD.tiddlerHasTag(tiddler, "action"))
			_GTD.refreshActionViews(tiddler);
		else
			// we need a broad notification here, not just refreshActionViews
			store.notify(tiddler.title, true);
	}
	return true;
}

config.macros.gtdToggleState = {}
config.macros.gtdToggleState.handler = function(place,macroName,params)
{
	var title = story.findContainingTiddler(place).getAttribute("tiddler");
	var tiddler = store.getTiddler(title);
	// oddly, we barf when setting the checkbox type on an input if we use createTiddlyElement...
	var cb = document.createElement("input");
	cb.setAttribute("type", "checkbox");
	cb.setAttribute("tiddler", title);
	var state = params[0] + escape(title);
	cb.setAttribute("stateName", state);
	cb.onclick = this.onClickDone;
	place.appendChild(cb);
	cb.checked = config.options[state];
}

config.macros.gtdToggleState.onClickDone = function(e)
{
	var tiddler = store.getTiddler(this.getAttribute("tiddler"));
	if (tiddler) {
		var state = this.getAttribute("stateName");
		config.options[state] = this.checked;
		saveOptionCookie(state);
		story.refreshTiddler(tiddler.title, null, true);
	}
	return true;
}

config.macros.importUpdates = { 
	importMode: "updates",
	buttonTitle: "Update", 
	buttonHelp: "Click here to update the application",
	missingHelperMessage: "This functionality depends on the LoadTiddlersPlugin, which is missing. Please import the plugin from TiddlyTools.",
	preUpdateMessage: "Once the download is finished, you will need to reload your document to complete the update. In order to allow you to review the update tiddlers, this will not be done automatically. \n\nClick \"OK\" start the update.",
	postUpdateMessage: "Please remember, you will need to save and reload your document to complete the update. In order to allow you to review the update tiddlers, this will not be done automatically."
}
config.macros.importUpdates.handler = function(place, macroName, params)
{
	var mode = params[1] ? params[1] : this.importMode;
	var title = params[2] ? params[2] : this.buttonTitle;
	var prompt = params[3] ? params[3] : this.buttonHelp;
	var button = createTiddlyButton(place, title, prompt, this.onClickUpdate);
	button.setAttribute("updateSource", params[0]);
	button.setAttribute("importMode", mode);
	if (params.length > 4) button.setAttribute("importExtras", params.slice(4).join(" "));
}

config.macros.importUpdates.onClickUpdate = function(e)
{
	if (config.macros.loadTiddlers == undefined || version.extensions.LoadTiddlersPlugin == undefined) {
		alert(config.macros.importUpdates.missingHelperMessage);
		return;
	}
	if (!confirm(config.macros.importUpdates.preUpdateMessage))
		return;
	var importParams = [ this.getAttribute("importMode"), this.getAttribute("updateSource") ];
	var importExtras = this.getAttribute("importExtras");
	if (importExtras) importParams = importParams.concat(importExtras.split(" "));
	// force a saveChanges with backup before the update
	_GTD.saveWithForcedBackup();
	// chain to the loadTiddlers macro
	config.macros.loadTiddlers.handler(this, "loadTiddlers", importParams);
	// ensure that relevant release notes are displayed on first launch
	config.options.chkGTDReleaseNotes = true;
	saveOptionCookie("chkGTDReleaseNotes");
	// do *not* cause a browser navigation
	return false;
}

config.macros.gtdArchive = {}
config.macros.gtdArchive.handler = function(place, macroName, params)
{
	var archiveAction = params.length > 0 ? params[0] : "archive"
	var btn = createTiddlyButton(place, archiveAction, "", this.onClick);
	btn.setAttribute("archiveAction", archiveAction);
}

config.macros.gtdArchive.onClick = function(e)
{
	var warning = "Are you sure you want to %0 all %1 projects and actions?";
	var status = "There were %0 project(s) and %1 action(s) %2d.";
	var archiveAction = this.getAttribute("archiveAction");
	
	var projectCount = 0, actionCount = 0;
	
	if (archiveAction == "archive") {
		if (confirm(warning.format([archiveAction, "completed"]))) {
			clearMessage();
			var projects = store.getTaggedTiddlers("project");
			for (var i = 0; i < projects.length; i++) {
				var project = projects[i];
				if (project.gtdActions == undefined || project.gtdActions.length == 0) continue;
				var projectComplete = true;
				for (var j = 0; projectComplete && j < project.gtdActions.length; j++)
					projectComplete = project.gtdActions[j].gtdActionDone;
				if (!projectComplete) continue;
				// if we get here, all project actions are done, so archive project
				story.closeTiddler(project.title, false, false);
				_GTD.tiddlerSwapTag(project, "project", "project-archive");
				_GTD.tiddlerHasChanged(project, false);
				projectCount++;
				for (j = 0; j < project.gtdActions.length; j++) {
					story.closeTiddler(project.gtdActions[j].title, false, false);
					_GTD.tiddlerSwapTag(project.gtdActions[j], "action", "action-archive");
					_GTD.tiddlerHasChanged(project.gtdActions[j], false);
					actionCount++;
				}
			}
			var actions = store.getTaggedTiddlers("action");
			for (i = 0; i < actions.length; i++) {
				var action = actions[i];
				if (action.gtdActionDone && !action.gtdProject) {
					story.closeTiddler(action.title, false, false);
					_GTD.tiddlerSwapTag(action, "action", "action-archive");
					_GTD.tiddlerHasChanged(action, false);
					actionCount++;
				}
			}
			displayMessage(status.format([projectCount, actionCount, archiveAction]));
			var saveClearMessage = clearMessage;
			clearMessage = function() {};
			if (config.options.chkAutoSave) saveChanges();
			clearMessage = saveClearMessage;
			store.notify(null, true);
		}
	}
	
	else if (archiveAction == "unarchive") {
		if (confirm(warning.format([archiveAction, "archived"]))) {
			clearMessage();
			var projects = store.getTaggedTiddlers("project-archive");
			for (var i = 0; i < projects.length; i++) {
				var project = projects[i];
				story.closeTiddler(project.title, false, false);
				_GTD.tiddlerSwapTag(project, "project-archive", "project");
				_GTD.tiddlerHasChanged(project, false);
				projectCount++;
			}
			var actions = store.getTaggedTiddlers("action-archive");
			for (i = 0; i < actions.length; i++) {
				var action = actions[i];
				story.closeTiddler(action.title, false, false);
				_GTD.tiddlerSwapTag(action, "action-archive", "action");
				_GTD.tiddlerHasChanged(action, false);
				actionCount++;
			}
			displayMessage(status.format([projectCount, actionCount, archiveAction]));
			var saveClearMessage = clearMessage;
			clearMessage = function() {};
			if (config.options.chkAutoSave) saveChanges();
			clearMessage = saveClearMessage;
			store.notify(null, true);
		}
	}
	
	else if (archiveAction == "purge") {
		if (confirm(warning.format([archiveAction, "archived"]))) {
			clearMessage();
			_GTD.saveWithForcedBackup();
			var projects = store.getTaggedTiddlers("project-archive");
			for (var i = 0; i < projects.length; i++) {
				var project = projects[i];
				story.closeTiddler(project.title, false, false);
				store.removeTiddler(project.title);
				projectCount++;
			}
			var actions = store.getTaggedTiddlers("action-archive");
			for (i = 0; i < actions.length; i++) {
				var action = actions[i];
				story.closeTiddler(action.title, false, false);
				store.removeTiddler(action.title);
				actionCount++;
			}
			displayMessage(status.format([projectCount, actionCount, archiveAction]));
			var saveClearMessage = clearMessage;
			clearMessage = function() {};
			if (config.options.chkAutoSave) saveChanges();
			clearMessage = saveClearMessage;
			store.notify(null, true);
		}
	}
	else
		alert("That archiving action is not supported");
}

config.formatters.push(
	{
	name: "gtdAction",
	match: "^\\.{2}.*",
	lookahead: "^\\.{2}([^|]*)(?:\\|?)(.*)",
	handler: function(w)
		{
			var lookaheadRegExp = new RegExp(this.lookahead,"g");
			var lookaheadMatch = lookaheadRegExp.exec(w.matchText)
			if (lookaheadMatch) {
				var params = [ lookaheadMatch[1].trim() ];
				if (lookaheadMatch[2].trim().length > 0) params.push(lookaheadMatch[2].trim());
				config.macros.gtdAction.handler(w.output, "gtdAction", params);
			}
		}
	}
);

config.commands.newAction = { text: "action", tooltip: "Create a new action for this context", hideReadOnly: true };
config.commands.newAction.handler = function(event, src, context)
{
	var d = new Date();
	var newActionTitle = d.formatString("New Action hh:0mm:0ss");
	if (!store.tiddlerExists(newActionTitle)) {
		var tiddler = store.createTiddler(newActionTitle);
		var templateText = store.getTiddlerText("NewActionTemplate", config.views.wikified.defaultText.format([newActionTitle]));
		tiddler.assign(newActionTitle, templateText, config.options.txtUserName, new Date(), [ "action", context ]);
		
		story.displayTiddler(null, newActionTitle, DEFAULT_EDIT_TEMPLATE);
		story.focusTiddler(newActionTitle, "title");
	}
	return false;
}

config.commands.newProjectAction = { text: "action", tooltip: "Create a new action for this project", hideReadOnly: true };
config.commands.newProjectAction.handler = function(event, src, project)
{
	var d = new Date();
	var newActionTitle = d.formatString("New Action hh:0mm:0ss");
	if (!store.tiddlerExists(newActionTitle)) {
		var defaultContext = config.options.txtGTDUnfiledContext;
		_GTD.appendProjectActionMarkup(store.getTiddler(project), newActionTitle, defaultContext);
		
		var tiddler = store.createTiddler(newActionTitle);
		var templateText = store.getTiddlerText("NewActionTemplate", config.views.wikified.defaultText.format([newActionTitle]));
		var tags = ["action"], fields = {};
		if (_GTD.usingProjectTags)
			tags.push(project);
		tags.push(defaultContext);
		if (_GTD.usingProjectTags)
			tiddler.assign(newActionTitle, templateText, config.options.txtUserName, new Date(), tags);
		else {
			fields["gtd.project"] = project;
			tiddler.assign(newActionTitle, templateText, config.options.txtUserName, new Date(), tags, new Date(), fields);
		}
		
		story.displayTiddler(null, newActionTitle, DEFAULT_EDIT_TEMPLATE);
		story.focusTiddler(newActionTitle, "title");
	}
	return false;
}

config.commands.changeContext = { text: "context", tooltip: "Change context of this action", hideReadOnly: true, popupNone: "There are no contexts" };
config.commands.changeContext.handler = function(event,src,title)
{
	var popup = Popup.create(src);
	if (popup) {
		var contexts = _GTD.getCachedContexts();
		var tiddler = store.getTiddler(title);
		var currentContext = _GTD.findActionContext(tiddler);
		if (!currentContext) currentContext = '';
		
		var c = false;
		for (var i = 0; i < contexts.length; i++)
			if (contexts[i].title != currentContext) {
				var button = createTiddlyButton(createTiddlyElement(popup, "li"), contexts[i].title, '', this.onClickContext);
				button.setAttribute("actionTiddler", title);
				button.setAttribute("oldContext", currentContext);
				button.setAttribute("newContext", contexts[i].title);
				c = true;
			}
			
		if (!c)
			createTiddlyText(createTiddlyElement(popup, "li", null, "disabled"), this.popupNone);
	}
	
	Popup.show(popup, false);
	event.cancelBubble = true;
	if (event.stopPropagation) event.stopPropagation();
	// do *not* cause a browser navigation
	return false;
}

config.commands.changeContext.onClickContext = function(e)
{
	var tiddler = store.getTiddler(this.getAttribute("actionTiddler"));
	if (tiddler) {
		var contextChanged = false;
		var oldContext = this.getAttribute("oldContext");
		var newContext = this.getAttribute("newContext");
		if (oldContext.length == 0)
			contextChanged = (tiddler.tags.push(newContext) > 0);
		else
			contextChanged = _GTD.tiddlerSwapTag(tiddler, oldContext, newContext);
		
		if (contextChanged) {
			tiddler.gtdContextName = newContext;
			_GTD.setExtendedValue(tiddler, "gtd.context", newContext);
			_GTD.tiddlerHasChanged(tiddler);
			_GTD.refreshActionViews(tiddler);
			// be sure to refresh old context as well...
			story.refreshTiddler(oldContext, null, true);
		}
	}
	// do *not* cause a browser navigation
	return false;
}

config.commands.changeProject = { text: "project", tooltip: "Change project of this action", hideReadOnly: true, popupNone: "There are no projects" };
config.commands.changeProject.handler = function(event,src,title)
{
	var popup = Popup.create(src);
	if (popup) {
		var projects = store.getTaggedTiddlers("project");
		var tiddler = store.getTiddler(title);
		var currentProject = (tiddler.gtdProject ? tiddler.gtdProject.title : '');
		
		var c = false;
		for (var i = 0; i < projects.length; i++)
			if (projects[i].title != currentProject) {
				var button = createTiddlyButton(createTiddlyElement(popup, "li"), projects[i].title, '', this.onClickProject);
				button.setAttribute("actionTiddler", title);
				button.setAttribute("oldProject", currentProject);
				button.setAttribute("newProject", projects[i].title);
				c = true;
			}
			
		if (!c)
			createTiddlyText(createTiddlyElement(popup, "li", null, "disabled"), this.popupNone);
	}
	
	Popup.show(popup, false);
	event.cancelBubble = true;
	if (event.stopPropagation) event.stopPropagation();
	// do *not* cause a browser navigation
	return false;
}

config.commands.changeProject.onClickProject = function(e)
{
	var tiddler = store.getTiddler(this.getAttribute("actionTiddler"));
	if (tiddler) {
		var oldProject = this.getAttribute("oldProject");
		var newProject = this.getAttribute("newProject");
		
		if (oldProject.length > 0)
			_GTD.removeProjectAction(tiddler.gtdProject, tiddler.title)
		if (_GTD.usingProjectTags)
			_GTD.tiddlerSwapTag(tiddler, oldProject, newProject);
		else
			_GTD.setExtendedValue(tiddler, "gtd.project", newProject);
		_GTD.appendProjectActionMarkup(store.getTiddler(newProject), tiddler.title, tiddler.gtdContextName);
		
		_GTD.tiddlerHasChanged(tiddler);
		_GTD.refreshActionViews(tiddler);
	}
	// do *not* cause a browser navigation
	return false;
}

config.commands.deleteAction = { text: "delete", tooltip: "Delete this action", hideReadOnly: true, warning: "Are you sure you want to delete '%0'?", altwarning: "Are you sure you want to delete '%0'? The action will also be removed from project '%1'." };
config.commands.deleteAction.handler = function(event, src, title)
{
	var tiddler = store.getTiddler(title);
	var ok = (tiddler.gtdProject ? confirm(this.altwarning.format([title, tiddler.gtdProject.title])) : confirm(this.warning.format([title])));
	if (ok) {
		if (tiddler.gtdProject) _GTD.removeProjectAction(tiddler.gtdProject, title);
		store.removeTiddler(title);
		story.closeTiddler(title,true,event.shiftKey || event.altKey);
		if (config.options.chkAutoSave)
			saveChanges();
	}
	
	return false;
}

config.commands.deleteContext = { text: "delete", tooltip: "Delete this context", hideReadOnly: true, warning: "Are you sure you want to delete '%0'? All associated actions will be tagged as 'unfiled'." };
config.commands.deleteContext.handler = function(event, src, title)
{
	if (confirm(this.warning.format([title]))) {
		store.suspendNotifications();
		this.unlinkActions(title);
		// force a rebuild of our context cache
		_GTD.clearContextCache();
		store.resumeNotifications();
		store.removeTiddler(title);
		story.closeTiddler(title,true,event.shiftKey || event.altKey);
		if (config.options.chkAutoSave)
			saveChanges();
	}
	
	return false;
}

config.commands.deleteContext.unlinkActions = function(contextTitle)
{
	var tiddlers = config.macros.list.tagged.innerHandler([contextTitle, "action"], true);
	for (var i = 0; i < tiddlers.length; i++) {
		var tiddler = tiddlers[i];
		_GTD.tiddlerSwapTag(tiddler, contextTitle, config.options.txtGTDUnfiledContext);
		_GTD.tiddlerHasChanged(tiddler, false);
		// context removal will do view notification...
	}
}

config.commands.archiveProject = { text: "archive", tooltip: "Archive this project", hideReadOnly: true, warning: "Are you sure you want to archive '%0'?", noarchive: "This project is %0 and will not be archived." };
config.commands.archiveProject.handler = function(event, src, title)
{
	if (confirm(this.warning.format([title]))) {
		var project = store.getTiddler(title);
		if (project.gtdActions == undefined || project.gtdActions.length == 0) {
			alert(this.noarchive.format(["empty"]));
			return;
		}
		var projectComplete = true;
		for (var j = 0; projectComplete && j < project.gtdActions.length; j++)
			projectComplete = project.gtdActions[j].gtdActionDone;
		if (!projectComplete) {
			alert(this.noarchive.format(["incomplete"]));
			return;
		}
		// if we get here, all project actions are done, so archive project
		story.closeTiddler(project.title, false, false);
		_GTD.tiddlerSwapTag(project, "project", "project-archive");
		_GTD.tiddlerHasChanged(project, false);
		for (j = 0; j < project.gtdActions.length; j++) {
			story.closeTiddler(project.gtdActions[j].title, false, false);
			_GTD.tiddlerSwapTag(project.gtdActions[j], "action", "action-archive");
			_GTD.tiddlerHasChanged(project.gtdActions[j], false);
		}
		store.notify(null, true);
		if (config.options.chkAutoSave)
			saveChanges();
	}

	return false;
}

config.commands.deleteProject = { text: "delete", tooltip: "Delete this project", hideReadOnly: true, warning: "Are you sure you want to delete '%0'? All associated actions will no longer be bound to this (or any) project." };
config.commands.deleteProject.handler = function(event, src, title)
{
	if (confirm(this.warning.format([title]))) {
		store.suspendNotifications();
		this.unlinkActions(title);
		store.resumeNotifications();
		store.removeTiddler(title);
		story.closeTiddler(title,true,event.shiftKey || event.altKey);
		if (config.options.chkAutoSave)
			saveChanges();
	}
	
	return false;
}

config.commands.deleteProject.unlinkActions = function(projectTitle)
{
	// var tiddlers = config.macros.list.tagged.innerHandler([projectTitle, "action"], true);
	var project = store.getTiddler(projectTitle);
	for (var i = 0; i < project.gtdActions.length; i++) {
		var tiddler = project.gtdActions[i];
		tiddler.gtdProject = null;
		tiddler.gtdProjectName = null;
		if (_GTD.usingProjectTags)
			tiddler.tags.splice(tiddler.tags.indexOf(projectTitle), 1);
		else {
			_GTD.setExtendedValue(tiddler, "gtd.project", null);
			_GTD.setExtendedValue(tiddler, "gtd.projectindex", null);
		}
		_GTD.tiddlerHasChanged(tiddler, false);
		// project removal will do view notification...
	}
}

config.commands.deleteProjectAll = { text: "delete all", tooltip: "Delete this project and its actions", hideReadOnly: true, warning: "Are you sure you want to delete '%0' and all its associated actions?" };
config.commands.deleteProjectAll.handler = function(event, src, title)
{
	if (confirm(this.warning.format([title]))) {
		store.suspendNotifications();
		this.deleteActions(title);
		store.resumeNotifications();
		store.removeTiddler(title);
		story.closeTiddler(title,true,event.shiftKey || event.altKey);
		if (config.options.chkAutoSave)
			saveChanges();
	}
	
	return false;
}

config.commands.deleteProjectAll.deleteActions = function(projectTitle)
{
	// var tiddlers = config.macros.list.tagged.innerHandler([projectTitle, "action"], true);
	var project = store.getTiddler(projectTitle);
	for (var i = 0; i < project.gtdActions.length; i++) {
		var tiddler = project.gtdActions[i].title;
		store.removeTiddler(tiddler);
		story.closeTiddler(tiddler, true, false);
		// project removal will do view notification...
	}
}

config.commands.projectify = { text: "projectify", tooltip: "Convert this action to a project", hideReadOnly: true, warning: "Are you sure you want to convert '%0' to a project?" };
config.commands.projectify.handler = function(event, src, title)
{
	if (confirm(this.warning.format([title]))) {
		var tiddler = store.getTiddler(title);
		if (tiddler.gtdProject) _GTD.removeProjectAction(tiddler.gtdProject, title);
		tiddler.tags = [ "project" ];
		_GTD.tiddlerHasChanged(tiddler, true);
		// we need a broad notification here, not just refreshActionViews
		store.notify(title, true);
	}
	
	return false;
}

// *** ***/
// *** These are overrides to core TiddlyWiki functionality ***
// *** ***/

Tiddler.prototype._GTDInheritedChanged = Tiddler.prototype.changed;
Tiddler.prototype.changed = function()
{
	this._GTDInheritedChanged();
	
	// Note that this is called both as part of normal tiddler changes AND as a part
	// of the initial TW loading process from DIVs...
	
	if (_GTD.tiddlerHasTag(this, "project")) {
		// (re)build the in-memory ordered action list
		this.gtdActions = [];
		this.gtdNextAction = null;
		if (this.text) {
			var reActionWikitext = "^\\.{2}([^|\\n]+)(?:\\|?)(.*)";
			var reActionMacro = "<<gtdAction ((?:[^>]|(?:>(?!>)))*)>>";
			var actionRe = new RegExp("(" + reActionWikitext + ")|(" + reActionMacro + ")", "mg");
			do {
				var formatMatch = actionRe.exec(this.text);
				if (formatMatch) {
					var macroParams = (formatMatch[1] ? null : formatMatch[5].readMacroParams());
					// note that for the ".." notation, we are trimming up action titles and contexts
					var actionTiddlerName = (formatMatch[1] ? formatMatch[2].trim() : macroParams[0]);
					var actionTiddler = store.getTiddler(actionTiddlerName);
					if (!actionTiddler) {
						var actionTags = (formatMatch[1] ? formatMatch[3].trim() : macroParams[1]);
						var extraTags = (formatMatch[1] ? '' : macroParams[2]);
						actionTiddler = config.macros.gtdAction.createAction(actionTiddlerName, this.title, actionTags, extraTags);
					}
					if (actionTiddler) {
						actionTiddler.gtdProject = this;
						if (this.gtdNextAction == null && !_GTD.tiddlerHasTag(actionTiddler, "done"))
							this.gtdNextAction = actionTiddler;
						this.gtdActions.push(actionTiddler);
						_GTD.setExtendedValue(actionTiddler, "gtd.projectindex", this.gtdActions.length - 1);
						// handle project renaming in action
						if (actionTiddler.gtdProjectName && actionTiddler.gtdProjectName != this.title) {
							if (_GTD.usingProjectTags)
								_GTD.tiddlerSwapTag(actionTiddler, actionTiddler.gtdProjectName, this.title);
							else
								_GTD.setExtendedValue(actionTiddler, "gtd.project", this.title);
							// action view won't get updated through any other refresh mechanism, so
							story.refreshTiddler(actionTiddler.title, null, true);
						}
						actionTiddler.gtdProjectName = this.title;
					}
				}
			} while(formatMatch);
		}
	}
	
	else if (_GTD.tiddlerHasTag(this, "context")) {
		if (this.gtdContextName == undefined)
			this.gtdContextName = this.title;
		else if (this.gtdContextName != this.title) {
			// propagate renamed context to affected actions
			store.suspendNotifications();
			var results = config.macros.list.tagged.innerHandler([ this.gtdContextName, "action"], true);
			for (var t = 0; t < results.length; t++) {
				_GTD.tiddlerSwapTag(results[t], this.gtdContextName, this.title);
				results[t].gtdContextName = this.title;
				_GTD.setExtendedValue(results[t], "gtd.context", this.title);
				// action view won't get updated through any other refresh mechanism, so
				//story.refreshTiddler(results[t].title, null, true);
			}
			// because the store is not yet updated, we need to manipulate the context cache directly
			_GTD.renameCachedContext(this.gtdContextName, this.title);
			this.gtdContextName = this.title;
			// we need a broad notification here, not just refreshActionViews
			store.resumeNotifications();
			store.notify(null, true);
		}
	}
	
	else if (_GTD.tiddlerHasTag(this, "action")) {
		if (this.gtdActionName == undefined)
			this.gtdActionName = this.title;
		else if (this.gtdActionName != this.title && this.gtdProject) {
			// ugh...dig into related project and update the wiki code to use new action name
			var reActionWikitext = "^(\\.{2}[ \\t]*)(" + this.gtdActionName + ")(([ \\t]*\\|.*\\n?)|(\\n?))";
			var reActionMacro = "(<<gtdAction [\"\']?)(" + this.gtdActionName + ")([\"\']?\\s+(?:[^>]|(?:>(?!>)))*>>)";
			this.gtdProject.text = this.gtdProject.text.replace(new RegExp(reActionWikitext, "mg"), "$1" + this.title + "$3");
			this.gtdProject.text = this.gtdProject.text.replace(new RegExp(reActionMacro, "mg"), "$1" + this.title + "$3");
			this.gtdActionName = this.title;
		}
		this.gtdActionDone = _GTD.tiddlerHasTag(this, "done");
		this.gtdContextName = _GTD.findActionContext(this);
		_GTD.setExtendedValue(this, "gtd.context", this.gtdContextName);
		// reset the next action on the associated project
		if (this.gtdProject) _GTD.setNextAction(this.gtdProject);
	}
}

Story.prototype.chooseTemplateForTiddler = function(title,template)
{
	// This override to core TW functionality is used to provide tag-based view and edit templates. The
	// basic idea is that the tiddler is scanned for its tags and, depending on whether we are opening a
	// tiddler in "view" or "edit" mode, a corresponding 'tag + "ViewTemplate"' or 'tag + "EditTemplate"'
	// tiddler is searched for. If it exists, it is used instead of the default templates.
	
	if (!template)
		template = DEFAULT_VIEW_TEMPLATE;

	// before reverting to default behaviour, check to see if a tag-based template exists
	if (template == DEFAULT_VIEW_TEMPLATE || template == DEFAULT_EDIT_TEMPLATE) {
		if (this.tagBasedTemplateCache == undefined) this.tagBasedTemplateCache = new Array();
		var templateRoot = (template == DEFAULT_VIEW_TEMPLATE ? "ViewTemplate" : "EditTemplate");
		var tiddler = store.getTiddler(title);
		if (tiddler) {
			for (var i = 0; i < tiddler.tags.length; i++) {
				var tag = tiddler.tags[i];
				var tagTemplate = tag + templateRoot;
				var tagCacheId = tag + template;
				// first check our cache to see if we have seen this template before
				if (this.tagBasedTemplateCache[tagCacheId] != undefined) {
					// make sure template still exists
					if (store.tiddlerExists(this.tagBasedTemplateCache[tagCacheId])) {
						template = this.tagBasedTemplateCache[tagCacheId];
						break;
					}
					else
						delete this.tagBasedTemplateCache[tagCacheId];
				}
				// go to the store to see if template exists
				if (store.tiddlerExists(tagTemplate)) {
					template = tagTemplate;
					this.tagBasedTemplateCache[tagCacheId] = tagTemplate;
					break;
				}
			}
		}
	}
	
	if (template == DEFAULT_VIEW_TEMPLATE || template == DEFAULT_EDIT_TEMPLATE)
		template = config.tiddlerTemplates[template];
	return template;
}

// Clint Checketts' IE first-child patch, version 1.1, http://www.checkettsweb.com/tw/gtd_tiddlywiki.htm#GiveFirstTiddlerClassPatch

Story.prototype.closeTiddlerIEFirstChild = Story.prototype.closeTiddler;
Story.prototype.closeTiddler = function(title,animate,slowly) {
	var tiddler = document.getElementById(this.idPrefix + title);
	// we need to test to ensure tiddler is actually open
	if (tiddler) {
		var storyArea = tiddler.parentNode;
		if ((this.idPrefix + title) == storyArea.firstChild.id){
			removeClass(storyArea.firstChild,"IEFirstChild");
			// this next line is redundant, since it is looked after at the end of this function
			// if (storyArea.firstChild.nextSibling) addClass(storyArea.firstChild.nextSibling,"IEFirstChild");
		}
		story.closeTiddlerIEFirstChild(title,animate,slowly);
		if (storyArea.firstChild) addClass(storyArea.firstChild,"IEFirstChild");
	}
}

Story.prototype.displayTiddlerIEFirstChild = Story.prototype.displayTiddler;
Story.prototype.displayTiddler = function(srcElement,tiddler,template,animate,unused,customFields,toggle,animationSrc) {
	var storyArea = document.getElementById(this.container);
	if (storyArea.firstChild) removeClass(storyArea.firstChild,"IEFirstChild");
	story.displayTiddlerIEFirstChild(srcElement,tiddler,template,animate,unused,customFields,toggle,animationSrc);
	addClass(storyArea.firstChild,"IEFirstChild");
}

_GTD.initialize();

//}}}
/***
!GTD specific styles
***/

/*{{{*/
/* how annoying is that big header anyway?! */
.headerForeground, .headerShadow {
 padding-top: 1em;
}

/* the tagging popup really gets in the way so push it off to the side */
.tagging { float: right; }

/* this unbullets actions in the actionList macro */
ul.gtdActionList { list-style-type: none; }
li.gtdActionListProject, li.gtdActionListContext { margin-top: 1.0em; }

.gtdCompletedActionItem { text-decoration: line-through; }
.gtdNextActionItem { border-bottom: 1px solid red; }
.gtdActionWithContent a { font-weight: bold; }
.gtdActionWithoutContent a { font-weight: normal; }

a.actionCrossReference { color: #228B22; }
a.actionCrossReference:hover { color: white; }

/* necessary bits copied from enhanced stylesheet to render properly without it */
#mainMenu {
 font-size: 1em;
 text-align: left;
 width: 12em;
}

#mainMenu * {
 font-size: 1em;
 font-weight: normal;
 padding: 0; margin: 0; border: 0;
}

#mainMenu ul {
 list-style: none;
 margin-bottom: 10px;
}

#mainMenu li {
 text-indent: 1em;
}

#mainMenu li li {
 text-indent: 1.5em;
}

#mainMenu li li li {
 text-indent: 2em;
}

#mainMenu li li li li {
 text-indent: 2.5em;
}

#mainMenu a.button, #mainMenu a.tiddlyLink, #mainMenu a.externalLink {
 display: block; margin: 0;
}

table.review { width: 98%; }
.review tr { vertical-align: top; }

/*}}}*/

/***
!Imported 3x5 printing styles
//adapted from the work of Clint Checketts, http://www.checkettsweb.com/tw/gtd_tiddlywiki.htm //
***/

/*{{{*/

@media print {
#mainMenu, #sidebar, #messageArea {display: none !important;}
#displayArea {margin: 1em 1em 0em 1em;}


/* LAYOUT ELEMENTS ========================================================== */
*
{
 margin: 0;
 padding: 0;
}

#contentWrapper
{
 margin: 0;
 width: 100%;
 position: static;
}

body {
 background: #fff;
 color: #000;
 font-size: 6.2pt;
 font-family: "Lucida Grande", "Bitstream Vera Sans", Helvetica, Verdana, Arial, sans-serif;
 /* we don't want any unnecessary output */
 border: none;
}

img {
 max-width: 2.2in;
 max-height: 4.3in;
}

#header, #side_container, #storeArea, #copyright, #floater, #messageArea, .save_accesskey, .site_description, #saveTest, .toolbar, .header, .footer, .tagging, .tagged
{
 display: none;
}

#tiddlerDisplay, #displayArea
{
 display: inline;
}

.tiddler {
 margin: 0 0 2em 0;
 border: none;
 page-break-before: always;
 font-size: 200%;
 /* IF YOU DO NOT USE INDEX CARDS, USE THIS */
 font-size: 100%;
}

.tiddler:first-child {
 page-break-before: avoid;
}

/* this relies on Clint's IE first-child patch */
.IEFirstChild {
 page-break-before: auto;
}

.title {
 font-size: 1.6em;
 font-weight: bold;
 margin-bottom: .3em;
 padding: .2em 0;
 border-bottom: 1px dotted #000;
}

p, blockquote, ul, li, ol, dt, dd, dl, table
{
 margin: 0 0 .3em 0;
}

h1, h2, h3, h4, h5, h6
{
 margin: .2em 0;
} 

h1
{
 font-size: 1.5em;
}

h2
{
 font-size: 1.3em;
}

h3
{
 font-size: 1.25em;
}

h4
{
 font-size: 1.15em;
}

h5
{
 font-size: 1.1em;
}

blockquote
{
 margin: .6em;
 padding-left: .6em;
 border-left: 1px solid #ccc;
}

ul
{
 list-style-type: circle;
}

li
{
 margin: .1em 0 .1em 2em;
 line-height: 1.4em; 
}

table
{
 border-collapse: collapse;
 font-size: 1em;
}

td, th
{
 border: 1px solid #999;
 padding: .2em;
}

hr {
 border: none;
 border-top: dotted 1px #777;
 height: 1px;
 color: #777;
 margin: .6em 0;
}
}
/*}}}*/

/***
!Imported styles for calendar plugin
***/

/*{{{*/

#mainMenu .calendar {
 width: 100%;
 background-color: transparent !important;
}

#mainMenu .calendar, #mainMenu .calendar tr, #mainMenu .calendar td, #mainMenu .calendar a {
}


/*}}}*/
/***
!Layout Rules /%==============================================%/
***/
/*{{{*/

body {
 /* this is required for proper layout on IE, for some reason... */
 _position: static;
}

.tagClear {
 /* this, too, is a necessary IE hack... */
 _margin-top: 10em; 
 _clear: both;
}

.headerForeground, .headerShadow {
 padding-top: 1em;
}

.tiddler {
 margin: 0 0 0.9em 0;
 padding-bottom: 1em;
}

#mainMenu {
 width: 16em;
 font-size: 1em;
 text-align: left;
 padding-top: 0.5em;
}

#mainMenu * {
 font-size: 1em;
 font-weight: normal;
 padding: 0; margin: 0; border: 0;
}

#mainMenu ul {
 list-style: none;
 margin-bottom: 10px;
}

#mainMenu li {
 text-indent: 1em;
}

#mainMenu a.button, #mainMenu a.tiddlyLink, #mainMenu a.externalLink {
 display: block; margin: 0;
}

#displayArea {
 margin-left: 19em; margin-top: 0;
}

.toolbar .button {
 margin-left: 4px;
}

/*}}}*/

/***
!Generic Rules /%==============================================%/
***/
/*{{{*/
body {
 background: #464646;
 color: #000;
}

h1,h2,h3,h4,h5 {
 color: #000;
 background: #eee;
}

/*}}}*/
/***
!Header /%==================================================%/
***/
/*{{{*/
.header {
 background: #000;
}

.headerForeground {
 color: #cf6;
}

.headerForeground a {
 font-weight: normal;
 color: #cf6;
}

/* ??? what is up when you specify a site title colour in IE ??? */
/* .siteTitle { color: red; } */

/*}}}*/
/***
!General tabs /%=================================================%/
***/
/*{{{*/

.tabSelected {
 color: #fff;
 background: #960;
 border: none;
}

.tabUnselected {
 color: #fff;
 background: #660;
}

.tabContents {
 color: #004;
 background: #960;
 border: none;
}

.tabContents .button, .tabContents a {
 border: none;
 color: #fff;
}

.tabContents a:hover, .tabset a:hover {
 background: #000;
}

/* make nested tab areas look different */
.tabContents .tabSelected, .tabContents .tabContents {
 background: #700;
 color: #fff;
}

.tabContents .tabContents {
 color: #eeb;
}

/*}}}*/
/***
!Main Menu /%=================================================%/
***/
/*{{{*/
#mainMenu {
 background: #700;
 color: #fff;
 border-right: 3px solid #500;
}

#mainMenu * {
 color: #fff;
}

#mainMenu a.button, #mainMenu a.tiddlyLink, #mainMenu a.externalLink {
 border: none;
 border-bottom: 1px solid #500;
 border-top: 1px solid #900;
}

#mainMenu a:hover,
#mainMenu a.button:hover {
 background-color: #b00;
 color: #fff;
}

/*}}}*/
/***
!Sidebar options /%=================================================%/
~TiddlyLinks and buttons are treated identically in the sidebar and slider panel
***/
/*{{{*/
#sidebar {
 color: #000;
 background: #eeb;
 border-right: 3px solid #bb8;
 border-bottom: 3px solid #520;
}

#sidebarOptions .sliderPanel {
 background: #fff;
}

#sidebarOptions .sliderPanel a {
 border: none;
 color: #700;
}

#sidebarOptions .sliderPanel a:hover {
 color: #fff;
 background: #700;
}

#sidebarOptions .sliderPanel a:active {
 color: #700;
 background: #fff;
}

#sidebarOptions a {
 color: #700;
 border: none;
}

#sidebarOptions a:hover, #sidebarOptions a:active {
 color: #fff;
 background: #700;
}

/*}}}*/
/***
!Message Area /%=================================================%/
***/
/*{{{*/
#messageArea {
 border-right: 3px solid #da1;
 border-bottom: 3px solid #a80;
 background: #ffe72f;
 color: #014;
}

/*}}}*/
/***
!Popup /%=================================================%/
***/
/*{{{*/
.popup {
 background: #cf6;
 border: none;
}

.popup hr {
 color: #000;
}

.popup li.disabled {
 color: #666;
 background: #cf6;
}

.popup li a, .popup li a:visited {
 color: #000;
 border: 1px outset #cf6;
 background: #cf6;
}

.popup li a:hover {
 color: #000;
 border: 1px outset #cf6;
 background: #ef9;
}
/*}}}*/
/***
!Tiddler Display /%=================================================%/
***/
/*{{{*/
.tiddler {
 background: #fff;
 border-right: 3px solid #aaa;
 border-bottom: 3px solid #555;
}

.title {
 color: #900;
}

.selected .toolbar a {
 color: #000;
}

.toolbar .button {
 background: #eeb /*#cf6*/;
 border: 1px outset #eeb /*#cf6*/;
}

.selected .toolbar .button:hover {
 background: #700 /*#ef9*/;
 color: #fff;
}

#mainMenu .calendar { border: 1px solid white; }
#mainMenu .calendar, #mainMenu .calendar tr, #mainMenu .calendar td, #mainMenu .calendar a {
}

/*}}}*/

/***
!Additional print overrides for fancy style /%==============================================%/
***/
/*{{{*/

@media print {

.tiddler {
 /* get rid of our fancy tiddler outline */
 border: none;
}

}
/*}}}*/
__Grolog Colloquium of 16 December 2010:__

SPEAKER: John Jules Meyer (UU/ATIA/TNO)

TITLE: ''On the Logic of Delegation: trying to match theory and practice''

TIME: 15:15 - 17:00

PLACE: Room Gamma, Faculty of Philosophy, Oude Boteringestraat 52

ABSTRACT: 

This talk concerns still preliminary, ongoing joint work with
Patrick Doherty (Linkoeping University) on a logical analysis of
delegation. The primary aim is not so much to get technically deep logical
results, but rather trying to match on the one hand a preformal theory of
Falcone & Castelfranchi on delegation with on the other hand the use of
delegation in a real-life application of control of a multi-agent system
of autonomous UAV s. I'll show we can establish a match of a logical
formalization of Falcone & Castelfranchi's notion with a logical
specification of a FIPA compliant implementation of delegation in an
agent-oriented language such as JADE.


--------------


__Grolog Colloquium of 25 November 2010:__

SPEAKERS: Valeriy Surovtsev and Vsevolod Ladov

TIME:

14:00 - 15:00: Valeriy Surovtsev: B. Russell and F.P. Ramsey on Infinity
15:00 - 15:15: discussion
15:30 - 16:45: Vsevolod Ladov: Self-referental propositions, paradoxes, and the theory of types
16:45 - 17:00: discussion

PLACE: VIP Room (5114.0001), Bernouilliborg, Nijenborgh 4,

SPEAKER: Valeriy Surovtsev 

ABSTRACT: ''B. Russell and F.P. Ramsey on Infinity''

The idea of infinity without which the mathematics is impossible, is entered into system of Principia Mathematica (PM) by means of an infinity axiom (IA) which asserts that a class containing n members corresponds to any inductive cardinal n [1]. IA is needed in PM because some features of definition of natural number concept and axiomatization of arithmetic by J. Peano. However there is a question. Is it possible to introduce the idea of infinity on other bases? There are such attempts. Purely analytically the idea of infinity can be introduced on the basis of the definition of the natural number concept offered by G. Frege, or on the basis of G. Cantor's theorem that the number of classes which can be formed from n elements, is more than n. However such attempts are logically unreasonable, as they lead to contradictions (Cantor’s paradox, Russell's paradox etc.) [2]. Another attempts a priori introduction the idea of infinity (Plato, Bolzano), are based on vague concepts or mistaken understanding of the nature of number. The idea of infinity cannot be introduced a posteriori because nothing reality says about its necessity. Hence, the axiom is just necessary.

Russell treats IA as a substantial statement about the world. He accepts it as a hypothesis to prove some important propositions of PM. However such approach conflicts with the logicist program which is developed by Russell. According to logicism, the mathematics is a part of logic, but IA falls outside the limits logic.

Ramsey suggests modifying Russell's approach and treating IA not as the substantial statement, but as the sentence of logic. Thus he uses Wittgenstein's idea that the sentences of logic (tautologies and contradictions) tell nothing about the world, but show the structure of the world [3]. In one of his early manuscripts Ramsey suggests using demonstrative function of tautologies for showing number of things in the partial worlds [4]. That some expressions are tautologies in such world, and another expressions are contradictions will show the number things in the world in this case. He offers corresponding updating of ways of notation for the similar statements accepted in PM. This approach can be extended to the world with infinite number of things. This idea of Ramsey remained unrealized. Later he develops another approach to IА [5]. However first attempt is extremely interesting, as it tries to synthesize Russell’s and Wittgenstein’s understanding of the nature of logic.

References:
1. Whitehead A., Russell B. Principia Mathematica, vol. II (2nd ed., 1927).
2. Russell B. Introduction to Mathematical Philosophy (1919).
3. Wittgenstein L. Tractatus Logico- Philosophicus (1921).
4. Ramsey F.P. The Number of Things in the World, in: Ramsey F.P. Notes on Philosophy, Probability and Mathematics (Bibliopolis, Napoli, 1991).
5. Ramsey F.P. Foundations of Mathematics (1925).


SPEAKER : Vsevolod Ladov

ABSTRACT: '' Self-referental propositions, paradoxes, and the theory of types''

•       B. Russell’s theory of types tried to overcome paradoxes by means of elimination of self-referential propositions (statements). However, there are two problems with the Russell’s strategy.
•       First, the theory of types is contradictory itself. Either its content is universal and it concerns with all types of statements (and in this case affirmation of the theory as an universal principle does not correspond to the main thesis of the theory, namely, that each statement should be applied to some types of statements only) or its content is limited and it concerns with some types of sentences (and in this case we can suppose some statements that do not fall under the main thesis of the theory; in other words, the main thesis of the theory admits the negation of the thesis). (For example, Paul Weiss discussed the theme of inconsistency of the theory of types very carefully: Weiss P., 1928: The Theory of Types. Mind, 37. pp. 338-348).
•       Second, the elimination of self-referential statements has negative influence to development of philosophical theories. (For example, Frederic Fitch says about importance of the idea of self-reference for philosophy: Fitch F.B, 1946: Self-reference in Philosophy. Mind, LV. pp. 64-73).  Philosophy differs from a science in its subject matter. The subject matter of a science is always limited. A science concerns with some segment of the being. Whereas philosophical ontology is a knowledge about all entities in the being. Statements (propositions) are some entities too and ontology should include them to its subject matter. The idea of self-reference points to one of the most important methodological procedure in philosophy, namely, reflection.
•       We can formulate the task of our investigation in following: Is it possible to save the idea of self-reference and self-referential statements in language and at the same time to avoid paradoxes? I suppose that we can give a positive answer the question. My strategy is following.
•       First, I think that B. Russell made a mistake when he asserted in Principia Mathemtica that the general cause of paradoxes consists in self-referential statements. We can point to examples of some self-referential statements that do not lead to paradoxes. Let us imagine that Epimenides says: “All Cretans say truth”. Is this statement true? Yes. Epimenides is Cretan too and he produces the true statement that all Cretan say truth. This self-referential statement is not paradoxical. Indeed, paradoxes arise in self-referential sphere (for example, the paradox “Lair”) but self-referential sphere as such is not a genuine cause of paradoxes. One can say that self-reference is necessary cause but is not sufficient cause for arising of paradoxes.
•       Second, we can attend to the fact that paradoxes arise when there is a negation in self-referential statements. Epimenides (in the case of the paradox “Lair”) says that all Cretans are not say truth. A paradox arises in epistemology when relativist says that any statement is not absolutely true. A negation presents in the paradox that B. Russell formulated in the letter to G. Frege. It was the paradox of class of all classes that are not included themselves. One can suppose that paradoxes arise only in negative self-referential statements. The negative self-referential statement is sufficient cause of paradoxes.
•       Therefore, to save the idea of self-reference for philosophy and, at the same time, to avoid the paradoxes we should put a ban on negative self-referential statements.
•       In ontology and epistemology, for example, we should put a ban on any kind of anti-realistic (relativistic) discourse.  Anti-realism asserts that any statement is not absolutely true, any statement does not say on what there is. Each statement is a cultural convention and says about only this convention. But this statement is contradictory. Anti-realist makes statement “Truth is a cultural convention”. What about this statement itself? Is it a cultural convention too? If it is then this view on the nature of the truth is only particular cultural convention and it does not express the general knowledge on the truth’s nature. If it is not then this view is an absolutely true statement and the affirmation of the statement contradicts to its own content, namely, that the truth is a cultural convention.
•       Realistic position is quite different. Here we can formulate self-referential statements and do not worry concerning contradiction. For example, realistic statement about the nature of affirmation statements in the language will be following: “Each affirmation statement should be made to say on what there is”. This statement is self-referential but is not contradictory. Making the statement realist pretends himself to say on what there is, namely, to say about the nature of affirmation statements in the language in general.
•       I name this position as “formal realism”. The position is formal because it leaves as open difficult questions about ways of our knowledge of objective reality. Formal realism just supposes the opportunity. Nevertheless, I think it is the single mode to save the idea of self-reference in philosophy and to avoid paradoxes of thinking. Formal realism is a different way of overcoming of paradoxes in compare with the theory of types. Formal realism is smoother mode to overcome the paradoxes than the theory of types can be offer.


--------------

__Grolog Colloquium of 27 October 2010:__

SPEAKER: Eric Pacuit (University of Tilburg, NL)
 
DATE: Wednesday 27 October, 2010
 
TIME: 15:15 — 17:00
 
PLACE: Room Omega, Faculty of Philosophy, Oude Boteringestraat 52, 9712 GL Groningen
 
TITLE: ''Strategic Rationality and Responsiveness to Reasons''
  
ABSTRACT:

In this paper we confront various notions of strategic rationality, that
is various choice rules for decision making in interaction, with the
idea that rationality consists, at least partly, in being responsive to
reasons. Our perspective is broadly Humean, and we are concerned with
subjective-normative reasons: facts that the agents believe to hold and,
if they were the case, would to promote the satisfaction of the agents'
desires. From that point of view responsiveness to reasons amounts to
(in)variance under certain changes in the agents' beliefs about the
context of the game. We provide a general classification of well-known
notions of strategic rationality in terms of how much, and to which type
of reasons they are responsive to.  

-----------------------

__Grolog Colloquium of 17 June 2010:__

TWO SPEAKERS:  Hanoch Ben Yami (CEU) and Can Baskent (CUNY)

DATE: 17 June

PLACE: Room Beta, Faculty of Philosophy

TIME: 13:15 - 17:00

TITLE: ''Why Rigidity?''

SPEAKER: Hanoch Ben Yami (Central European University)

ABSTRACT: 

In Naming and Necessity Kripke argues ‘intuitively’ for the
claim that proper names are rigid. Unlike him, I attempt to derive
rigidity, or something close to it, from other facts about our use of
referring expressions and of language more generally, relying on a
principle first formulated by Buridan. I dub the related derived
principle, the priority of reference. I then discuss a difficulty in
accepted formulations of the rigidity claim, stemming from the fact
that the same name can be used to name different particulars. This
difficulty might force us to adopt a weaker or revised form of the
rigidity claim, which is very close to the principle of the priority
of reference; a result that in its turn suggests that it might be best
to consider the related principle as saving what can be saved of the
rigidity claim. Additional facts concerning the behaviour of referring
expressions in modal contexts, unexplained by the rigidity claim but
derivable from the principle of the priority of reference, are
discussed as well, the discussion supporting the same conclusion.
These considerations also lead to a discussion of rigid versus alleged
non-rigid uses of definite descriptions, its conclusion being in
disagreement with Kripke’s position.

SPEAKER: Can Baskent (City University of New York)


TITLE: ''Epistemic Investigations on Nabla Modality''

ABSTRACT: 

Nabla modality $\nabla$ was initially introduced by Larry
Moss for coalgebraic purposes. The significant difference between the
nabla modality and classical modalities is the fact that the nabla
modality takes a set of formulae, possibly empty or infinite, as its
argument. In this work starting with its definition, we take nabla as
our modal operator and consider its epistemic applications.

After making some intuitive observations about nabla modality, we
establish a dynamic epistemic nabla logic and show its completeness
akin to the similar work on dynamic epistemic logics. Then, we apply
the basic ideas about nabla modality to some other epistemic
applications such as epistemic entrenchment, language splitting and
nabla algebras. Our goal is to shed some light on the epistemic
applications of nabla modality and observe how those epistemic systems
would behave in the reconstructed epistemic language. Along the way,
we also make some complexity observations regarding some computational
problems about nabla modality.



-----------------------------------------------------------

__Grolog Colloquium of 10 June 2010:__

SPEAKER: Rohit Parikh (City University of New York)

DATE: Thursday 10 June, 2010

TIME: 15:15 — 17:00

PLACE: Room 5161.0165 in the Bernoulliborg Building on the Zernikecomplex, Nijenborgh 9

TITLE: ''Measuring Belief''

ABSTRACT:

Knowledge is understood as justified true belief, plus something else, as we all know from Gettier. But if belief is an important component of knowledge, then in order to understand knowledge, we need to think more about belief.

Actual beliefs are not closed under logical inference, and they can be inconsistent with each other. Moreover, expressed belief may conflict with observed behavior. All of this was pointed out by Daniel Kahneman in his Nobel lecture. So we need something more refined than Kripke structures to deal with actual belief.

We point out that beliefs can be observed in two ways. One is by simply asking the agent and presuming that one is told the truth. The other way is to observe the choices made by an agent and inferring from these observations both the beliefs and the preferences of the agent.

This second way was pursued, among others, by Ramsey and Savage, and is, indeed the only way we have of assigning beliefs to infants and animals. But we still retain the "vanilla" notion of belief, namely beliefs ascertained by asking questions. Adults of course have both notions of belief and they are often, but not always, correlated with each other.

We will discuss these two ways of understanding belief, compare them to Tamar Gendler's notion of "alief", and also mention the experimental work of Verbrugge and her colleagues.

----------------------------------------------

__Grolog Colloquium of 8 June 2010:__

SPEAKER: Hans van Ditmarsch, University of Sevilla

DATE and TIME: 8 June, 12h30 - 14h

Place: Room 253, Bernoulliborg Building, Faculty of Mathematics and Natural Sciences, RUG

Title: ''The art of lying''

Abstract:

I will present various ways to model lying and bluffing in dynamic epistemic logics, building on prior work and semantics by Alexandru Baltag, Sonja Smets, Barteld Kooi, Jan van Eijck, ... and many other friends. For who remembers the consecutive number riddle that Rineke presented at her inaugural (i.e., everybody): I will treat consecutive numbers with lying, and discuss when it's safe to lie, when not, and when you may or may not get caught.



----------------------------------------------
__Grolog Colloquium of 18 March 2010:__

SPEAKER: Francesca Poggiolesi  (CLWF, Vrije Universiteit Brussel)

DATE: Thursday 18 March 2010

TIME: 15:15 — 17:00

PLACE: Room Gamma, Department of Philosophy, Oude Boteringestraat 52

TITLE: ''Cut-free and Normalised Logic of Proof''

ABSTRACT:

The old question discussed by Godel in 1933/38 concerning the intended provability semantics of the classical modal logic S4 and intuitionistic logic IPC was finally settled by the logic of proof introduced in Artemov (2001). The logic of proof  Lp is a natural extension of classical propositional logic by means of proof-carrying formulas. The operations of proofs in the logic  of proof suffice to recover the explicit provability of modal and intuitionistic logic.
    In the logic of proof  Lp we can prove the deduction theorem, the substitution lemma and the internalisation of proofs. Moreover, Lp can be shown to be sound and complete with respect to Kripke semantics enriched with an evidence function, and introduced by Fitting (2005). 
    There also exists a version of Lp with an intuitionistic base, namely Ilp, introduced
in Artemov (2002). Unsurprisingly, analogous results can be obtained in the logic of proof with an intuitionistic base. In Ilp, we can prove the deduction theorem, the substitution lemma and the internalisation of proofs. Ilp too is sound and complete with respect to the modal logic S4 with an intuitionistic base, and with respect to Heything Arithmetic.
     From a Gentzen-style point of view, we can formulate two simple and similar sequent calculi for the two systems Lp and Ilp, respectively (see Artemov (2002)). Both these calculi are cut-free. Unluckily, none of them enjoys the subformulaproperty. Moreover, their contraction rules are not admissible. Therefore, following Poggiolesi (2010) and Wansing (1998), they are not good sequent calculi. This is a very unpleasant feature for logics that seems to be of such a crucial relevance.
     In this talk, we aim at repairing this situation. We will do it in two steps, and, for reasons that will become clear in the course of the talk, for the only logic Ilp. The two steps are the following. (i) We will introduce the calculus Gilp. We will show that this calculus is cut-free, contraction-free and sound and complete with respect to the corresponding Hilbert system. (ii) We will enrich the language of the logic of proof, and formulate the sequent calculus
Gilp*_ in this new language. We will prove that Gilp*_ is embeddable in Gilp, and vice-versa, and that Gilp*_ is contraction-free, cut-free and it enjoys a sort of normalisation. We will argue that this technique can also be used for the system Lp.

References: 

Artemov, S. (2001). Explicit provability and constructive semantics. Bulletin of Symbolic Logic, 7:1-36.

Artemov, S. (2002). Unied semantics for modality and lambda-terms via proof polynomials.
In Vermeulen, K. and Copestake, A., (eds.), Algebras, Diagrams and Decisions in Language, Logic and Computation, pages 1-35. CSLI, Stanford University.

Fitting, M. (2005). The logic of proofs, semantically. Annals of Pure and Applied Logic, 132:1-25.

Poggiolesi, F. (2010). Gentzen Calculi for Modal Propositional Logic.Trends in Logic Series, Springer, forthcoming.

Wansing, H. (1998). Displaying Modal Logic. Kluwer Ac. Pub., Dordrecht.




------------------------------------------
__Grolog Colloquium of 28 January 2010:__

Speaker: Catarina Dutilh Novaes, ILLC, Universiteit van Amsterdam

Date: Thursday December 17th

Time: 15:15 -- 17:00

Place: Room Beta, Department of Philosophy, Oude Boteringstraat 52

Title: ''Hintikka's `scandal of deduction' and a response from the psychology of reasoning''

Abstract:

In his Logic, language-games and information (1973) Hintikka raises the following question (p.222): if deductive reasoning (and logic in particular) is `tautological' and `analytical', in which sense then (if any) does deductive reasoning give us new information? Hintikka refers to this puzzle as a `scandal of deduction'. In fact, this is a version of the tension between the validity and the usefulness of logic which had already been identified by Mill (1843), and is also often referred to as `the paradox of inference'. "If in an inference the conclusion is not contained in the premises, it cannot be valid; and if the conclusion is not different from the premises, it is useless, but the conclusion cannot be contained in the premises and also possess novelty; hence [deductive] inferences cannot be both valid and useful." (Cohen and Nagel 1934, 173)

Recently, the scandal of deduction has attracted the interest of some logicians and philosophers, who tried to formulate an account of logic and of deductive reasoning where validity and usefulness are allowed to co- exist. Some of these are D'Agostino and Floridi (2009), Sequoiah- Grayson (2008) and Primiero (2008), and each of them has proposed a way to reconcile validity and usefulness (information gain) for deductive reasoning and logic in particular. In my talk, I will outline yet another possible response to the dilemma, one which draws on experimental results from the psychology of reasoning. One of the reasoning mechanisms studied by this tradition is the so-called belief-bias, i.e. our tendency to seek confirmation of previously held beliefs when reasoning. My suggestion will be that deductive reasoning in fact acts as a counterbalance to belief-bias, and that this is one of the reasons why deductive reasoning can be and often is informative after all. The built-in belief-bias suppressing effect of deductive reasoning makes it in fact particularly apt to deliver unexpected conclusions and thus information gain.


--------------------------------------

__Grolog Colloquium of 10 December 2009:__

Speaker: Patrick Girard, University of Auckland (New Zealand)

Date: Thursday December 10th

Time: 15:15 -- 17:00

Place: Room Beta, Department of Philosophy, Oude Boteringstraat 52

Title: ''Reasoning About Social Preferences''

Abstract:

The problem of designing a voting procedure that accurately reflects individual preferences is notoriously hard. Certain plausible assumptions about the fairness of the procedure were shown to be mutually incompatible by the economist Kenneth Arrow, in his influential book Social Choice and Individual Values (1951).  Yet if individuals agree to defer their preferences to others in a systematic way, a fair method of aggregating their preferences is possible.  In fact, a logical calculus for reasoning about group preferences can be developed using the tools of hybrid modal logic. In this talk, I will outline the logic of preference aggregation and discuss it's relation to Arrow's theorem in particular and its role in social choice theory in general. 

--------------------------

__Grolog Colloquium of 19 November 2009:__

Speaker: Eric Pacuit (University of Tilburg, Tilburg Center for Logic and Philosophy of Science)

Title: ''Dynamic Logics of Intention and Belief''

Date: 19 November 2009

Place: Faculty of Philosophy, Room Beta, Oude Boteringestraat 52, Groningen 

Time: 15:15 - 17:00

Abstract: While there is an extensive literature developing logical models to reason about informational attitudes (e.g. belief, knowledge, certainty) in a dynamic environment, other mental states have received relatively less attention. (A notable exception here is work on logics of preferences and preference change.) However, this is changing with recent articles developing a theory of intention revision (see, for example, two recent articles: "Towards a Theory of Intention Revision" by van der Hoek, Jamroga and Wooldridge and "A Logic of Intention and Attempt" by Lorini and Herzig). These papers take as a starting point logical frameworks derived from Cohen and Levesque's seminal paper aimed at formalizing Bratman's planning theory of intention.   In this talk, I will discuss a number of recent dynamic logics of intention and beliefs (including recent work which is joint with Thomas Icard and Yoav Shoham).   In the process we will reexamine a number of foundational issues surrounding so-called BDI - logics.
*'' Thursday 24 February 2011, location Center Groningen''. The meeting will start at 14:00 hrs. Location: Muntinggebouw, Entrance Grote Kruisstraat 2/1, Room M.0074, Groningen (http://bit.ly/ejCuSM). Topic is Logic, Strategies and Games

** [[Program of the seminar on the 24th of February 2011]]

*'' Thursday 24 January 2011, location Center Amsterdam''. The meeting will start at 14:00 hrs. Topic:  Substructural logics, information and interaction

** [[Program of the seminar on the 24th of January 2011]]


*'' Thursday 11 November 2010, location Center Groningen''. The meeting will start at 15:00 hrs. Location: Oude Boteringestraat 52,Groningen. Topic Formal Epistemology 

** [[Program of the seminar on the 11th of November 2010]]

*'' Monday 25 October 2010, location Center Amsterdam'', the topic will be Social Choice. The meeting will start at 14:00 hrs.

** [[Program of the seminar on the 25th of October 2010|http://www.illc.uva.nl/lgc/seminar/]]

*'' Monday 7 December 2010, location Center Amsterdam'', the topic will be Epistemic Protocols. The meeting will start at 14:00 hrs, and will take place in the Nina van Leer room of the Allard Pierson Museum, Amsterdam.

** [[Program of the seminar on the 7th December 2010|http://www.illc.uva.nl/lgc/seminar/?p=534]]

*'' Monday 9 November 2010, location Center Amsterdam'', room 21 of the Maagdenhuis, starts at 2PM. 

** [[Program of the seminar on the 9th of November 2010|http://www.illc.uva.nl/lgc/seminar/?p=408]]

*''Monday 16 November 2010, location Center Groningen'', Harmony Building (Harmonie gebouw) in the faculty of Arts. Room number (13) 15 00 43, Oude Kijk in 't Jatstraat number 26, 9712 EK Groningen. 

** [[Program Dynamic Seminar on the 16th]]

** [[Map of Harmony building complex|http://www.rug.nl/Rechten/voorzieningen/audiovisueledienst/images/college_en_computerzalen_overzicht.jpg]]

** [[Location|http://maps.google.nl/maps?f=q&hl=nl&geocode=&q=oude+kijk+in+'t+jatstraat+26,+groningen&sll=53.218484,6.562679&sspn=0.009341,0.025105&ie=UTF8&ll=53.219049,6.562078&spn=0.00934,0.025105&z=16&iwloc=addr&om=1]]
/***
|Name|InlineJavascriptPlugin|
|Source|http://www.TiddlyTools.com/#InlineJavascriptPlugin|
|Documentation|http://www.TiddlyTools.com/#InlineJavascriptPluginInfo|
|Version|1.9.5|
|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
<<<
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
|please see [[InlineJavascriptPluginInfo]] for additional revision details|
2005.11.08 [1.0.0] initial release
<<<
!!!!!Code
***/
//{{{
version.extensions.InlineJavascriptPlugin= {major: 1, minor: 9, revision: 5, date: new Date(2009,4,11)};

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

	handler: function(w) {
		var lookaheadRegExp = new RegExp(this.lookahead,"mg");
		lookaheadRegExp.lastIndex = w.matchStart;
		var lookaheadMatch = lookaheadRegExp.exec(w.source)
		if(lookaheadMatch && lookaheadMatch.index == w.matchStart) {
			var src=lookaheadMatch[1];
			var label=lookaheadMatch[2];
			var tip=lookaheadMatch[3];
			var key=lookaheadMatch[4];
			var show=lookaheadMatch[5];
			var code=lookaheadMatch[6];
			if (src) { // 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(/^#/,'')); } }
//}}}
To join the grolog mailinglist, [[subscribe here|http://tcw2.ai.rug.nl/mailman/listinfo/grolog]]
/***
|''Name:''|LoadRemoteFileThroughProxy (previous LoadRemoteFileHijack)|
|''Description:''|When the TiddlyWiki file is located on the web (view over http) the content of [[SiteProxy]] tiddler is added in front of the file url. If [[SiteProxy]] does not exist "/proxy/" is added. |
|''Version:''|1.1.0|
|''Date:''|mar 17, 2007|
|''Source:''|http://tiddlywiki.bidix.info/#LoadRemoteFileHijack|
|''Author:''|BidiX (BidiX (at) bidix (dot) info)|
|''License:''|[[BSD open source license|http://tiddlywiki.bidix.info/#%5B%5BBSD%20open%20source%20license%5D%5D ]]|
|''~CoreVersion:''|2.2.0|
***/
//{{{
version.extensions.LoadRemoteFileThroughProxy = {
 major: 1, minor: 1, revision: 0, 
 date: new Date("mar 17, 2007"), 
 source: "http://tiddlywiki.bidix.info/#LoadRemoteFileThroughProxy"};

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

bidix.core.loadRemoteFile = loadRemoteFile;
loadRemoteFile = function(url,callback,params)
{
 if ((document.location.toString().substr(0,4) == "http") && (url.substr(0,4) == "http")){ 
 url = store.getTiddlerText("SiteProxy", "/proxy/") + url;
 }
 return bidix.core.loadRemoteFile(url,callback,params);
}
//}}}
/***
|Name|LoadTiddlersPlugin|
|Source|http://www.TiddlyTools.com/#LoadTiddlersPlugin|
|Documentation|http://www.TiddlyTools.com/#LoadTiddlersPluginInfo|
|Version|3.6.3|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|plugin|
|Requires||
|Overrides||
|Options|##Configuration|
|Description|macro for automated updates or one-click installations of tiddlers from remote sources|
!!!!!Documentation
>see [[LoadTiddlersPluginInfo]]
!!!!!Configuration
<<<
__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
<<<
2008.10.27 [3.6.3] in doImport(), fixed Safari bug by replacing static Array.concat(...) with new Array().concat(...)
|please see [[LoadTiddlersPluginInfo]] for additional revision details|
2005.07.20 [1.0.0] Initial Release
<<<
!!!!!Code
***/
//{{{
version.extensions.LoadTiddlersPlugin= {major: 3, minor: 6, revision: 3, date: new Date(2008,10,27)};

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! Are you sure you want 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 noreport=(params[0]=="noreport"); if (noreport) params.shift();
		this.newTags=[]; if (params[0]) this.newTags=params; // any remaining params are used as "autotags"
		if (label.trim().length) {
			// link triggers load tiddlers from another file/URL and then applies filtering rules to add/replace tiddlers in the store
			createTiddlyButton(place,label.format([src.replace(/%20/g," ")]),tip.format([src.replace(/%20/g," ")]), function() {
				if (src=="ask") src=prompt(this.askMsg);
				config.macros.loadTiddlers.loadFile(src,config.macros.loadTiddlers.doImport,{quiet:quiet,ask:ask,filter:filter,force:force,init:init,noreport:noreport});
			})
		}
		else {
			// load tiddlers from another file/URL and then apply filtering rules to add/replace tiddlers in the store
			if (src=="ask") src=prompt(this.askMsg);
			config.macros.loadTiddlers.loadFile(src,config.macros.loadTiddlers.doImport,{quiet:quiet,ask:ask,filter:filter,force:force,init:init,noreport:noreport});
		}
	},
	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.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
				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 (callback) callback(true,params,convertUTF8ToUnicode(txt),src,null);
			}
		} else {
			var name=config.options.txtRemoteUsername; var pass=config.options.txtRemotePassword;
			var x=doHttp("GET",src,null,null,name,pass,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");	
		}
	},
	doImport: function(status,params,html,src,xhr) {
		var quiet=params.quiet;
		var ask=params.ask;
		var filter=params.filter;
		var force=params.force;
		var init=params.init;
		var noreport=params.noreport;
		var tiddlers = config.macros.loadTiddlers.readTiddlersFromHTML(html);
		var count=tiddlers?tiddlers.length:0;
		var querypos=src.lastIndexOf("?"); if (querypos!=-1) src=src.substr(0,querypos);
		if (!quiet) displayMessage(config.macros.loadTiddlers.foundMsg.format([count,src.replace(/%20/g," ")]));
		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==config.macros.loadTiddlers.reportTitle)
				continue; // skip "ImportedTiddlers" history from the other document...
			if (theExisting && theExisting.tags.contains(config.macros.loadTiddlers.lockedTag)) {
				if (!quiet) displayMessage(config.macros.loadTiddlers.lockedMsg.format([theExisting.title,config.macros.loadTiddlers.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=config.macros.loadTiddlers.nochangeMsg;
					if (!quiet&&msg.length) displayMessage(msg.format([inbound.title]));
					continue;
				}
			}
			// get confirmation if required
			if (ask && !confirm((theExisting?"Update":"Add")+" tiddler '"+inbound.title+"'\nfrom "+src.replace(/%20/g," ")+"\n\nOK to proceed?"))
				{ tiddlers[t].status=config.macros.loadTiddlers.skippedMsg; continue; }
			// DO IT!
			var tags=new Array().concat(inbound.tags,config.macros.loadTiddlers.newTags);
	                store.saveTiddler(inbound.title, inbound.title, inbound.text, inbound.modifier, inbound.modified, tags, inbound.fields, true, inbound.created);
	                store.fetchTiddler(inbound.title).created = inbound.created; // force creation date to imported value - needed for TW2.1.3 or earlier
			tiddlers[t].status=theExisting?"updated":"added"
			if (init && tags.contains("systemConfig") && !tags.contains("systemConfigDisable")) {
				var ok=true;
				if (ask||!quiet) ok=confirm(config.macros.loadTiddlers.warning.format([inbound.title]))
				if (ok) { // run the plugin
					try { window.eval(inbound); tiddlers[t].status+=" (plugin initialized)"; }
					catch(ex) { displayMessage(config.messages.pluginError.format([exceptionText(ex)])); }
				}
			}
			count++;
		}
		store.resumeNotifications();
		if (count) {
			// refresh display
			store.setDirty(true); store.notifyAll();
			// generate a report
			if (!noreport) config.macros.loadTiddlers.report(src,tiddlers,count,quiet);
		}
		// always show final message when tiddlers were actually loaded
		if (!quiet||count) displayMessage(config.macros.loadTiddlers.loadedMsg.format([count,tiddlers.length,src.replace(/%20/g," ")]));
	},
	report: function(src,tiddlers,count,quiet) {
		// 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";
		// get current report (if any)
		var title=config.macros.loadTiddlers.reportTitle;
		var currText="";
		var theReport = store.getTiddler(title);
		if (theReport) currText=((theReport.text!="")?'\n----\n':"")+theReport.text;
		// update the ImportedTiddlers content and show the tiddler
		store.saveTiddler(title, title, newText+currText, config.options.txtUserName, new Date(), theReport?theReport.tags:null, theReport?theReport.fields:null);
		if (!quiet) { story.displayTiddler(null,title,1,null,null,false); story.refreshTiddler(title,1,true); }
	}
}
//}}}
/***
|Name|LoadTiddlersPluginInfo|
|Source|http://www.TiddlyTools.com/#LoadTiddlersPlugin|
|Documentation|http://www.TiddlyTools.com/#LoadTiddlersPluginInfo|
|Version|3.6.3|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|documentation|
|Requires||
|Overrides||
|Description|documentation for LoadTiddlersPlugin|
!!!!!Usage
<<<
Syntax:
{{{<<loadTiddlers label:text prompt:text filter source quiet confirm force init noreport tag tag tag...>>}}}

Example:
{{{<<loadTiddlers "label:load tiddlers from %0" example.html confirm temporary>>}}}
<<loadTiddlers "label:load tiddlers from %0" example.html confirm temporary>>

Where:
''"""label:text"""'' and ''"""prompt:text"""''
>defines link text and tooltip (prompt) that can be clicked 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) determines which tiddlers will be automatically selected for importing.  Use one of the following keywords:
>''"all"'' retrieves ALL tiddlers from the import source document, even if they have not been changed.
>''"new"'' retrieves only tiddlers that are found in the import source document, but do not yet exist in the destination document
>''"changes"'' retrieves only tiddlers that exist in both documents for which the import source tiddler is newer than the existing tiddler
>''"updates"'' retrieves both ''new'' and ''changed'' tiddlers (this is the default action when none is specified)
>''""""tiddler:TiddlerName""""'' retrieves only the specific tiddler named in the parameter.
>''""""tag:text""""'' retrieves only the tiddlers tagged with the indicated text.
>> Note: ''if an existing tiddler is tagged with '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.
''source'' (required) 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 keyword ''ask'' to prompt for a source location whenever the macro is invoked
''"quiet"'' (optional)
>supresses all status message during the import processing (e.g., "opening local file...", "found NN tiddlers..." etc).  Note that if ANY tiddlers are actualy imported, a final information message will still be displayed (along with the ImportedTiddlers report), even when 'quiet' is specified.  This ensures that changes to your document cannot occur without any visible indication at all.
''"confirm"'' (optional)
>adds interactive confirmation.  A browser message box (OK/Cancel) is displayed for each tiddler that will be imported, so that you can manually bypass any tiddlers that you do not want to import.
''"init"'' (optional)
>invoke tiddlers tagged with <<tag systemConfig>> as plugins as soon as they are imported, without requiring a save-and-reload action first.  For safety, a browser message box (OK/Cancel) is displayed for each imported plugin, so that you can manually bypass any plugins that you do not want to invoke.  Note, however, that those tiddlers are still //imported// into your document and therefore will still take effect the next time you save-and-reload the document.
''"force"'' (optional)
>import all matching tiddlers, even if unchanged
''"noreport"'' (optional)
>suppress generation of [[ImportedTiddlers]] report
''"tag tag tag..."'' (optional)
>any remaining parameters are used as tag values to be added to each imported tiddler (i.e., "tag-on-import")
<<<
!!!!!Configuration
<<<
__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
<<<
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).  Fixes error caused when ImportTiddlersPlugin has NOT been installed along side this plugin.
2007.03.26 [3.4.2] renamed import() to doImport() to fix IE load-time error ("identifier expected").  This may also cause a problem with FF1.5.0.x.... Apparently, "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 functionality into separate plugins
|please see [[ImportTiddlersPluginInfo]] for additional revision details|
2005.07.20 [1.0.0] Initial Release
<<<
<<tiddler GTDMenu>>
/***
|Name|NestedSlidersPlugin|
|Source|http://www.TiddlyTools.com/#NestedSlidersPlugin|
|Documentation|http://www.TiddlyTools.com/#NestedSlidersPluginInfo|
|Version|2.4.5|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|plugin|
|Requires||
|Overrides||
|Options|##Configuration|
|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.06.07 - 2.4.5 in 'onmouseover' handler for 'open on hover' slider buttons,<br>use call() method when invoking document.onclick function (avoids error in IE)
|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.nestedSliders = {major: 2, minor: 4, revision: 5, date: new Date(2008,6,7)};

// 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");

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";

	// 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")
				{ ctrls[c].focus(); break; }
		}
	}
	var cookie=theTarget.sliderCookie;
	if (cookie && cookie.length) {
		config.options[cookie]=!isOpen;
		if (config.options[cookie]!=theTarget.defOpen)
			saveOptionCookie(cookie);
		else { // remove cookie if slider is in default display state
			var ex=new Date(); ex.setTime(ex.getTime()-1000);
			document.cookie = cookie+"=novalue; path=/; expires="+ex.toGMTString();
		}
	}

	// 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}) 
	}
	return retval;
};
//}}}
//{{{
// adjust floating panel position based on button position
if (window.adjustSliderPos==undefined) window.adjustSliderPos=function(place,btn,panel) {
	if (hasClass(panel,"floatingPanel")) {
		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);
		}
	};
}
//}}}
[[ViewTemplate]]

[[DefaultTiddlers]]


<<gtdActionList>>
<<gtdActionList>>
The outcome for this project is 
<<gtdAction "New Action 19:07:20" "unfiled">>
The outcome for this project is 
|''URL:''|http://dcubed.ca/d3-update-13.html|
|''Description:''|Official d-cubed feed|
|''Author:''|Tom Otvos|
<div class='header' macro='gradient vert #000 #464646'>
<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' force='true'></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>
/***
|''Name:''|PasswordOptionPlugin|
|''Description:''|Extends TiddlyWiki options with non encrypted password option.|
|''Version:''|1.0.2|
|''Date:''|Apr 19, 2007|
|''Source:''|http://tiddlywiki.bidix.info/#PasswordOptionPlugin|
|''Author:''|BidiX (BidiX (at) bidix (dot) info)|
|''License:''|[[BSD open source license|http://tiddlywiki.bidix.info/#%5B%5BBSD%20open%20source%20license%5D%5D ]]|
|''~CoreVersion:''|2.2.0 (Beta 5)|
***/
//{{{
version.extensions.PasswordOptionPlugin = {
	major: 1, minor: 0, revision: 2, 
	date: new Date("Apr 19, 2007"),
	source: 'http://tiddlywiki.bidix.info/#PasswordOptionPlugin',
	author: 'BidiX (BidiX (at) bidix (dot) info',
	license: '[[BSD open source license|http://tiddlywiki.bidix.info/#%5B%5BBSD%20open%20source%20license%5D%5D]]',
	coreVersion: '2.2.0 (Beta 5)'
};

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

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

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

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

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

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

merge(config.optionsDesc,{
		pasPassword: "Test password"
	});
*/
//}}}
Grolog Organization:

- [[Barteld Kooi|http://www.philos.rug.nl/~barteld/]]
- [[Sonja Smets|http://www.rug.nl/staff/S.J.L.Smets/index]]
- [[Allard Tamminga|http://www.rug.nl/staff/a.m.tamminga/index]]

Groningen - Amsterdam Dynamic Seminar 

''Program on Monday 16 November:''

* 14:00 - 14:35   Jeremy Meyers (Stanford University) : ''Hybrid Ontology'' 
** 14:35 - 14:50 Discussion
** 14:50 - 15:00 Coffee break
* 15:00 - 15:35   Alexandru Baltag (Oxford University) : ''SURPRISE!? An Answer to the Hangman, or How to Avoid Unexpected Exams''
** 15:35 - 15:50 Discussion
** 15:50 - 16:00 Coffee break
* 16:00 - 16:35  Allard Tamminga (University of Groningen): ''Conditional permissions and Nash equilibria''
** 16:35 - 16:50 Discussion
** 17:00 - Drinks in our favorite Pub

-------------------------------------------------

''THE ABSTRACTS:''

* Jeremy Meyers (Stanford University) : ''Hybrid Ontology'':

In this talk we consider logics based on K_{hmo}, the logic of hybrid ontology in the hybrid tense language with existence, atom, and inverse modalities. Even though it is weaker than the first order language, it has sufficient expressive power to define all the major systems of mereology - indeed, up to zero-deleted boolean algebras or "decompositions". In this lattice-up style approach, general completeness results holds for atomic, atomless, mixture, and complete cases with the addition of axioms defining those frame classes. Several concrete completeness results are easy in this system.

Next, we consider the pure fragment, K_{hmg}. I argue that this system represents a fundamental type of calculus for individuals, being devoid of any set-abstraction device and incapable of axiomatizations of irreducible second order frame conditions. Nonetheless, it is incredibly powerful; the logic is complete with respect to any regular open decomposition (i.e. regular open boolean algebra minus 0) of any finite dimension of R. We briefly consider concrete completeness results over atomic decompositions. We muse over the possibility, and perhaps desire for, more expressive systems: explicit temporal extensions, mereotopologies/topomereologies, and Kit Fine's (2006) idea of a reality operator <R>.

In conclusion I make two claims: (1) I argue that the modal formalism is an important requirement for any formal ontology, and (2) that mereology is fundamental for understanding the semantics of modal discourse. 

* Alexandru Baltag (Oxford University) : ''SURPRISE!? An Answer to the Hangman, or How to Avoid Unexpected Exams'':

The "Hangman" puzzle, in its ``Unexpected Examination" version,  involves a Teacher announcing her students that the exam's date (known only to be sometimes next week) will be a surprise: even in the evening before the exam, the students will still not be sure that the exam is tomorrow. Intuitively, one can prove (by backward induction, starting with Friday) that, if this announcement is true, then the exam cannot take place in any day of the week. So, using this argument, the students come to ``know" that the announcement is false: the exam cannot be a surprise. Given this, they dismiss the announcement, and... then, whenever the exam will come (say, on Tuesday) it will indeed be a complete surprise!

Jelle Gerbrandy proposed a nice solution to the puzzle, using the logic of public announcements. His answer is based on interpreting the expression ``it will be a surprise" as: ``before the Teacher's announcement, it was the case that (if the Teacher didn't make the announcement, then) the exam's date would have been a surprise". Gerbrandy interprets the announcement itself as an ``update" (conveying ``hard" information) with the above sentence. In this reading, the students' correct conclusion should be only that (if the Teacher tells the truth, then) the exam won't take place on Friday; but none of the previous days can be excluded.

I propose a different solution, which in my view better captures the intended meaning of Teacher's announcement, namely: ``The exam's date will be a surprise, even after I'm telling you this!" Assuming that students trust their Teacher, I show that the belief revision  induced by this self-referential announcement cannot be an ``update", but only an ``upgrade" with ``soft" information; i.e. the teacher is a trusted, but not infallible, source of information, and thus the students believe (though they do NOT know) that her announcements are true UNLESS they are already known to be false. I prove that in fact there exists only one possible doxastic transformation that models this announcement. Its effect is to make the content of the announcement known to be false, although the announcement itself (as a belief-revising action) is still ``efficacious" (and thus it cannot be dismissed).

I show this first by using a combination of Temporal Logic and Conditional Doxastic Logic. But then I go back to (the belief-revision-friendly version of) Dynamic Epistemic Logic, and show that the effect of the announcement is equivalent to the students' revising their beliefs with the sentence ``surprise", then revising again with the same sentence, then again... ad infinitum. This ``iterated upgrade" perspective relates the Surprise Exam puzzle to the theory of fixed points of doxastic upgrades. Finally, I also give a Probabilistic analysis of the puzzle, using (infinite iterations of) Jeffrey's Rule. 

All the three proposed approaches come essentially to the same conclusion: if the students start by trusting the Teacher, then after the announcement they should come to regard as more plausible (or more probable) that the exam will take place in any particular day than that it will take place in the next day. As a result, every evening the students will believe the exam is tomorrow. So, whenever the exam comes, it won't be a surprise! Thus, the Teacher's announcement comes to be known to be false, but this doesn't entitle the students to dismiss it. On the contrary, the only way for them to ``prove" the teacher wrong is to be prepared for the exam at any given moment! I find it very pleasant that this solution agrees with (what should be every) Teacher's true intentions: what more can she expect to achieve with this announcement?

* Allard Tamminga (University of Groningen): ''Conditional permissions and Nash equilibria'':

We develop a multi-agent deontic logic to study the logical behaviour of two types of permissions: (1) absolute permissions, having the form “Group G best furthers group F’s interest by performing action aG” and (2) conditional permissions, having the form “If group H were to perform action aH, then group G would best further group F’s interest by performing action aG”. First, we define a formal language for multi-agent deontic logic and a class of consequentialist models to interpret the formulas of the language. Second, we define a transformation that converts any strategic game into a consequentialist model. Third, we show that an outcome a¤ is a Nash equilibrium of a strategic game if and only if a conjunction of certain conditional permissions is true in the consequentialist model that results from the transformation of that strategic game.
LIRA seminar session on Formal Epistemology:

Date: Thursday, November 11, 3-6 p.m.

Location: Philosophy Department, Oude Boteringestraat 44, Room Alfa

SPEAKERS: David Etlin (Groningen), Wes Holliday (Stanford), Olivier Roy (Groningen)

''Program and abstracts''


15:00 – 15:35 Wes Holliday (Stanford): Epistemic Closure and Epistemic Logic

One of the central debates in epistemology in recent decades concerns epistemic closure principles, such as the closure of knowledge under known implication (the K axiom). In this talk, I will introduce epistemic-logical models of three influential theories of knowledge according to which various epistemic closure principles do not hold: the relevant alternatives (RA) theory, the tracking theory, and the safety theory of knowledge. The main result is a complete characterization of the epistemic closure principles that hold according to these formalized theories. Analysis of this result shows that two parameters of an epistemological theory affect whether closure fails according to the theory. Finally, extending the formal framework in the style of dynamic epistemic logic, I relate failures of closure in a fixed context to failures of closure across context changes, as suggested by contextualist versions of the RA and tracking theories.


15:35 – 15:50 Questions and Discussion

15:50 - 16:00  Coffee break

16:00 – 16:35 David Etlin (Groningen): Modals, Conditionals and Supposition (provisional title)

Abstract: TBA

16:35 – 16:50 Questions and Discussion

16:50 – 17:00 Coffee break

17:00 – 17:35 Olivier Roy (Groningen): Strategic Rationality and Responsiveness to Reasons

In this paper we confront various notions of strategic rationality, that
is various choice rules for decision making in interaction, with the
idea that rationality consists, at least partly, in being responsive to
reasons. Our perspective is broadly Humean, and we are concerned with
subjective-normative reasons: facts that the agents believe to hold and,
if they were the case, would promote the satisfaction of the agents'
desires. From that point of view responsiveness to reasons amounts to
(in)variance under certain changes in the agents' beliefs about the
context of the game. We provide a general classification of well-known
notions of strategic rationality in terms of how much, and to which type
of reasons they are responsive to. 

NOTE: this is a *different* talk from the one Eric Pacuit recently gave at the GROLOG colloquium.

17:35 - 17:50 Questions and Discussion

17:50 – 18:00 General Discussion
* LIRA: The Groningen - Amsterdam Exchange Dynamic Seminar 

''Program on February 24 February 2011:''

14:00 -- 14: 40

Paolo Turrini (Utrecht): Strategic Games and Truly Playable Effectivity Functions

Abstract: A well known result by Marc Pauly states that for every playable effectivity function E there exists a strategic game that assigns to coalitions exactly the same power as E, and vice versa. While the latter direction of the correspondence is correct, I will show that the former is not. I will discuss the consequences of this problem, especially for the logics used to reason on strategic games. I will then characterize the class of 'truly playable' effectivity functions, that does correspond to strategic games. I will also show that Coalition Logic is not expressive enough to distinguish between playable and truly playable effectivity functions, and I will extend it to a logic that can make this distinction while enjoying finite axiomatization and finite model property. What I present is joint work with Valentin Goranko (University of Denmark) and Wojtek Jamroga (University of Luxembourg).


14:40 -- 14:50 Discussion

14:50 -- 15:00 Coffee break

15:00 -- 15:40

Sunil Simon (Amsterdam): From logic to games and back

Abstract: Model checking games present one of the classic applications of game theoretic techniques in logic. In this view, the notion of truth can be stated in terms of winning strategies. Efficient algorithms to find the winning region in the associated class of games can in turn be employed to solve the model checking question. There is also the reverse relationship between games and logic: the question of whether the winning region (and the winning strategy) of a class of games is definable in a logic.

It is well known that the class of perfect information games with omega regular objectives encompass model checking games of several interesting logics including modal logic, first order logic and its fixed point extensions. It is well behaved in terms of computational and logical definability questions and also robust in the sense that these properties remain invariant under natural extensions. However, moving to the class of imperfect information games, most of the nice algorithmic and definability properties break down. We look at a natural subclass of imperfect information games for which the computational questions remain tractable.

15:40 -- 15:50 Discussion

15:50 -- 16:00 Coffee break

16:00 -- 16:40

Rineke Verbrugge (Groningen): Reasoning strategies: Logical and cognitive views

Abstract: This talk presents an attempt to bridge the gap between logical and cognitive treatments of strategic reasoning in games. The focus is backward induction, a principle which is purported to follow from common knowledge of rationality by Zermelo’s theorem. There have been extensive formal debates about the merits of the principle of backward induction among game theorists and logicians. Experimental economists and psychologists have shown that human subjects, perhaps due to their bounded resources, do not always follow the backward induction strategy, leading to unexpected outcomes. Recently, based on an eye-tracker study by Ben Meijering, it has turned out that even human subjects who produce the outwardly correct ‘backward induction answer’ may use a different internal reasoning strategy to achieve it. This paper presents a formal language to represent different strategies on a finer-grained level than was possible before. The language and its semantics may lead to precisely distinguishing different cognitive reasoning strategies, that can then be tested on the basis of computational cognitive models and experiments with human subjects. This talk is based on work with Ben Meijering and Sujata Ghosh.

16:40 -- 16:50 Discussion
16:50 -- 17:00 General Discussion
''LIRA: Special session of the Seminar on Logic and Interactive Rationality'' 

Special Topic: Substructural logics, information and interaction

SPEAKERS: Daniele Porello (Amsterdam), Sebastian Sequoiah - Grayson (Groningen), Michael Moortgat (Utrecht)

DATE and TIME: Monday 24 January, 14-17 hrs

LOCATION: Oude Manhuispoort 4-6, Room C0.23, Amsterdam
(Map: http://rooster.uva.nl/conceptrooster2010nl/showtimetable.aspx?type=reporturl&idstring=110CC023)

PROGRAM AND ABSTRACTS:

15:00 – 15:40 Daniele Porello (ILLC)

''Modeling Resource Allocation in Linear Logic''

In the last decades, resource allocations problems have been widely investigated also from a computational point of view both in the AI and the logic community. In this presentation, I will show how substructural logics, and linear logic in particular, provide a principled modeling of resources allocation problems, which can be classified according to the types of goods agents trade. I will present a classification of resource allocation problems with the corresponding logical language to encode preferences and we will see how dropping contraction, weakening or exchange affects the type of goods on which agents express their valuations. It is interesting to stress that, in this framework, the process of allocating goods to agents can be modeled by the notion of proof in some suitable fragments of linear logic. This presentation is based on two joint works with Ulle Endriss (KR 2010 and ECAI 2010).

14:40 – 14:50 Questions and Discussion
14:50 – 14:00 Coffee Break
15:00 – 15:40 Sebastian Sequoiah - Grayson (Groningen)

''Modeling Epistemic Actions''

Epistemic actions such as acts of deductive reasoning, communication, and observation, saturate our rational lives. Such actions play the epistemically crucial roles that they do due to the fact that we lack certain fantastic epistemic abilities – logical omniscience, clairvoyance, and omniscience respectively. We will see how it is that that the limits of such actions correspond to various subsystem thresholds of the database corresponding to the total universe of information. The dynamic properties of the actions that facilitate such convergence are modeled by various substructural logics. In detail, we will see how it is that the dynamic properties of deductive information processing are modeled by the operational semantic frames corresponding to the categorical grammar marked by mobiles; bracket-sensitive commuting structures.

Keywords: epistemic actions, information, omniscience, operational semantics, categorical grammar.

15:40 – 15:50 Questions and Discussion
15:50 – 16:00 Coffee break
16:00 – 16:40 Michael Moortgat (Utrecht)

''Syntax and Semantics in Generalized Lambek Calculus''

The syntactic calculus, as proposed by Lambek in 1961, is a logic completely without structural rules: rules affecting multiplicity (contraction, weakening) or structure (commutativity, associativity) of the grammatical resources are not considered. Originally conceived with linguistics in mind, Lambek’s calculus (both the ’61 and the associative ’58 variant or its modern pregroup incarnation) have found many models outside linguistics: as the logic for composition of informational actions, for example, and in fields such as mathematical morphology or quantum physics. In terms of expressivity, Lambek’s calculi are strictly context-free. The context-free limitation makes itself felt in situations where syntactic and semantic composition seem to be out of sync: long distance dependencies in syntax, or the dynamics of scoping in semantics. Competing frameworks in the ‘mildly context-sensitive’ family (TAG, MG, MCFG, etc) handle such phenomena gracefully. In the talk, I discuss the Lambek Grishin calculus, a symmetric generalization of the syntactic calculus allowing multiple conclusions. I focus on two features that help resolve tensions at the syntax-semantics interface:
- A continuation-passing-style interpretation, making contexts an explicit part of the composition process. As a result of the richer view on the mapping between syntax and semantics, the syntactic source calculus itself can be kept very simple.
- Distributivity principles relating Lambek’s original type-forming operations and their duals. These principles characterize syntactic deformations under which interpretations are stable. They allow a quite natural treatment of patterns beyond CF.

Background reading
Moortgat 2009, Symmetric categorial grammar. J Philosophical Logic 38 (6):681-710.

16:40 – 16:50 Questions and Discussion
16:50 – 17:00 General Discussion
! Active projects with remaining actions
<<gtdActionList *>>
! Projects with no open actions
<<list tagged "project done -someday">>
*+++(gtdImportantProjectsSliderState)[Important:] <<list tagged "project important -someday" all>>===
+++(gtdOtherProjectsSliderState)[Other:] <<list tagged "project -syntora -important -someday" all>>===
<<list tagged txtGTDReferenceContext any>>
/***
|''Name:''|ReminderPlugin|
|''Version:''|2.3.8.3 (Nov 28, 2006)|
|''Source:''|http://www.geocities.com/allredfaq/reminderMacros.html|
|''Author:''|Jeremy Sheeley(pop1280 [at] excite [dot] com)|
|''Modified by:''|Tom Otvos|
|''Licence:''|[[BSD open source license]]|
|''Macros:''|reminder, showreminders, displayTiddlersWithReminders, newReminder|
|''TiddlyWiki:''|2.0+|
|''Browser:''|Firefox 1.0.4+; InternetExplorer 6.0|

!Description
This plugin provides macros for tagging a date with a reminder.  Use the {{{reminder}}} macro to do this.  The {{{showReminders}}} and {{{displayTiddlersWithReminder}}} macros automatically search through all available tiddlers looking for upcoming reminders.

''This version contains a fix by Tom Otvos that modifies tag filtering when tiddlers contain no tags. In this version, if you are filtering showReminders by tag, and a tiddler has no tags, the filter will //not// match the tiddler. There are also a number of small UI-related changes to make the reminder interface a bit nicer. Do not copy this into your own TW documents unless you accept these changes.''

!Installation
* Create a new tiddler in your tiddlywiki titled ReminderPlugin and give it the {{{systemConfig}}} tag.  The tag is important because it tells TW that this is executable code.
* Double click this tiddler, and copy all the text from the tiddler's body.
* Paste the text into the body of the new tiddler in your TW.
* Save and reload your TW.
* You can copy some examples into your TW as well.  See [[Simple examples]], [[Holidays]], [[showReminders]] and [[Personal Reminders]]

!Syntax:
|>|See [[ReminderSyntax]] and [[showRemindersSyntax]]|

!Revision history
* v2.3.8 (Mar 9, 2006)
**Bug fix: A global variable had snuck in, which was killing FF 1.5.0.1
**Feature: You can now use TIDDLER and TIDDLERNAME in a regular reminder format
* v2.3.6 (Mar 1, 2006)
**Bug fix: Reminders for today weren't being matched sometimes.
**Feature:  Solidified integration with DatePlugin and CalendarPlugin
**Feature:  Recurring reminders will now return multiple hits in showReminders and the calendar.
**Feature:  Added TIDDLERNAME to the replacements for showReminders format, for plugins that need the title without brackets.
* v2.3.5 (Feb 8, 2006)
**Bug fix: Sped up reminders lots.  Added a caching mechanism for reminders that have already been matched.
* v2.3.4 (Feb 7, 2006)
**Bug fix: Cleaned up code to hopefully prevent the Firefox 1.5.0.1 crash that was causing lots of plugins 
to crash Firefox.  Thanks to http://www.jslint.com
* v2.3.3 (Feb 2, 2006)
**Feature: newReminder now has drop down lists instead of text boxes.
**Bug fix:  A trailing space in a title would trigger an infinite loop.
**Bug fix:  using tag:"birthday !reminder" would filter differently than tag:"!reminder birthday"
* v2.3.2 (Jan 21, 2006)
**Feature: newReminder macro, which will let you easily add a reminder to a tiddler. Thanks to Eric Shulman (http://www.elsdesign.com) for the code to do this.
** Bug fix: offsetday was not working sometimes
** Bug fix: when upgrading to 2.0, I included a bit to exclude tiddlers tagged with excludeSearch.  I've reverted back to searching through all tiddlers
* v2.3.1 (Jan 7, 2006)
**Feature: 2.0 compatibility
**Feature AlanH sent some code to make sure that showReminders prints a message if no reminders are found.
* v2.3.0 (Jan 3, 2006)
** Bug Fix:  Using "Last Sunday (-0)" as a offsetdayofweek wasn't working.
** Bug Fix:  Daylight Savings time broke offset based reminders (for example year:2005 month:8 day:23 recurdays:7 would match Monday instead of Tuesday during DST.

!Code
***/
//{{{

//============================================================================
//============================================================================
//           ReminderPlugin
//============================================================================
//============================================================================

version.extensions.ReminderPlugin = {major: 2, minor: 3, revision: 8, date: new Date(2006,3,9), source: "http://www.geocities.com/allredfaq/reminderMacros.html"};

//============================================================================
// Configuration
// Modify this section to change the defaults for 
// leadtime and display strings
//============================================================================

config.macros.reminders = {};
config.macros["reminder"] = {};
config.macros["newReminder"] = {};
config.macros["showReminders"] = {};
config.macros["displayTiddlersWithReminders"] = {};

config.macros.reminders["defaultLeadTime"] = [0,365];
config.macros.reminders["defaultReminderMessage"] = "DIFF: TITLE on DATE ANNIVERSARY";
config.macros.reminders["defaultShowReminderMessage"] = "DIFF: TITLE on DATE ANNIVERSARY -- TIDDLER";
config.macros.reminders["defaultAnniversaryMessage"] = "(DIFF)";
config.macros.reminders["untitledReminder"] = "Untitled Reminder";
config.macros.reminders["noReminderFound"] = "Couldn't find a match for TITLE in the next LEADTIMEUPPER days."
config.macros.reminders["todayString"] = "Today";
config.macros.reminders["tomorrowString"] = "Tomorrow";
config.macros.reminders["ndaysString"] = "DIFF days";
config.macros.reminders["emtpyShowRemindersString"] = "There are no upcoming events";


//============================================================================
//  Code
// You should not need to edit anything 
// below this.  Make sure to edit this tiddler and copy 
// the code from the text box, to make sure that 
// tiddler rendering doesn't interfere with the copy 
// and paste.
//============================================================================

// This line is to preserve 1.2 compatibility
// if (!story) var story=window; 
//this object will hold the cache of reminders, so that we don't
//recompute the same reminder over again.
var reminderCache = {};

config.macros.showReminders.handler = function showReminders(place,macroName,params)
{
   var now = new Date().getMidnight();
   var paramHash = {};
   var leadtime = [0,14];
   paramHash = getParamsForReminder(params);
   var bProvidedDate = (paramHash["year"] != null) || 
			(paramHash["month"] != null) || 
			(paramHash["day"] != null) || 
			(paramHash["dayofweek"] != null);
   if (paramHash["leadtime"] != null)
   {
      leadtime = paramHash["leadtime"];
      if (bProvidedDate)
      {
         //If they've entered a day, we need to make 
         //sure to find it.  We'll reset the 
         //leadtime a few lines down.
         paramHash["leadtime"] = [-10000, 10000];
      }
   }
   var matchedDate = now;
   if (bProvidedDate)
   {
      var leadTimeLowerBound = new Date().getMidnight().addDays(paramHash["leadtime"][0]);
      var leadTimeUpperBound = new Date().getMidnight().addDays(paramHash["leadtime"][1]);
      matchedDate = findDateForReminder(paramHash, new Date().getMidnight(), leadTimeLowerBound, leadTimeUpperBound); 
   }

   var arr = findTiddlersWithReminders(matchedDate, leadtime, paramHash["tag"], paramHash["limit"]);
   var elem = createTiddlyElement(place,"span",null,null, null);
   var mess = "";
   if (arr.length == 0)
   {
      mess += config.macros.reminders.emtpyShowRemindersString; 
   }
   for (var j = 0; j < arr.length; j++)
   {
      if (paramHash["format"] != null)
      {
         arr[j]["params"]["format"] = paramHash["format"];
      }
      else
      {
         arr[j]["params"]["format"] = config.macros.reminders["defaultShowReminderMessage"];
      }
      mess += getReminderMessageForDisplay(arr[j]["diff"], arr[j]["params"], arr[j]["matchedDate"], arr[j]["tiddler"]);
      mess += "\n";
   }
   wikify(mess, elem, null, null);
};


config.macros.displayTiddlersWithReminders.handler = function displayTiddlersWithReminders(place,macroName,params)
{
   var now = new Date().getMidnight();
   var paramHash = {};
   var leadtime = [0,14];
   paramHash = getParamsForReminder(params);
   var bProvidedDate = (paramHash["year"] != null) || 
			(paramHash["month"] != null) || 
			(paramHash["day"] != null) || 
			(paramHash["dayofweek"] != null);
   if (paramHash["leadtime"] != null)
   {
      leadtime = paramHash["leadtime"];
      if (bProvidedDate)
      {
         //If they've entered a day, we need to make 
         //sure to find it.  We'll reset the leadtime 
         //a few lines down.
         paramHash["leadtime"] = [-10000,10000];
      }
   }
   var matchedDate = now;
   if (bProvidedDate)
   {
      var leadTimeLowerBound = new Date().getMidnight().addDays(paramHash["leadtime"][0]);
      var leadTimeUpperBound = new Date().getMidnight().addDays(paramHash["leadtime"][1]);
      matchedDate = findDateForReminder(paramHash, new Date().getMidnight(), leadTimeLowerBound, leadTimeUpperBound); 
   }
   var arr = findTiddlersWithReminders(matchedDate, leadtime, paramHash["tag"], paramHash["limit"]);
   for (var j = 0; j < arr.length; j++)
   {
      displayTiddler(null, arr[j]["tiddler"], 0, null, false, false, false);
   }
};

config.macros.reminder.handler = function reminder(place,macroName,params)
{
   var dateHash = getParamsForReminder(params);
   if (dateHash["hidden"] != null)
   {
      return;
   }
   var leadTime = dateHash["leadtime"];
   if (leadTime == null)
   {
      leadTime = config.macros.reminders["defaultLeadTime"]; 
   }
   var leadTimeLowerBound = new Date().getMidnight().addDays(leadTime[0]);
   var leadTimeUpperBound = new Date().getMidnight().addDays(leadTime[1]);
   var matchedDate = findDateForReminder(dateHash, new Date().getMidnight(), leadTimeLowerBound, leadTimeUpperBound);
   if (!window.story) 
   {
      window.story=window; 
   }
   if (!store.getTiddler) 
   {
      store.getTiddler=function(title) {return this.tiddlers[title];};
   }
   var title = window.story.findContainingTiddler(place).id.substr(7);
   if (matchedDate != null)
   {
      var diff = matchedDate.getDifferenceInDays(new Date().getMidnight());
      var elem = createTiddlyElement(place,"span",null,null, null);
      var mess = getReminderMessageForDisplay(diff, dateHash, matchedDate, title);
      wikify(mess, elem, null, null);
   }
   else
   {
      createTiddlyElement(place,"span",null,null, config.macros.reminders["noReminderFound"].replace("TITLE", dateHash["title"]).replace("LEADTIMEUPPER", leadTime[1]).replace("LEADTIMELOWER", leadTime[0]).replace("TIDDLERNAME", title).replace("TIDDLER", "[[" + title + "]]") );
   }
};

config.macros.newReminder.handler = function newReminder(place,macroName,params)
{
	// tomo - cleaned up the form layout a bit
	var today=new Date().getMidnight();
	var formstring = '<html><br/><form>';
	
	formstring += 'Year: <select name="year"><option value="">Every year</option>';
	for (var i = 0; i < 5; i++)
	{
		formstring += '<option' + ((i == 0) ? ' selected' : '') + ' value="' + (today.getFullYear() +i) + '">' + (today.getFullYear() + i) + '</option>';
	}
	formstring += '</select>&nbsp;&nbsp;Month: <select name="month"><option value="">Every month</option>';
	for (i = 0; i < 12; i++)
	{
		formstring += '<option' + ((i == today.getMonth()) ? ' selected' : '') + ' value="' + (i+1) + '">' + config.messages.dates.months[i] + '</option>';
	}
	formstring += '</select>&nbsp;&nbsp;Day: <select name="day"><option value="">Every day</option>';
	for (i = 1; i < 32; i++)
	{
		formstring += '<option' + ((i == (today.getDate() )) ? ' selected' : '') + ' value="' + i + '">' + i + '</option>';
	}
	formstring += '</select>&nbsp;&nbsp;&nbsp;&nbsp;Reminder Title: <input type="text" size="40" name="title" value="" onfocus="this.select();">&nbsp;&nbsp;<input type="button" value="Add reminder" onclick="addReminderToTiddler(this.form)">';
	formstring += '</form></html>';
	
	var panel = config.macros.slider.createSlider(place, null, "New Reminder", "Open a form to add a new reminder to this tiddler");
	wikify(formstring, panel, null, store.getTiddler(params[1]));
};

// onclick: process input and insert reminder at 'marker'
window.addReminderToTiddler = function(form) {
	if (!window.story) 
	{
		window.story=window; 
	}
	if (!store.getTiddler) 
	{
		store.getTiddler=function(title) {return this.tiddlers[title];};
	}
	var title = window.story.findContainingTiddler(form).id.substr(7);
	var tiddler=store.getTiddler(title);
	var txt='\n<<reminder ';
	if (form.year.value != "")
		txt += 'year:'+form.year.value + ' ';
	if (form.month.value != "")
		txt += 'month:'+form.month.value + ' ';
	if (form.day.value != "")
		txt += 'day:'+form.day.value + ' ';
	txt += 'title:"'+form.title.value+'" ';
	txt +='>>';
	tiddler.set(null,tiddler.text + txt);
	window.story.refreshTiddler(title,1,true);
	store.setDirty(true);
	// tomo - make sure to save if required
	if(config.options.chkAutoSave)
		saveChanges();
};

function hasTag(tiddlerTags, tagFilters)
{
	// tomo - this has been updated to work better with tag-less tiddlers
	
	//Make sure we respond well to empty tagFilterlists
	if (tagFilters.length==0) return true;
	
	var bHasTag = false;
	
	/*bNoPos says: "'till now there has been no check using a positive filter"
	Imagine a filterlist consisting of 1 negative filter:
	If the filter isn't matched, we want hasTag to be true.
	Yet bHasTag is still false ('cause only positive filters cause bHasTag to change)
	
	If no positive filters are present bNoPos is true, and no negative filters are matched so we have not returned false
	Thus: hasTag returns true.
	
	If at any time a positive filter is encountered, we want at least one of the tags to match it, so we turn bNoPos to false, which
	means bHasTag must be true for hasTag to return true*/
	var bNoPos=true;
	
	for (var t3 = 0; t3 < tagFilters.length; t3++)
	{
		var negTest = tagFilters[t3].length > 1 && tagFilters[t3].charAt(0) == '!';
		// do the positive filter test outside of the tag loop, in case there are no tags!
		if (bNoPos && !negTest) bNoPos = false;
		
		for(var t2=0; t2<tiddlerTags.length; t2++)
		{
			if (negTest) 
			{
				if (tiddlerTags[t2] == tagFilters[t3].substring(1))
				{
					//If at any time a negative filter is matched, we return false
					return false;
				}
			}
			else 
			{
				if (tiddlerTags[t2] == tagFilters[t3])
				{
					//A positive filter is matched. As long as no negative filter is matched, hasTag will return true
					bHasTag=true;
				}
			}
		}
	}
	return (bNoPos || bHasTag);
};

//This function searches all tiddlers for the reminder  //macro.  It is intended that other plugins (like //calendar) will use this function to query for 
//upcoming reminders.
//The arguments to this function filter out reminders //based on when they will fire.
//
//ARGUMENTS:
//baseDate is the date that is used as "now".  
//leadtime is a two element int array, with leadtime[0] 
//         as the lower bound and leadtime[1] as the
//         upper bound.  A reasonable default is [0,14]
//tags is a space-separated list of tags to use to filter 
//         tiddlers.  If a tag name begins with an !, then 
//         only tiddlers which do not have that tag will 
//         be considered.  For example "examples holidays"  
//         will search for reminders in any tiddlers that  
//         are tagged with examples or holidays and 
//         "!examples !holidays" will search for reminders 
//         in any tiddlers that are not tagged with 
//         examples or holidays.  Pass in null to search 
//         all tiddlers.
//limit.  If limit is null, individual reminders can 
//        override the leadtime specified earlier.  
//        Pass in 1 in order to override that behavior.

window.findTiddlersWithReminders = function findTiddlersWithReminders(baseDate, leadtime, tags, limit)
{
//function(searchRegExp,sortField,excludeTag)
//   var macroPattern = "<<([^>\\]+)(?:\\*)([^>]*)>>";
   var macroPattern = "<<(reminder)(.*)>>";
   var macroRegExp = new RegExp(macroPattern,"mg");
   var matches = store.search(macroRegExp,"title","");
   var arr = [];
   var tagsArray = null;
   if (tags != null)
   {
      tagsArray = tags.split(" ");
   }
   for(var t=matches.length-1; t>=0; t--)
   {
      if (tagsArray != null)
      {
         //If they specified tags to filter on, and this tiddler doesn't 
	 //match, skip it entirely.
         if ( ! hasTag(matches[t].tags, tagsArray))
         {
            continue;
         }
      }

      var targetText = matches[t].text;
      do {
         // Get the next formatting match
         var formatMatch = macroRegExp.exec(targetText);
         if(formatMatch && formatMatch[1] != null && formatMatch[1].toLowerCase() == "reminder")
         {
            //Find the matching date.
            
            var params = formatMatch[2] != null ? formatMatch[2].readMacroParams() : {};
            var dateHash = getParamsForReminder(params);
            if (limit != null || dateHash["leadtime"] == null)
            {
               if (leadtime == null)
                   dateHash["leadtime"] = leadtime;
               else
               {
                  dateHash["leadtime"] = [];
                  dateHash["leadtime"][0] = leadtime[0];
                  dateHash["leadtime"][1] = leadtime[1];
               }
            }
	    if (dateHash["leadtime"] == null)
               dateHash["leadtime"] = config.macros.reminders["defaultLeadTime"]; 
            var leadTimeLowerBound = baseDate.addDays(dateHash["leadtime"][0]);
            var leadTimeUpperBound = baseDate.addDays(dateHash["leadtime"][1]);
            var matchedDate = findDateForReminder(dateHash, baseDate, leadTimeLowerBound, leadTimeUpperBound);
            while (matchedDate != null)
            {
               var hash = {};
               hash["diff"] = matchedDate.getDifferenceInDays(baseDate);
               hash["matchedDate"] = new Date(matchedDate.getFullYear(), matchedDate.getMonth(), matchedDate.getDate(), 0, 0);
               hash["params"] = cloneParams(dateHash);
               hash["tiddler"] = matches[t].title;
               hash["tags"] = matches[t].tags;
               arr.pushUnique(hash);
	       if (dateHash["recurdays"] != null || (dateHash["year"] == null))
	       {
	         leadTimeLowerBound = leadTimeLowerBound.addDays(matchedDate.getDifferenceInDays(leadTimeLowerBound)+ 1);
                 matchedDate = findDateForReminder(dateHash, baseDate, leadTimeLowerBound, leadTimeUpperBound);
	       }
	       else matchedDate = null;
            }
         }
      }while(formatMatch);
   }
   if(arr.length > 1)  //Sort the array by number of days remaining.
   {
      arr.sort(function (a,b) {if(a["diff"] == b["diff"]) {return(0);} else {return (a["diff"] < b["diff"]) ? -1 : +1; } });
   }
   return arr;
};

//This function takes the reminder macro parameters and
//generates the string that is used for display.
//This function is not intended to be called by 
//other plugins.
 window.getReminderMessageForDisplay= function getReminderMessageForDisplay(diff, params, matchedDate, tiddlerTitle)
{
   var anniversaryString = "";
   var reminderTitle = params["title"];
   if (reminderTitle == null)
   {
      reminderTitle = config.macros.reminders["untitledReminder"];
   }
   if (params["firstyear"] != null)
   {
      anniversaryString = config.macros.reminders["defaultAnniversaryMessage"].replace("DIFF", (matchedDate.getFullYear() - params["firstyear"]));
   }
   var mess = "";
   var diffString = "";
   if (diff == 0)
   {
      diffString = config.macros.reminders["todayString"];
   }
   else if (diff == 1)
   {
      diffString = config.macros.reminders["tomorrowString"];
   }
   else
   {
      diffString = config.macros.reminders["ndaysString"].replace("DIFF", diff);
   }
   var format = config.macros.reminders["defaultReminderMessage"];
   if (params["format"] != null)
   {
      format = params["format"];
   }
   mess = format;
//HACK!  -- Avoid replacing DD in TIDDLER with the date
   mess = mess.replace(/TIDDLER/g, "TIDELER");
   mess = matchedDate.formatStringDateOnly(mess);
   mess = mess.replace(/TIDELER/g, "TIDDLER");
   if (tiddlerTitle != null)
   {
      mess = mess.replace(/TIDDLERNAME/g, tiddlerTitle);
      mess = mess.replace(/TIDDLER/g, "[[" + tiddlerTitle + "]]");
   }
   
   mess = mess.replace("DIFF", diffString).replace("TITLE", reminderTitle).replace("DATE", matchedDate.formatString("DDD MMM DD, YYYY")).replace("ANNIVERSARY", anniversaryString);
   return mess;
};

// Parse out the macro parameters into a hashtable.  This
// handles the arguments for reminder, showReminders and 
// displayTiddlersWithReminders.
window.getParamsForReminder = function getParamsForReminder(params)
{
   var dateHash = {};
   var type = "";
   var num = 0;
   var title = "";
   for(var t=0; t<params.length; t++)
   {
      var split = params[t].split(":");
      type = split[0].toLowerCase();
      var value = split[1];
      for (var i=2; i < split.length; i++)
      {
         value += ":" + split[i];
      }
      if (type == "nolinks" || type == "limit" || type == "hidden")
      {
         num = 1;
      }
      else if (type == "leadtime")
      {
         var leads = value.split("...");
         if (leads.length == 1)
         {
            leads[1]= leads[0];
            leads[0] = 0;
         }
         leads[0] = parseInt(leads[0], 10);
         leads[1] = parseInt(leads[1], 10);
         num = leads;
      }
      else if (type == "offsetdayofweek")
      {
          if (value.substr(0,1) == "-")
          {
             dateHash["negativeOffsetDayOfWeek"] = 1;
	     value = value.substr(1);
          }
          num = parseInt(value, 10);
      }
      else if (type != "title" && type != "tag" && type != "format")
      {
         num = parseInt(value, 10);
      }
      else
      {
         title = value;
         t++;
         while (title.substr(0,1) == '"' && title.substr(title.length - 1,1) != '"' && params[t] != undefined)
         {
            title += " " + params[t++];
         }
         //Trim off the leading and trailing quotes
         if (title.substr(0,1) == "\"" && title.substr(title.length - 1,1)== "\"")
         {
            title = title.substr(1, title.length - 2);
            t--;
         }
         num = title;
      }
      dateHash[type] = num;
   }
   //date is synonymous with day
   if (dateHash["day"] == null)
   {
      dateHash["day"] = dateHash["date"];
   }
   return dateHash;
};

//This function finds the date specified in the reminder 
//parameters.  It will return null if no match can be
//found.  This function is not intended to be used by
//other plugins.
window.findDateForReminder= function findDateForReminder( dateHash, baseDate, leadTimeLowerBound, leadTimeUpperBound)
{
   if (baseDate == null)
   {
     baseDate = new Date().getMidnight();
   }
   var hashKey = baseDate.convertToYYYYMMDDHHMM();
   for (var k in dateHash)
   {
      hashKey += "," + k + "|" + dateHash[k];
   }
   hashKey += "," + leadTimeLowerBound.convertToYYYYMMDDHHMM();
   hashKey += "," + leadTimeUpperBound.convertToYYYYMMDDHHMM();
   if (reminderCache[hashKey] == null)
   {
      //If we don't find a match in this run, then we will
      //cache that the reminder can't be matched.
      reminderCache[hashKey] = false;
   }
   else if (reminderCache[hashKey] == false)
   {
      //We've already tried this date and failed
      return null;
   }
   else
   {
      return reminderCache[hashKey];
   }
   
   var bOffsetSpecified = dateHash["offsetyear"] != null || 
				dateHash["offsetmonth"] != null || 
				dateHash["offsetday"] != null || 
				dateHash["offsetdayofweek"] != null || 
				dateHash["recurdays"] != null;
   
   // If we are matching the base date for a dayofweek offset, look for the base date a 
   //little further back.
   var tmp1leadTimeLowerBound = leadTimeLowerBound;  
   if ( dateHash["offsetdayofweek"] != null)
   {
      tmp1leadTimeLowerBound = leadTimeLowerBound.addDays(-6);  
   }
   var matchedDate = baseDate.findMatch(dateHash, tmp1leadTimeLowerBound, leadTimeUpperBound);
   if (matchedDate != null)
   {
      var newMatchedDate = matchedDate;
      if (dateHash["recurdays"] != null)
      {
         while (newMatchedDate.getTime() < leadTimeLowerBound.getTime())
         {
            newMatchedDate = newMatchedDate.addDays(dateHash["recurdays"]);
         }
      }
      else if (dateHash["offsetyear"] != null || 
		dateHash["offsetmonth"] != null || 
		dateHash["offsetday"] != null || 
		dateHash["offsetdayofweek"] != null)
      {
         var tmpdateHash = cloneParams(dateHash);
         tmpdateHash["year"] = dateHash["offsetyear"];
         tmpdateHash["month"] = dateHash["offsetmonth"];
         tmpdateHash["day"] = dateHash["offsetday"];
         tmpdateHash["dayofweek"] = dateHash["offsetdayofweek"];
	 var tmpleadTimeLowerBound = leadTimeLowerBound;
	 var tmpleadTimeUpperBound = leadTimeUpperBound;
	 if (tmpdateHash["offsetdayofweek"] != null)
	 {
	 	if (tmpdateHash["negativeOffsetDayOfWeek"] == 1)
		{
		   tmpleadTimeLowerBound = matchedDate.addDays(-6);
		   tmpleadTimeUpperBound = matchedDate;

		}
		else
		{
		   tmpleadTimeLowerBound = matchedDate;
		   tmpleadTimeUpperBound = matchedDate.addDays(6);
		}

	 }
	 newMatchedDate = matchedDate.findMatch(tmpdateHash, tmpleadTimeLowerBound, tmpleadTimeUpperBound);
         //The offset couldn't be matched.  return null.
         if (newMatchedDate == null)
         {
            return null;
         }
      }
      if (newMatchedDate.isBetween(leadTimeLowerBound, leadTimeUpperBound))
      {
         reminderCache[hashKey] = newMatchedDate;
         return newMatchedDate;
      }
   }
   return null;
};

//This does much the same job as findDateForReminder, but
//this one doesn't deal with offsets or recurring 
//reminders.
Date.prototype.findMatch = function findMatch(dateHash, leadTimeLowerBound, leadTimeUpperBound)
{

   var bSpecifiedYear =     (dateHash["year"] != null);
   var bSpecifiedMonth =     (dateHash["month"] != null);
   var bSpecifiedDay =     (dateHash["day"] != null);
   var bSpecifiedDayOfWeek =     (dateHash["dayofweek"] != null);
   if (bSpecifiedYear && bSpecifiedMonth && bSpecifiedDay)
   {
      return new Date(dateHash["year"], dateHash["month"]-1, dateHash["day"], 0, 0);
   }
   var bMatchedYear = !bSpecifiedYear;
   var bMatchedMonth = !bSpecifiedMonth;
   var bMatchedDay = !bSpecifiedDay;
   var bMatchedDayOfWeek = !bSpecifiedDayOfWeek;
   if (bSpecifiedDay && bSpecifiedMonth && !bSpecifiedYear && !bSpecifiedDayOfWeek)
   {

      //Shortcut -- First try this year.  If it's too small, try next year.
      var tmpMidnight = this.getMidnight();
      var tmpDate = new Date(this.getFullYear(), dateHash["month"]-1, dateHash["day"], 0,0);
      if (tmpDate.getTime() < leadTimeLowerBound.getTime())
      {
         tmpDate = new Date((this.getFullYear() + 1), dateHash["month"]-1, dateHash["day"], 0,0);
      }
      if ( tmpDate.isBetween(leadTimeLowerBound, leadTimeUpperBound))
      {
         return tmpDate;
      }
      else
      {
         return null;
      }
   }

   var newDate = leadTimeLowerBound; 
   while (newDate.isBetween(leadTimeLowerBound, leadTimeUpperBound))
   {
      var tmp = testDate(newDate, dateHash, bSpecifiedYear, bSpecifiedMonth, bSpecifiedDay, bSpecifiedDayOfWeek);
      if (tmp != null)
        return tmp;
      newDate = newDate.addDays(1);
   }
};

function testDate(testMe, dateHash, bSpecifiedYear, bSpecifiedMonth, bSpecifiedDay, bSpecifiedDayOfWeek)
{
   var bMatchedYear = !bSpecifiedYear;
   var bMatchedMonth = !bSpecifiedMonth;
   var bMatchedDay = !bSpecifiedDay;
   var bMatchedDayOfWeek = !bSpecifiedDayOfWeek;
   if (bSpecifiedYear)
   {
      bMatchedYear = (dateHash["year"] == testMe.getFullYear());
   }
   if (bSpecifiedMonth)
   {
      bMatchedMonth = ((dateHash["month"] - 1)  == testMe.getMonth() );
   }
   if (bSpecifiedDay)
   {
      bMatchedDay = (dateHash["day"] == testMe.getDate());
   }
   if (bSpecifiedDayOfWeek)
   {
      bMatchedDayOfWeek = (dateHash["dayofweek"] == testMe.getDay());
   }

   if (bMatchedYear && bMatchedMonth && bMatchedDay && bMatchedDayOfWeek)
   {
      return testMe;
   }
};

//Returns true if the date is in between two given dates
Date.prototype.isBetween = function isBetween(lowerBound, upperBound)
{
  return (this.getTime() >= lowerBound.getTime() && this.getTime() <= upperBound.getTime());
}
//Return a new date, with the time set to midnight (0000)
Date.prototype.getMidnight = function getMidnight()
{
   return new Date(this.getFullYear(), this.getMonth(), this.getDate(), 0, 0);
};
// Add the specified number of days to a date.
Date.prototype.addDays = function addDays(numberOfDays)
{
   return new Date(this.getFullYear(), this.getMonth(), this.getDate() + numberOfDays, 0, 0);
};
//Return the number of days between two dates.
Date.prototype.getDifferenceInDays = function getDifferenceInDays(otherDate)
{
//I have to do it this way, because this way ignores daylight savings
   var tmpDate = this.addDays(0);
   if (this.getTime() > otherDate.getTime())
   {
      var i = 0;
      for (i = 0; tmpDate.getTime() > otherDate.getTime(); i++)
      {
         tmpDate = tmpDate.addDays(-1);
      }
      return i;
   }
   else
   {
      var i = 0;
      for (i = 0; tmpDate.getTime() < otherDate.getTime(); i++)
      {
         tmpDate = tmpDate.addDays(1);
      }
      return i * -1;
   }
   return 0;
};
function cloneParams(what) {
    var tmp = {};
    for (var i in what) {
        tmp[i] = what[i];
    }
    return tmp;
}
// Substitute date components into a string
Date.prototype.formatStringDateOnly = function formatStringDateOnly(template)
{
	template = template.replace("YYYY",this.getFullYear());
	template = template.replace("YY",String.zeroPad(this.getFullYear()-2000,2));
	template = template.replace("MMM",config.messages.dates.months[this.getMonth()]);
	template = template.replace("0MM",String.zeroPad(this.getMonth()+1,2));
	template = template.replace("MM",this.getMonth()+1);
	template = template.replace("DDD",config.messages.dates.days[this.getDay()]);
	template = template.replace("0DD",String.zeroPad(this.getDate(),2));
	template = template.replace("DD",this.getDate());
	return template;
};

//}}}
!Overdue actions
<<showReminders leadtime:-365...-1 tag:"action !done" format:"DATE: @@color:red;TITLE@@ [ TIDDLER ]">>
!Actions for today and tomorrow
<<showReminders leadtime:0...1 tag:"action !done" format:"DIFF: @@color:red;TITLE@@ [ TIDDLER ]">>
!All reminders for the next week
<<showReminders leadtime:0...7 tag:"!done" format:"DIFF: @@color:red;TITLE@@ [ TIDDLER ]">>


Click on the button below to create a new reminder as a tickler:

<<newReminder>>
/***
|Name|SinglePageModePlugin|
|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|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
<<<
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: 6, date: new Date(2008,10,17)};
//}}}
//{{{
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=document.getElementById(story.idPrefix+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=document.getElementById(story.idPrefix+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;
}
//}}}
Groningen Logicians <<tiddler ToggleRightSidebar with: ".">> 
GROLOG
<<list tagged txtGTDSomedayContext any>>
The Grolog Colloquia are sponsored by:

- the Department of Computer Science, RUG
- the Department of Artificial Intelligence, RUG
- the Department of Theoretical Philosophy, RUG
[[GTDStyleSheet]]
[[GTDTWStyleSheet]]

/***
!Personal preferences
***/

/*{{{*/
/* make input fields in viewer (options) show up in correct size */
.viewer input { font-size: 0.9em; }

.editor { font-family: monospace; font-size: 10pt; }

/*}}}*/
/*{{{*/

@media print {
#mainMenu, #sidebar, #messageArea {display: none !important;}
#displayArea {margin: 1em 1em 0em 1em;}


/* LAYOUT ELEMENTS ========================================================== */
*
{
 margin: 0;
 padding: 0;
}

body {
 background: #fff;
 color: #000;
 font-size: 6.2pt;
 font-family: "Lucida Grande", "Bitstream Vera Sans", Helvetica, Verdana, Arial, sans-serif;
}

img {
 max-width: 2.2in;
 max-height: 4.3in;
}

#header, #side_container, #storeArea, #copyright, #floater, #messageArea, .save_accesskey, .site_description, #saveTest, .toolbar, .footer
{
 display: none;
}

#tiddlerDisplay, #displayArea
{
 display: inline;
}

.tiddler {
 margin: 0 0 2em 0;
 border-top: 1px solid #000;
 page-break-before: always;
}

.tiddler:first-child {
 page-break-before: avoid;
}

.title {
 font-size: 1.6em;
 font-weight: bold;
 margin-bottom: .3em;
 padding: .2em 0;
 border-bottom: 1px dotted #000;
}

p, blockquote, ul, li, ol, dt, dd, dl, table
{
 margin: 0 0 .3em 0;
}

h1, h2, h3, h4, h5, h6
{
 margin: .2em 0;
} 

h1
{
 font-size: 1.5em;
}

h2
{
 font-size: 1.3em;
}

h3
{
 font-size: 1.25em;
}

h4
{
 font-size: 1.15em;
}

h5
{
 font-size: 1.1em;
}

blockquote
{
 margin: .6em;
 padding-left: .6em;
 border-left: 1px solid #ccc;
}

ul
{
 list-style-type: circle;
}

li
{
 margin: .1em 0 .1em 2em;
 line-height: 1.4em; 
}

table
{
 border-collapse: collapse;
 font-size: 1em;
}

td, th
{
 border: 1px solid #999;
 padding: .2em;
}

hr {
 border: none;
 border-top: dotted 1px #777;
 height: 1px;
 color: #777;
 margin: .6em 0;
}
}
/*}}}*/

|''URL:''|http://www.tiddlytools.com/|
|''Description:''|TiddlyTools - Small Tools for Big Ideas|
|''Author:''|Eric Shulman|
/%
!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:
<<<
{{{
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;
}}>>
/***
Description: Contains the stuff you need to use Tiddlyspot
Note, you also need UploadPlugin, PasswordOptionPlugin and LoadRemoteFileThroughProxy
from http://tiddlywiki.bidix.info for a complete working Tiddlyspot site.
***/
//{{{

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

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

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

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

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

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

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

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

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

});
//}}}
If you are connected to the Internet, you can always get the latest version of this application. While it is possible to upgrade using the standard TiddlyWiki import using the backstage area (for which there is an official d-cubed feed, but see the caveats for upgrading using backstage, below), there are ''three better'' ways you can do this:

Click the following button if you simply want to get the latest changes to any of the core tiddlers that make up this application. These tiddlers are tagged "gtd", and updating in this way will not overwrite any of the core tiddlers that you may have changed unless the core tiddlers are even newer than your changes. This is the recommended way to get updates:
**<<importUpdates "http://www.dcubed.ca/d3-update-13.html">>

Click the following button if you would like to get the latest changes to any of the core tiddlers, but to interactively approve each and every updated tiddler as it is loaded into your system. If there are no updated tiddlers, you will not be prompted and the update will exit quietly:
**<<importUpdates "http://www.dcubed.ca/d3-update-13.html" updates "Update interactively" "Click here to interactively update the application" confirm>>

Click the following button if you want to download all of the core tiddlers, regardless of their modification date. Use this to absolutely ensure that you are running with the core application as it was originally written:
**<<importUpdates "http://www.dcubed.ca/d3-update-13.html" all "Update everything" force>>

''For your safety, your file will be saved and a backup file will be automatically generated before any update is performed.''

!!Updating using backstage

There is a feed defined to enable you to update from "backstage". Just select "Official d-cubed feed" from the feed selection list, and import all tiddlers. Be sure to uncheck the "Keep these tiddlers linked..." checkbox before importing.

Also, unless you are importing into an empty d-cubed document, always save a copy before importing into a document that has important stuff.
Because of the changes to TiddlyWiki, it is not possible to upgrade to this new version from version 1.2 using the normal UpdateApplication you are familiar with. Indeed, the only way to get this new version is to start with an empty d-cubed document, and import your projects, actions, and contexts from your existing d-cubed document.

The most reliable way to import your tiddlers into a new document is to use the "backstage import" feature of the new TiddlyWiki. If you are not familiar with this, you should take a few moments at http://www.tiddlywiki.com/ to learn the new features. However please note that ''whenever you are using the backstage import feature of TiddlyWiki to import actions, projects, or contexts, you must first disable the "GTDPlugins" plugin''. 

To reliably upgrade your d-cubed document (subject to caveats, below):
# Start with a copy of an empty d-cubed document (you will need the empty document later).
# Open the "backstage", click on the "plugins" tab, and ensure there is a check in the "Disabled" column of "GTDPlugins". Save and reload your document.
# Import all the tiddlers from your old d-cubed document. Be sure to have the "Keep these tiddlers linked..." checkbox //unchecked//.
# After importing all the tiddlers from your original d-cubed document ''but before saving and reloading'', do another import from the original empty d-cubed document you copied in step 1. Again, ensure that the "Keep these tiddlers linked..." checkbox is //unchecked//.
# Once you have completed your import, confirm that "GTDPlugins" is re-enabled, reversing step 2. Save and reload, and you should be back in business. 
# Remove or disable the following obsolete plugins: TWUpdatePlugin, NewerTiddlerPlugin, ImportTiddlersPlugin. If you have customized core pieces of d-cubed (such as GTDMenu or ProjectList) you can now also carefully merge those changes into your new working document.
If you do not follow this procedure, especially disabling "GTDPlugins", you will see strange behaviour as the core d-cubed code tries to process your GTD tiddlers as they are being pulled in. However once you are upgraded you can freely use the backstage import at any time in the future to get other non-d3 tiddlers (like other plugins) without disabling "GTDPlugins". 

While the upgrade process described above is rather inelegant, the good news is that unless TiddlyWiki undergoes another major architectural change, future updates to d-cubed will revert to the usual painless process in UpdateApplication.

!!Platform caveats
As of this writing, version 2.4.1 of TiddlyWiki has a number of issues with certain browser/platform configurations:
#On Firefox for Mac, you need to ensure that the source and destination d-cubed documents for the import are in the same directory. Otherwise, you get some pretty messy behaviour in the file path selection.
#On IE (Windows), file importing is simply broken ("access is denied"). There does not appear to be a workaround save using Firefox (for the import at least).
| !date | !user | !location | !storeUrl | !uploadDir | !toFilename | !backupdir | !origin |
| 20/10/2010 17:56:48 | grolog | [[/|http://grolog.tiddlyspot.com/#%5B%5BGroningen-Amsterdam%20Dynamic%20Seminar%5D%5D]] | [[store.cgi|http://grolog.tiddlyspot.com/store.cgi]] | . | [[index.html | http://grolog.tiddlyspot.com/index.html]] | . | ok |
| 20/10/2010 17:57:51 | grolog | [[/|http://grolog.tiddlyspot.com/#%5B%5BGroningen-Amsterdam%20Dynamic%20Seminar%5D%5D]] | [[store.cgi|http://grolog.tiddlyspot.com/store.cgi]] | . | [[index.html | http://grolog.tiddlyspot.com/index.html]] | . | ok |
| 20/10/2010 18:00:28 | grolog | [[/|http://grolog.tiddlyspot.com/#%5B%5BGroningen-Amsterdam%20Dynamic%20Seminar%5D%5D]] | [[store.cgi|http://grolog.tiddlyspot.com/store.cgi]] | . | [[index.html | http://grolog.tiddlyspot.com/index.html]] | . | ok |
| 20/10/2010 18:01:11 | grolog | [[/|http://grolog.tiddlyspot.com/#%5B%5BGroningen-Amsterdam%20Dynamic%20Seminar%5D%5D]] | [[store.cgi|http://grolog.tiddlyspot.com/store.cgi]] | . | [[index.html | http://grolog.tiddlyspot.com/index.html]] | . |
| 05/02/2011 14:57:30 | grolog | [[/|http://grolog.tiddlyspot.com/]] | [[store.cgi|http://grolog.tiddlyspot.com/store.cgi]] | . | [[index.html | http://grolog.tiddlyspot.com/index.html]] | . |
| 12/02/2011 15:07:40 | grolog | [[/|http://grolog.tiddlyspot.com/]] | [[store.cgi|http://grolog.tiddlyspot.com/store.cgi]] | . | [[index.html | http://grolog.tiddlyspot.com/index.html]] | . | ok |
| 12/02/2011 15:19:59 | grolog | [[/|http://grolog.tiddlyspot.com/]] | [[store.cgi|http://grolog.tiddlyspot.com/store.cgi]] | . | [[index.html | http://grolog.tiddlyspot.com/index.html]] | . | ok |
| 12/02/2011 15:25:34 | grolog | [[/|http://grolog.tiddlyspot.com/]] | [[store.cgi|http://grolog.tiddlyspot.com/store.cgi]] | . | [[index.html | http://grolog.tiddlyspot.com/index.html]] | . | ok |
| 12/02/2011 15:31:40 | grolog | [[/|http://grolog.tiddlyspot.com/]] | [[store.cgi|http://grolog.tiddlyspot.com/store.cgi]] | . | [[index.html | http://grolog.tiddlyspot.com/index.html]] | . | ok |
| 12/02/2011 15:42:41 | grolog | [[/|http://grolog.tiddlyspot.com/]] | [[store.cgi|http://grolog.tiddlyspot.com/store.cgi]] | . | [[index.html | http://grolog.tiddlyspot.com/index.html]] | . |
/***
|''Name:''|UploadPlugin|
|''Description:''|Save to web a TiddlyWiki|
|''Version:''|4.1.3|
|''Date:''|Feb 24, 2008|
|''Source:''|http://tiddlywiki.bidix.info/#UploadPlugin|
|''Documentation:''|http://tiddlywiki.bidix.info/#UploadPluginDoc|
|''Author:''|BidiX (BidiX (at) bidix (dot) info)|
|''License:''|[[BSD open source license|http://tiddlywiki.bidix.info/#%5B%5BBSD%20open%20source%20license%5D%5D ]]|
|''~CoreVersion:''|2.2.0|
|''Requires:''|PasswordOptionPlugin|
***/
//{{{
version.extensions.UploadPlugin = {
	major: 4, minor: 1, revision: 3,
	date: new Date("Feb 24, 2008"),
	source: 'http://tiddlywiki.bidix.info/#UploadPlugin',
	author: 'BidiX (BidiX (at) bidix (dot) info',
	coreVersion: '2.2.0'
};

//
// Environment
//

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

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

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

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

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

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

//
// uploadOptions Macro
//

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

//
// upload functions
//

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

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

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

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

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

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

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

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

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

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

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

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

//
// Utilities
// 

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

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

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

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

//
// Initializations
//

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

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

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

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


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


//}}}
<!--{{{-->
<div class='toolbar' macro='toolbar [[ToolbarCommands::ViewToolbar]]'></div>
<div class='title' macro='view title'></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 projectify +saveTiddler -cancelTiddler deleteAction'></div>
<div class='title' macro='view title'></div>
<div class='subtitle'><span macro='view gtd.project'></span></div>
<div class='editor' macro='edit title'></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'></span></div>
<div class='toolbar' macro='toolbar changeContext changeProject deleteAction closeTiddler closeOthers +editTiddler permalink references jump'></div>
<div class='title' macro='view title'></div>
<div class='subtitle'><span macro='view gtd.project link'></span></div>
</span>complete&nbsp;<span macro='gtdToggleTag floating'></span>floating</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><br/>
<div macro='newReminder'></div>
<div class='toolbar' macro='toolbar +saveTiddler -cancelTiddler deleteContext'></div>
<div class='title' macro='view title'></div>
<div class='editor' macro='edit title'></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'></span></div>
<div class='toolbar' macro='toolbar newAction closeTiddler closeOthers +editTiddler permalink references jump'></div>
<div class='title' macro='view title'></div>
<div class='viewer' macro='view text wikified'></div>
<div class='tagClear'></div>
Completed document conversion. Do not delete this tiddler unless you want to rebuild the action metadata.

This tiddler also contains document-specific preferences which, if deleted, will revert to default settings.

<div class='toolbar' macro='toolbar newProjectAction archiveProject deleteProject deleteProjectAll closeTiddler closeOthers +editTiddler permalink references jump'></div>
<div class='title' macro='view title'></div>
<div class='tagged' macro='tags'></div>
<div class='viewer' macro='view text wikified'></div>
<div class='tagClear'></div><br/><div macro='newReminder'></div>
<div class='toolbar' macro='toolbar closeTiddler closeOthers +editTiddler permalink references jump'></div>
<div class='title' macro='view title'></div></div>
<div class='viewer' macro='view text wikified'></div>
<div class='tagClear'></div>
if(config.options.txtUserName != "grolog") {
config.options.chkDatePopupHideCreated= true;
config.options.chkDatePopupHideChanged= true;
config.options.chkDatePopupHideTagged= true;
config.options.chkDatePopupHideReminders= true; 
config.options.chkSinglePageMode= true; 
config.options.chkShowRightSidebar=false; 
readOnly = true;
showBackstage = false;
}