<!--{{{-->
<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'></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>>
<<tiddler JournalNavigation>>

Personal Information Management can be roughly defined as the practice of collecting one's information, organizing it, storing it, and generally getting it back as quickly as possible when it is needed.  Knowledge Management is involves discovering real knowledge out of the flood of noise in the information flow, and then republishing that knowledge so that other people can work with it.  

So, where PIM is about organization, KM is about discovering new things and communicating those to other people.  Organization comes first, effective collaboration comes second.  Both can be practiced at the same time, but as one improves one's organization, e also improves eir ability to effectively collaborate.

These words are badly overloaded, but they do have real meanings.

This is where my passion lies.  Gather everything I know.  Organize it, make it easily retrievable.  Keep a detailed journal of everything I think of.  Try to keep it as a bunch of "searchable notes" or some such, along with a few synthetic essays.

My target audience is anyone who is interested.  My friends and close associates are the obvious people.  I am not an expert on this topic.  I read information as it comes my direction, but I lack any significant training in neuroscience, psychology, advanced mathematics, set theory, and possibly a great many other fields that are relevant to this topic.  My approach is purely empirical, involving semi-blind experiments to see what helps me and what does not.

I have two intents with this log.  First, I want to explain to those close to me what exactly I am working on, why I am passionate about it, and ultimately what I see producing.  Second, I want to explain everything that I know on the topics of information and knowledge management, everything that can be useful to other people.  Thirdly, I want to elicit comment from those who can help me by contributing new techniques, refining my ideas, or contributing coding skill.

My Grand Goal is to produce a set of software and techniques that help out with both PIM and KM, and maybe even take the next step to smart agents that work to help me seek out new, relevant information before I even know it exists.

Under normal circumstances, I would publish this on my own web page.  I do not, however, currently have any weblogging software.  In lieu of publishing this on my own web page, I will instead use Livejournal and Zaadz as my publication media.  Over the next few months to one year, I will slowly create additional essays covering whatever topic seems most important to me at the time.

For those who have known me for a long time, this is not a mellowing about Livejournal.  I still do not trust any other system to be there for me when I need it.  My work is done entirely inside my own filing system.  I will, when it is done, actually copy-and-paste this document into Livejournal.  This is how I work, primarily to protect myself from mistakes on the part of people whom I do not know and am not paying.  For now, however, it is necessary for me to use Livejournal as the medium in which to push my ideas to you.

Welcome.  Walk this road with me, and let us see where we get, as practical people applying abstract theory to our real worlds.

* [[Wikipedia: Personal Information Management|http://en.wikipedia.org/wiki/Personal_information_management]]
* [[Wikipedia: Knowledge Management|http://en.wikipedia.org/wiki/Knowledge_management]]
* [[My livejournal|http://savanni.livejournal.com/]]
* [[My Gaia log|http://savanni.gaia.com/blog]]

<<tiddler JournalNavigation>>
<<tiddler JournalNavigation>>
This entry starts off at ground zero.  I will describe my organizational system in a broad overview, leaving a great many details for later documents.

Having my information organized is very much the first step in my broader goal.  In the near term, it is important because it gives me a system in which I can work easily and accomplish what I want to accomplish.  In the longer term, it puts enough information together that automated searching tools may be able to assist me at higher levels than they currently do.

I have gotten organized.  It is not incredible organization, but it is a work in progress that is actually making progress.  For those who wish to know, my system is heavily influenced by the book "Getting Things Done", by David Allen.  Part of my mind is also heavily influenced by the book "The 7 Habits of Highly Effective People", by Stephen Covey, but that is not currently reflected in my organizational system.

I theorize that 7 Habits is better for high-level planning, deciding what to do, where GTD is good for day-to-day churning through work.  Factoring that into my system is a goal for the future.

! Objects
!! Notecards
Call this my first line of my organization.  Many of you have seen me carrynig these around.  Onto my notecards every day go my tasks for the day.  That is also where I put any new ideas that I have.  It is where I scribble out ideas.  It is, in short, the tiny fragment of my organization system which I can carry around in my pocket and which requires no electricity.

This part is critical to me.  I have tried out many forms over the years, but in the end a set of notecards worked out best.

!! Email Inbox
The flood.  All of you are familiar with this.  Family and friend checkins.  Organizing events.  Tossing out ideas.  General chatting.  I even get my *news* in my email inbox because of the magic of RSS feeds.

Large papers can and have been written about email, email overload, handling the flood, and a myriad other topics related to just trying to manage the deluge.  I, personally, make liberal and rapid use of the "delete" key, and employ very aggressive front-end spam filtering.

!! Paper Inbox
The other place under which I can get crushed.  Paper always feels less urgent, so I am more inclined to let things pile up here.  Of course, this is also where the bills go, so letting things pile up here is a cannonically bad idea.

The problem is that paper is harder to deal with than email.  With email, I can easily cut and paste important stuff before throwing the message away.  Anything I want in paper I will have to manually type.  Not that this should be a bad thing, but it still provides a higher barrier to entry than email.

!! Task List
Here is where I keep a list of everything that I am actually committed to doing.  This is not everything that I think of to do, merely everything that I plan to do.  Ideally it is everything that I will do in the near future.

In general, I subdivide this section up first by tasks that I am waiting on, tasks that I could do right now, and tasks that I want to do today.  Each of those has additional tags, one to represent what project, if any, with which it is associated, and another to represent what "context" is necessary in order to actually do that task.

"context" is important, though a feature that I do not use often.  GTD afficionados will already know what I am talking about here.  It is a categorization for "this is where I need to be or what I need to have in order to perform the task".  An obvious set of contexts are @home and @work.  I also heavily use @calls, @online, and @offline.  I may not use contexts very well.  In my system, it is possible to me in many different contexts at once.  For instance, in my house I can almost always do something in the @home, @offline, @online, or @calls contexts.  The result is that I do not do really pay attention to context, whereas ideally a task manager would not even let me see tasks that are currently out of context.

!! Maybe List
Just like the task list, but all of these things are things that I might do one day, or things that are so far away that, well... maybe.

!! Calendar
My Schedule (TM).  This is the location for all appointments and for tasks that are due on a certain day.  Paying my mortgage ends up as a repeating event on my calendar.  GTD describes this as the "static landscape", i.e., what must be done and when.  In reality, some things end up there that do not belong there because I want them to *nag* me.  That does not, however, seem to help me get them done any sooner.

A side-effect of the calendar is that I know exactly where my time is going, and this makes it more obvious when I am overscheduling myself.

!! Reminder File
This is a place where I put documents that need to come back and nag me on a certain date.  Bills, reciepts for products that are going to become unreturnable, invitations, or documents that need to be revived on a certain date.  This is a way to mail something to my future self so that I do not have to think about it again.

At this time, I have only a paper version of the Reminder File.  I am still trying to develop a digital version.

!! Project Files
This should be a file that contains all information relevant to a project.  With this, it should be very easy to take everything related to a project, put it into a file, and push it out of the way.  Then be able to grab a file, pull it out, and immediately spread it across my workspace in a big context shift.  All tasks that are related to a project should be listed right here.

Unfortunately, if the tasks related to a project are listed inside the project folder, it is harder to get them to the global task list.  Common wisdom is to put all of the project tasks with the project, and then transfer from the project to the global task list the next task that you want to carry out on that project.  I do not know how effective that will be, but it is something that I may one day try.

At this time, I only barely have a digital version of the Project File.  To some extent I sort of have a digital version.  The paper version is much clearer.  However, a major weakness in my life is that much of my life is digital and I do not use my folders.

!! Journal
Also a problematic section.  This is where I scribble what happened on any given day, as well as thoughts that I have not organized into any particular place.  The problem which arises is that once I have written a journal entry, there will be new ideas that need to be extract.  So, when I extract the idea into a organized location, do I delete the concept from the journal, or do I leave it there?

I am inclined towards deleting the idea from the journal.  A lot of the journal writing that I am doing now remains stuff that needs to be extracted.  A few journal entries are true self-reflective style entries, and those I should leave intact at all times.  But the ones that do no more than report what I did and what I thought up should definitely be refactored down to nothing more than a report of the outcomes of various completed tasks.

!! Archive
The final resting place for all information that I must keep.

In paper form, this is just an organized box into which I put all information that I will rarely need.

In digital form, this is a big pile of documents that are easily searchable.  I actually put all documents into the digital pile, as there is rarely any need to move a document from immediate reference to an old archive.  The absolutely most important part of this is that it is easy to search and easy to jump around within the pile.

I also have an email archive, scattered documents, and old web pages sitting around on my computer.  This is very annoying because they are disjoint from my active active archive, and so I tend to not search them at all.  I have the long-term goal of pulling in or nuking all information remaining in those ancient, dusty archives.

! Actions
These are the actions that actually piece together all of the tools into a coherent(ish) whole.

!! Ubiquitous capture
This is a pretty obvious GTD concept.

Capture and externalize everything.  I keep around my notecards in order to write down every single concept that I possibly can.  As a thought comes across, I want it written down so that it does not hang out in my mind.  If I cannot get it out of my mind, it will definitely continue to nag me.  It might, on occasion, remain in my mind and continue to nag me, but getting it written into a permanent form increases the likelihood that I can forget the details that can bog me down.

!! Inbox Zero
All of those inboxes that I have, paper, email, and notecards, need to get cleared.  Emptied.  Every single message in each one has to be processed.  Ideally, this happens every single day.

I had a recent incident in which, after several months of not being late on a single bill, I was late paying my cable bill because I did not clear out my paper inbox for something on the order of a week, and so the bill did not get organized into my reminder file.

Generally, though, clearing out all of the inboxes are a way of clearing the mind even further.  Until they are cleaned out, my mind constantly wants to go back and review what is in them and see if I need to do something about them.

!! Action extraction
Part of cleaning out inboxes is to extract the tasks that I need to do.  These tasks and events end up on my task list or my calendar, and anything else that I need ends up in an archive.

!! Review
As a final step, everything has to be reviewed on a regular basis.  My current review routine is still forming, as that requires a certain level of time management organization that I have not yet achieved.

Each day, the Reminder File, Calendar, and Task need to be reviewed.

The easiest the Reminder File review.  I need to do nothing more than pulling out the file for today.  Grab every message in that today's file, and that becomes a message that I need to deal with today.

On my Calendar, I simply note everything that is on my schedule for the day and any tasks that are scheduled to happen on that particular day.  Often I look later into the week to see if the schedule that I have for the week is still relevant.

Additionally, on my Task List I take a small set of Next Actions and note them as things to accomplish today.  Sometimes there is a theme, sometimes not.  But the point is to do this small step every day.

Then I create a journal entry and over the course of the day I note the actions I have taken, the decisions I have made, and certain outcomes of various things for the day.  The journal entry is just another document inside my digital Archive, though with very slightly different markup.  Since I am already in the digital archive, creating additional documents or adding information to existing documents is trivial.  It is just a quick jump to another part of the archive, and getting back to the journal is easy.

On a weekly basis, I should be reviewing all of my sections, but with a special emphasis on the Journal, the digital Archive, and the Maybe List.

From the Journal, I should be ensuring that I am extacting all useful information.  If there are any new tasks in the journal, those are important to pull out.  If there are any new insights, those are important for me to note.

With the digital Archive being an active reference, it is important that I review as much of what is in it as possible, and try to make it smaller by eliminating duplicate information.  If I have two documents on Alexandria (which I will discuss in detail in a future paper), then those two documents need to be truly unique, with references pointing to each other.  If concepts are duplicated between the two documents, then those concepts need to find a true home in one or the other.  Similar things need to be done across a lot of different documents, and the only way to do it at this time is to review the documents manually.

Manual review is somewhat slow.  It depends in large part on my skimming speed, but even if I manage to read all of the documents in my archive in a single sitting, there is no way that I can remember enough to make all of the connections.  Continuous partial reviews, and weekly larger reviews, are the thing to do; however I do not yet know of a good systematic way of doing either.  Generally, when I write something new, I search through my archive often for anything relevant or any duplicates.

! Conclusion
As I said... the first step.  There are even gaps in my system, places where things can still fall into the cracks and places where my routines need to get better.

Probably in the nearest upcoming articles I will discuss the fine details of the tools that I use, and ideas that I have for improving them.  I will also start trying to speculate on how to create the connections between my paper life and my digital life.

* [[Wikipedia: GTD|http://en.wikipedia.org/wiki/GTD]]
* [[Getting Things Done|http://www.amazon.com/Getting-Things-Done-Stress-Free-Productivity/dp/0142000280/ref=pd_bbs_sr_1/002-7740142-0097657?ie=UTF8&s=books&qid=1182811339&sr=1-1]]
* [[The Seven Habits of Highly Effective People|http://www.amazon.com/o/ASIN/0743269519/ref=s9_asin_title_1/002-7740142-0097657?pf_rd_m=ATVPDKIKX0DER&pf_rd_s=center-2&pf_rd_r=0GJ709FEPMZPQF5DZS4G&pf_rd_t=101&pf_rd_p=292858801&pf_rd_i=507846]]

<<tiddler JournalNavigation>>
<<tiddler JournalNavigation>>
Last week's post was very much about details.  It was not as detailed as I can get, and I will later get back and talk in extreme detail about several of the tools that I am working with.

One of the 7 Habits is "Begin with the end in mind".  I have alluded to the goal, to the big picture, but right now, I am going to talk about it in more detail.

My ultimate goal is twofold: make it easy to store and anything that I write and have the computer help me search for information related to what I am writing.

I am going to ground this in fantasy.  I have a world, which I named Alyra.  I started creating this world in 1999, and it has evolved over time, becoming more complex and more expansive as time passed.  At the very beginning of the project I started noticing an information management problem, where I wanted to have some things written, but people other than myself and my designated game masters should not know everything.  All of my passion into information management started from that simple problem.

! A Library
Building a library of information might seem straightforward.  In reality, part of it is, and part of it is not.  How complex this is depends on how you build it.

When the typical computer user creates a document, e opens a word processor or a spreadsheet, types out what e wants, then saves it and closes the program.  Sometimes e gives it a good name, and sometimes e files the document away in a folder of related documents.  Sometimes e does not.

This describes the simplest levels of file organization.  Not only is this simple, it is super-fast, easily accessible, and supported in all systems.

The problem comes when trying to find an obscure document in the distant past.  Perhaps the name or location of the document has been forgotten.  Either way, finding the document later can be hard unless the mind of the computer owner is highly organized and the files are similarly ordered.

When I create documents, though, I attach "metadata".  This amounts to various kinds of summary information about the content of the document.

For instance, I create a document entitled "Thrysha".  Thrysha is the name of a city in the Aetherean Empire, a highly magical realm ruled over by a rather benevolent priesthood.  Consider it a very peaceful form of the Minbari civilization (Babylon 5).  The document describes the city, the culture of the city, the government style, and maybe even the general layout.  For this, the metadata might include information like this:

{{{
Nation: Aetherea
Subject: Capital Cities; Aetherean Culture; Thrysha
Author: Savanninalkavir D'Generinel <savanni@alyra.org>
License: http://creativecommons.org/licenses/by-sa/1.0/
URL: http://www.alyra.org/~markus/guid_getter/20070627110700CDT
}}}

This is a pretty basic set of metadata.  The first two lines, Nation and Subject, would be useful in all instances.  The additional three lines, Author, License, and URL, are useful primarily in publication.

By stating that this document is related to the nation Aetherea, and that the document is about Capital Cities, this makes it easier for me to later ask the computer to search for all articles on "Capitals Cities".  I could further restrict the search to match only documents related to the Nation Aetherea.  The resulting set of documents would be far more manageable than digging through all of the documents that are related to Aetherea, or digging through all the documents related to capital cities, or digging through a list of of documents that are differentiated only by name.

In addition to making searches, easier, this metadata makes listings easier.  Sometimes the correct information is just a list of all documents related to a particular piece of information.  A search for "Subject: Capital Cities" would list off all documents in the library that describe capital cities.  A search for "Subject: Thrysha" would list off all documents related to Thrysha, assuming that a cluster of documents was necessary to adequately describe a city of 50,000 people for storytelling purposes.

Everyone who has spent time in an older style library is familiar with metadata.  The concept has been around in various forms for centuries.  Immediately before libraries became computerized, all of the metadata about all of the books in the library were stored on index cards in the card catalogues.  Author, Title, Subject, Dewy Decimal number (if one existed), and an all-important "pointer" to where it is stored in the library.

iTunes is famous for metadata, throwing all music into one big list and then allowing searches based on any criteria (Artist, Album, Bitrate, Genre) and sorting by any of those criteria.

The entire point of metadata is to make searching more accurate.  More accurate searches are always easier to manage, but there is more effort that must be put into the initial search.  Google only to a small extent handles metadata, so all searches are easy to type but search the entire content of a document.  This usually works, but when it does not, the searcher is deluged with a huge pile of documents that may or may not be related to the original intended search.

Agents can also run in the background, searching documents for patterns.  Given some analysis, some of those agents can search a group of documents and two documents may relate to each other but that there is no metadata to indicate that.  Such agents have to be very intelligent, or know how to exploit the statistical frequency of words in the language of the documents.

This involves some advanced statistical analysis.  I have read about the algorithms and even played a little with them, but they are currently beyond my understanding.  I will write about them some time later when I understand them well enough to present on them.

! Going Outside My Library
In addition to everything in my library, I sometimes want to go outside my library.  At this time, the most common way of doing this is to go to Google and search.  A short time ago, however, I described the weakness of this method.

Again, this is where metadata can be helpful.  Searching the web should, in theory, be as easy as searching my own library, but without the additional metadata searching, it is not.

Fixing this problem in the general is far beyond the scope of my capabilities.  It is highly complex, requires a huge amount of hardware, and then would involve overtaking Google as the best search engine in the world.  Not likely... I could start on such a project, and Google would beat me to it by years.

I can, however, solve this in a small case by looking at Livejournal, Zaadz, LinkedIn, or any other social networking site.

Here are the steps...

# devise a way to track my social network without depending on a third party system
# devise a way, probably a small set of programs, to publish selected parts of my work to selected parts of my social network
# convince other people in my social network to do the same, maybe with different programs but with some agreed-upon protocol
# enhance my (mythical) agents to search the published documents of other people in my social network

The means of doing this is an ongoing research problem in my case.  The consequences of doing this are simple, but could yield some outstanding results.

First, I may be providing a fairly simple little publication system.  All of my friends would have to find a place to run this publication system, but it would still be present.  If done right, I could make self-publishing web pages easier than it has been in the past.  Admittedly, Livejournal is probably easier, but I go on the premise that Livejournal is not trustworthy.

Second, once the publication system is running, each person is publishing not just text, but text that agents can to some extent "read".  If several people doing this sort of publication know about each other, they can all point their agents at one another.  One possible function of an agent might be to just collect everything that my friends publish.  Another might be to collect pages that reference one of mine, like a comment feed.  I publish something, then a friend pubishes a response and my agent detects the response and shows it to me appropriately.

Each one of us can hold a Library of information, but our agents can crawl our libraries and present higher levels of structure.  Properly tuned agents will be crawling specifically for information that I am interested in, presenting that information in whatever context it can find.

The point of all of this is to get the computer to assist me.  It will help me collaborate with my friends, but it will also filter down the huge amount of information out there into something that I can easily sort and analyze.

The ultimate goal of all of this is a system that I call Alexandria.  I am still creating and revising the specifications for Alexandria, writing experimental code, and writing impressive-looking web pages that point to too much work.

I do not work on this in a void.  In future articles, I will discuss some of the work that other people are doing to make this all a reality.

* [[Web 2.0|http://howtosplitanatom.com/news/how-to-talk-web-20/]]
* [[Web 3.0|http://howtosplitanatom.com/news/how-to-search-web-30/]]

Questions, comments and feedback to me at savanni@alyra.org.  Please let me know what you would like me to write about next.  Possibilities are:

* Modern Collaboration Tools -- Livejournal, Data Silos, Zaadz, RSS, Email, IM
* Metadata -- Dublin Core, RDF, Internet Text Messages
* Living In One Text File -- Two, really.

<<tiddler JournalNavigation>>
<<tiddler JournalNavigation>>
In a previous article, I made reference to my "Archive".  This article is concerned entirely with the Plain Text aspect of my digital archive.

! Plain Text
Text mode and Binary mode are two different modes that have almost no meaning in the computer any more, but which have a great deal of meaning for human users.  Historically, the text vs. binary modes existed only on DOS-based computers, but later versions of windows have either thoroughly hidden or completely discarded the original technical difference.  At this time, only the human factor retains any meaning.  Roughly, "text" is anything that can be manipulated very easily by unaided humans.  This is typically unformatted data that looks like ordinary words and numbers to us.  When we are working in "text mode", we are typically altering a document one byte or character at a time.  "binary" data is very different.  This would be something like an image, some music, a scene description, a word document, or a video.  All of these represent a huge amount of data, but more importantly, the raw data is almost meaningless to us.  Specialized programs are necessary to turn a long stream of numbers into an image or a song.

Text is the most universal of all media.  For those readers using the English/Latin alphabet, the encoding of raw machine data to the glyphs that we can read is the same across all computers that we are likely to encounter.  It is so simple that the encoding scheme was completely changed once several decades ago and is currently going through a more important, but less drastic migration.  The discussion of the migration from ASCII encoding to Unicode is huge, complex, and far beyond what I will discuss now.  English readers may assume that there is no difference between the two, and therefore there is no risk of losing data.

Binary data does not get the title of "universal".  For the sole purpose of storing an image, we have encoding schemes called JPEG, GIF, PNG, TGA, and dozens more.  Not all programs properly interpret that information correctly.  Formats fall in and out of favor.  Patents liabilities suddenly get enforced, leading GIF to fall greatly out of favor on the free/liberty side of the Internet several years ago.  This is particularly true of Word documents.  Every version of Microsoft Word produces a new encoding which previous versions of Word cannot read.  Applications other than Microsoft Word may or may not be able to read the documents.  Later versions of Word may not be able to read documents created with early versions.

So, for purposes of universality, I work in "plain text".  For now.  I put all of that text into a single large file.  This effectively means that all documents that I have written are all stored in one place  (Please ignore, for now, that I actually have documents scattered around in old systems that I have abandoned).  The advantage of this is that once I have opened the file finding the document that I want is a simple search.  With just a few keystrokes ("/Title: Living in one Text File") my cursor can jump directly to there and I can begin working.  A thing to note is that I find that the task of searching through lots of different files in order to find a particular piece of information is an unpleasant task, is time consuming, and actually impedes me from finding whatever I am seeking.  I find this to be the case even though I have tools on the GNU platform that specialize in searching plain text documents quickly.  With those tools I could actually search multiple files at once, but it is less efficient: once I find the correct file, I then need to open it in an editor and actually repeat the search, unless I have managed to integrate the search tool with the editor.  Doing so is possible, but beyond the scope of this document and the scope of my own knowledge.

! Format
In my case, I have decided that as I add information to this file, I also impose some order.  This is not strictly necessary, and different people will want different levels of order, both more and less than what I use.  I use a rather simple format for organizing the file.  In part, this makes it easier for me to visually see the various sections in the file, but this also makes it easy for me to write programs that can process the file.  I will take some time to describe this format and the justification for it.

At the highest level, every "document" begins with a single line which contains eighty "-" characters.  That line must, by definition, begin at the beginning of the line with no spaces at the beginning.  Visually, I instantly see the ending of a document.

Within each document are a header and a body.  The header consists of several name/value pairs that describe the metadata of the document.  It is then followed by a single blank line and the body begins.  The body itself is free-form.  If any structure is imposed to it, that structure is not going to be covered here.

To ground it all in reality, this article begins like this:

{{{
-----------------------------------------------------
Title: Living In One Text File
Journal: PKM Unpublished
Guid: 20070710103922CDT
Subject: Personal Knowledge Management; One Text File
License: http://creativecommons.org/licenses/by-sa/1.0/

In a previous article, I made reference to my "Archive".  This article is concerned entirely with the Text aspect of my digital archive.
}}}

The header for this particular article contains five different pieces of metadata: "Title", "Journal", "Guid", "Subject", and "License".  These are five different ways of classifying and describing the content of the document.  The format is derived from a truly ancient format called [[RFC822: Standard for the format of ARPA Internet text messages|http://www.faqs.org/rfcs/rfc822.html]].  This is the format used for all email messages, all newsgroup messages, and is the foundation for the format of all HTTP (web) messages.  If you tell your email client to show you the source of the message, you will see a very large number of these headers at the top of the message, though the names of the headers will be different than the names I used here.

Formally, my format is subtly different and certainly more restrictive, than standard RFC-822 format.  It can be describe as thus:

{{{
<section>     := <divider> \n [<header>\n]* \n <body>
<divider>     := "-" * 80
<header>      := <field-name>: [<field-value> ";"]*
<field-name>  := Any letter, number, "_", or "-", but no spaces, \n, or other punctuation
<field-value> := Anything except a new line
<body>        := anything except a <divider>
}}}

The changes that I have made from the Internet standard are borne from some very painful experiences of trying to write code that can handle true RFC-822.  The standard leaves much to interpretation, and many applications do not actually emit content which follows the standard.

Finally, as I said before, the structure of <body> is not defined at this level.  This allows for multiple levels of processing.  What I mean by this is that a program can parse the entire file into a list of Sections (as I call them).  It can then pass the body of each section to other programs that know how to process the format hidden within the body, such as a Wikipedia to HTML conversion.  Nested processing like this allows each processor can be specialized for one particular function and there is no need for the processor to be intimately familiar with all possible aspects of a system.

! The Format of An Article
The content of this article is very plain, but it is similar to the Wikipedia content.  I am not using anything like the full extent of the Wikipedia format, and I am abandoning it for whatever looks good in plain text, but the basics are there.  If I wanted to do automatic conversion of this article from this from to HTML, I would be very strict about the format.

! The Format of a Task List
The section which contains my task list has a different, more rigid format.  Here's an example:

{{{
N +stillpoint @offline                  Add the track transitions table to the schema
T +pkmWeblog @offline                  Write "Living in One Text File"
M @online                               Re-read the [DIY Ginormous Whiteboards] instructions
}}}

My task list is a big list of tasks.  The very first letter on the line is a character that indicates the task's current status:

* N -- next action, can pick this one up at any time
* T -- work on this task today
* M -- maybe one day
* W -- waiting for something

After the letter is at least one space, then two fields, both of which are optional, to indicate both the project that the task belongs to (+stillpoint, +pkmWeblog), or the context in which the task can be done:

* @offline -- no Internet connection but probably my laptop
* @online -- Internet connection required, or working on my server which is always on an Internet connection, often the other end of my Internet connection
* @home -- have to physically be at home
* Several others.

Then, a whole bunch of space and an actual command for what to do.  I am actually not so good at writing tasks, but I am getting better at making them actual statements of task instead of some vague goal.  The details of writing a task list are better covered by the GTD system, and the details of deciding what to do next are better covered by the 7-habits system.

The emphasis here is on a human-readable task list.  I do not have any programs that modify the list for me, so I have to be able to modify the list in my own text file.  I have some programs that will list out just some of my tasks based on what is most useful to me at any given time.  If I want to see only tasks that can be done "at work", I ask one of those programs to list tasks that are New or Need to be Worked On Today, and can only be done @work.  Using really basic GNU tools, this is easy:

{{{
grep -i "^T " todo.pim | sort | grep "@work"
}}}

These are all standard GNU tools.  "grep" is a search function (Globally Search for a Regular Expression and Print).  "sort" sorts all of the lines of an output alphabetically and by number.  The vertical bars are anonymous pipes, unnamed structures which allow the output of one program to be fed into the input of the next program in the chain.  So, the first command in the chain searches through the files "todo.pim" for every line that begins with a T (today's tasks) and prints the result to the "screen", but that "screen" result gets captured by the pipe and "piped" into the function to sort the lines.  The output of that then is piped into a grep which will emit only those lines that contain the "@work" context.

These tools, and others, can be recombined in a myriad of ways.  These are extremely common tools, and they all contribute to the tendency on the GNU platform to work in plain text.  Plain text is easy for humans to read, and GNU has many tools that are optimized for processing plain text.  In addition to grep and sort, there is also awk (split a line into fields) and sed (do inline replacement based on regular expressions).  The use of all of these tools is detailed in many other places, and some google searching should reveal several sites dedicated to recipes for chaining the tools together.

! Gardening
I have no better name for this term.  Gardening is all about browsing through the information, reorganizing information so that related bits are close together, and pruning parts that are obsolete or redundant.

No matter how advanced the organizational system is, some of the data is going to get old and stale.  I have old information about a game I will never get the chance to play, organizational notes for a dinner which has long since passed, and scattered pieces of information about Buddhism and about Aikido.  I have actually duplicated the same task several times on my task list, but did not realize it because I worded the task significantly differently each time.  Much later, I will be pruning my task list, browsing categories, and notice tasks that I completed long ago.

On occasion I need a summary of what is present in my system.  I need to examine that summary closely, looking for things that are no longer important in any way, or things that I have written more than once.  Getting this summary involves building tools that can distill information down to a minimal amount, however information always gets lost in distillation.  Nothing ever completely replaces simply going in and reading the documents that I have written, but extra computer processing can help me figure out exactly where to look.

Deleting a duplicate document is easy.  Merging two documents is very difficult for me.  Say I have two documents that list tasks for working on the Vretil project, one document that looks in detail at a couple of portions of the tasks, and maybe two documents that discuss how a task list application needs to work (Vretil being the code name of my great information management architecture, as opposed to Alexandria which is "just" the storage database).  This is a real scenario that arose because I forgot that I ever wrote anything on these topics before, and so I wrote more about them.

The first step is always to decide where all of the data should live.  As it turns out, none of the documents belongs in my system, but they all need to be processed.  Because Vretil is a programming project, all documents related to it ultimately need to be put into a documentation section of the project.  This makes things more complicated, because theoretical concepts may originate with the rest of my PKM system and then have to be extracted out to the project pages.

Once that is decided, the above documents should merge into a single task list, links to additional documents for discussing the details of individual tasks, and a summary page for how the application should work at a high level.  After that, it is simply a matter of picking apart pieces of information and putting them into their final resting places.  This is also hard, but it is only marginally different from composing a formal research paper.  Avoid redundancy, make sure everything sits in a place where it clearly belongs, create new "locations" as the need arises, and delete locations as new locations supersede old ones.

! Conclusions
I have several pieces of inspiration for this and how to make it all work.

* [[Living in One Text File|http://www.oreillynet.com/pub/wlg/7567]] -- inspiration for even trying this
* [[Why plain text|http://todotxt.com/whytxt.php]] -- ideas for how to format a todo list
* [[DCMI Metadata Terms|http://www.dublincore.org/documents/dcmi-terms/]] -- some good suggestions for titles to use to describe my metadata
* [[Text Processing in Python|http://gnosis.cx/TPiP/]], [[RFC822|http://www.faqs.org/rfcs/rfc822.html]], and living in email -- all inspirations for the header format that I am using

This system is working well.  I have been using it for only a few months, and it will continue to serve me for some time longer.  I do want to migrate to something more advanced, something which I will discuss in the future, but I can live with this for now.  My huge goal is to find all of the old documents I want to keep and pull them together into this system.  Fragmentation is a huge enemy, because it requires that I search in many places to find what I want.

One day, however, I want a database system that allows me to truly treat each document separately, especially for publication purposes, but still allows me to work as fluidly as I currently do.

<<tiddler JournalNavigation>>
<<tiddler JournalNavigation>>
Moved all of the books, games, and junk from the library last night. That took a really long time... a full hour at least. Then removed most of the furniture. All removed items are now cluttering up my living room. The huge bookshelf/entertainment center I moved into the center of the room with the help of these amazing sliding disks/casters that are something like three inches across.

Tonight I will move the 20-gallon aquarium out of that room and lay down dropcloths.

I have decided to not worry about the ceiling popcorns for now. Maybe some time in the future they will drive me crazy, in which case I will look into having them removed. Maybe even by a contractor. Until then, though, my ceilings will remain popcorned.

! Task List

* +paintLibrary @home Move aquarium
* +paintLibrary @home Tape the trim and put down plastic
* +paintLibrary @home Pull down blinds
* +paintLibrary @home Tape window frame
* +paintLibrary @home Paint walls
* +paintLibrary @home Uncover trim
* +paintLibrary @home Paint trim

<<tiddler JournalNavigation>>
<<tiddler JournalNavigation>>
Finally got the aquarium moved out of what used to be the library. It took quite a while to do that, and in the process I discovered that, as I was not paying attention, the biosphere of the aquarium has essentially crashed. Oh well... I am paying attention again and so it will probably recover. There were one or two tiny little mushroom corals left, and they breed like weeds. It is now set up over near the other marine aquarium.

I pulled out several more things that show to me just how half-assed one of the previous owners was. There is a phone line that runs around the outside of the house to the front of the house, down the front from the second floor, and then through a hole that was drilled through the rock all the way into the library. It then went into a small box attached to the baseboard, and a new phone line came out of the box, ran under the carpet, and then came back out in another side of the room.

Yeah... half-assed.

I do not really like hack jobs like that, so I would have actually run the line into a real wall panel. Maybe, now that I know how to do it, I would have cut out some of the sheetrock to run the wires around.

Anyway, that has been removed and the hole plugged on the inside. I do not yet know how I am going to plug the hole on the outside. Come to think of it, the cable company did the same kind of thing, but I think there is actually a wall plate there.

Anyway, a candle next to the wall had dripped some time in the past and it got some wax on the wall and a lot on the carpet. I removed it from the wall as best I could, and then looked at that and the spackling jobs, and I have decided that I am going to prime the walls before I paint them. I think they need it in order to smooth out the oddities.

Last thing I did was to tape all of the trim and take photos. Taping all of the trim took about 30 - 45 minutes, which is really much longer than I expected. The room is not really very large. Still, it is done and I have a better feel for how long it will take for me to do the other rooms.

I cannot post the photos yet due to broken software, but I will do so soon. The laptop is busily upgrading all of my tools today.

Dropcloths. I am nearly frothing at the mouth to get dropcloths down!
Task List

* +paintLibrary @home Paint trim | waiting to uncover the trim
* +paintLibrary @home Paint walls | waiting to prime walls
* +paintLibrary @home Prime walls | waiting to put down plastic and to pull down blinds
* +paintLibrary @home Uncover trim | waiting to paint walls

<<tiddler JournalNavigation>>
<<tiddler JournalNavigation>>
Dropcloths are down. It took a very long time to get that done, and they are not even really sticking to the floor. That bothers me a lot, but I think it will hold. When I do the trim, though, I imagine that I will be re-taping the floor.

Anyway, paint hits the walls tonight. I have decided not to prime the walls because they are already white and I was able to sand down the rough spots that I made when I spackled.

First and second coats can both go on tonight. Tomorrow night I can paint the trim.

Roxxor!
About the Paint and Color Scheme

The paint I am using is the Freshaire Choice . I am not sure about the details of all the ways it is good for the world, but I do know that it has no Volitile Organic Compounds. This means very little smell and no toxic outgasing. I am personally getting quite on board with making my house less toxic.

The paint colors in the library will be Ancient Rosewood for the walls and Poetic Light for the trim. The ceiling is not getting painted because I do not want to deal with painting over or removing the popcorns at this time. The new blinds are going to be real wood blinds and will be some color that goes well with the rest of the room, though I do not yet know what color that will be.

I would like to see the popcorns gone, but I need to have them tested for asbestos before I even begin to rip them out. Then, from what I read, the process of ripping them out is long and time-consuming, even if they have no asbestos in them. That is not worthwhile at this time. Maybe another time, but not for this set of painting.

! Task List

* +paintLibrary @home Prime walls
* +paintLibrary @home Paint walls
* +paintLibrary @home Paint trim | waiting to uncover the trim
* +paintLibrary @home Uncover trim | waiting to paint walls

''update'': in talking to co-workers, I have found that I actually do need to prime the walls. The dark paint on white walls will end up not saturating and I will need many layers in order to get the desired color.

<<tiddler JournalNavigation>>
<<tiddler JournalNavigation>>
Paint is on the walls. The room now has dimension and personality that white paint could never convey to it. "Wisdom", by Nene Thomas do a Google Image search belonged in that room before I painted it. Now, It Was Made For That Room!

I so much want to show you all pictures, but my gallery software continues to spite me. Not to worry. I am working on it. Slowly.

I opted out of the primer. Apparently there are no tinted primers for the Freshaire paint, so any primer that I added would get me away from the non-toxic-non-aeromatic goal that I had for this project. I still bought a can of white primer for some of the rooms that need to be PAINTED OVER *GAG* . I got home and then I went at the walls.

First coat is on. Wow, it looks incredible. Amazingly so. The second coat will make it even better as I fill in the spots that the roller missed.

So, I plan to get the second coat on tonight and the trim done tomorrow night. Sunday, if I am happy with the results, I will put the room back together.

! Task List

Largely the same as yesterday because I still need to put on a second coat:

* +paintLibrary @home Paint walls
* +paintLibrary @home Paint trim | waiting to uncover the trim
* +paintLibrary @home Uncover trim | waiting to paint walls

<<tiddler JournalNavigation>>
<<tiddler JournalNavigation>>
The ~Library-Office is now finished.

Friday night I did a second layer of paint on all of the walls. This filled in a lot of the places where the paint was showing through, but in retrospect I think I would have spent my time better filling those in with a paintbrush. I think I will get a thicker roller before I do any more dark rooms of the house. The light rooms will probably not matter as much.

I did the trim when I got home Saturday night. Window sill, window frame, baseboards. The baseboards were a real serious pain, but I think I learned about about how to do them. The tape on the ground is incredibly helpful. Dropcloths do not need to be everywhere or even taped to the ground. Just move them in to wherever I am working. It is the tape itself that is on the ground that will help. Taping the trim around the baseboards was not so useful because the paint slipped up underneath the tape and back onto the walls.

I have a straight edge on a handle that I used some in this, but maybe not to full advantage. I will use that more on the next room and post about the results.

Sunday morning I spent doing final touch-up and there are *still* little white dots on the walls . Then I spent some time measuring out the room and the furniture and arranging it all on paper and finally started moving furniture into the room. That room is now both my library and my office. There is currently no storage at all in that room, so I am going to go look for baskets, maybe at the Container Store, that I can use as drawers and put on my bookshelves.

It is very, very nice and I am quite happy with the results.

NEXT ROOM!!!

<<tiddler JournalNavigation>>
<<tiddler JournalNavigation>>
The dust has only barely settled from me painting my ~Library-Office. Now, I am already at it again.

My meditation room is the second room in the house to get painted. This room was actually kind of urgent. Shortly after I moved in, the cats marked the room in a few places and I was never able to get the scent completely out. With that in mind, I ripped out all of the carpet, carpet padding, and the carpet frame last month, stripping the room down to floorboards. Then I let it sit for a while, because my guidance was to get the ~Library-Office done first.

As soon as that was done, though, my attention turned back upstairs. Tuesday night, I finished changing out the outlets and switch in that room. For those of you who do not know, when I moved into the house not one of the outlets could actually hold a plug. Since then, I have been replacing outlets. But the regular beige color is not enough, so it has been the black outlet, black switch, and brushed metal plates that you saw in my ~Library-Office.

Wednesday night, I got up there with a mop and full-strength pine sol and I scrubbed the room. The house still smells potently of pine sol, but I have gotten used to it and cannot smell it at all.

Tonight, I got in there, taped the trim, and with a bit of help I got the walls painted. The whole job is very fast because I do not have flooring in there that I have to protect.

Tomorrow night I will do the top of the walls. I left those undone tonight just because of the amount of effort involved in painting into the corner between wall and ceiling. I will also get all of the places that did not get full coverage.

This time, though, I provide pictures from the beginning! .

! Task List

* +paintMeditationRoom @home Paint the trim and doors | waiting to uncover the trim
* +paintMeditationRoom @home Uncover trim | waiting to paint walls
* +paintMeditationRoom @home Paint the tops of the walls
* +paintMeditationRoom @home Recover areas of inadequate coverage

<<tiddler JournalNavigation>>
<<tiddler JournalNavigation>>
The meditation room is not quite done, but it is close. I just need to pull up the last of the tape and then photograph the results.

However, last night, I got motivated at 10pm, put down some dropcloths, and painted the entryway of my house. Photos here .

I am convinced that this house work, this transformation of my home, is an external metaphore for something going on within me, but I have not yet figured out what it means.

! Task List

* Pull up the trim tape in my meditation room
* Put on a second layer of paint in the entryway
* Paint the trim in the entryway

<<tiddler JournalNavigation>>
<<tiddler JournalNavigation>>
Congratulations to all of us here in the United States for finally electing a new presidential regime!

My voting life is not that long.  The earliest election I was able to vote on was the Dole/Clinton election.  This, however, is the first time when I got to vote for somebody I liked, as opposed to the normal routine of just voting for the person I could tolerate the most.

Now, the first thing to really keep in mind for the newly elected President and the newly elected Democrats in Congress is that apparently the American people really will get pissed off and vote out any even related to a regime that they have decided to hate.  So, play nice, get the job done, but do not piss off reasonably level-headed people in the process.

This also marks the beginning of a new public journal.  I do not know that anything will be important in this one, as my real work remains in topic specific journals.

For the gamers in the audience: http://media.1up.com/media/03/6/4/3/lg/201.jpg?r

<<tiddler JournalNavigation>>
<<tiddler JournalNavigation>>
Anyone want to hang out with me Saturday morning/day while I finish off two rooms in my house? Just sit there and chat with me, no work needed on your part. And have 911 ready in case I switched off the wrong breaker before touching the wires.

<<tiddler JournalNavigation>>
<<tiddler JournalNavigation>>
Friday, 5pm to 1:45 am: Moved paramour out of her apartment.

Saturday: Had car worked on.  Bought and started reading Tantra manual.  Painted and changed outlets.  Dinner and religious conversation with other paramour.

Sunday: Painted and ''more'' changed outlets.  Moved roomie into house.  Many minions yielded a two-hour unload.  Did not even have to participate in the heavy furniture.  Affectionate feline purrs in bed.

So sore I abandoned plans to cycle today.

<<tiddler JournalNavigation>>
<<tiddler JournalNavigation>>
I attended the Board Game Geek Convention over the weekend and played so many games that my brain pretty well turned to mush.  I do not think I could learn a new game right now if I tried.

There were some games that I saw over and over and over again.  Further, cooperative games were really popular throughout the convention.  I have also heard that there are more cooperative games in line for publication.  I am feeling a shift in the gaming industry, and it may be a shift in the overall culture, towards lower competition and greater collaboration.  Perhaps this is because our culture is growing up, perhaps it is because older souls are now coming of age and forcing our culture to grow up.  I am not sure which.  This change pleases me greatly.

Here is what I played.

! Antike
I last played this one several years ago, and then I spent three years trying to remember its name.  This is a game much like Civilization, but without a huge amount of waiting and downtime.  Turns are quick and involve lots of small actions, and the entire game plays in one to two hours.

I am very fond of this game.

! Battlestar Galactica
This is a cooperative game, but like ''Shadows over Camelot'', there is a traitor somewhere.  Generally the game plays out with each player taking an action, then drawing a Crisis that changes the game state, such as a crisis that warps in a Base Star and some fighters that begin attacking.  The goal is to make a certain number of hyperspace jumps to arrive at a new homeworld before the Cylons destroy the ship.

There are many different possible defeat conditions.  With one traitor guaranteed in the first half of the game, and a second guaranteed in the second half, the game is decided stacked against the players.  ''Shadows over Camelot'' was difficult, but this is even worse.

I also found this to be an excellent game.

! Tinner's Trail
This is a game about mining for copper and tin in north England.  There is a time-based game mechanic in which you can take various actions to acquire or prospect for new mines, remove water from the mines, and actually carry out the mining processes.

I generally did not like this one, but we also got very unlucky.  Almost every mine at the beginning was flooded with water (which drastically increases the cost of mining), and every mine that I prospected was totally filled with water without any resources at all.

! Ghost Stories
Another magnificent cooperative game.  This is set in a Japanese-style village that is being seiged by ghosts.  On every player's turn, a new ghost appears.  It is then up to the players to go to the various locations and destroy the ghosts before they can do much harm.  Late in the game, one Super-Ghost appears.  At that point, there are a total of ten turns to kill the super-ghost before the players lose the game.

This one is supposedly exceptionally difficult.  We found that there was one rule that we did not obey correctly, but do not think that would have made it hugely more difficult.  My thought is that we chose a very good combination of special powers and then worked together very well to eliminate everything.

I tried to purchase this one, but it was so popular (I saw it *everywhere*) that the sellers ran out of it in their first day at the con.

! Supernova
Each player takes the role of a galactic civilization that is trying to establish itself in an exodus away from their original homeworld before their star goes supernova.

This was an interesting concept, but we all found that the random elements made any kind of strategic planning a little too difficult.  There was also a mechanic in the game that allowed the player in the lead to accelarate that lead, with almost no counter-balancing mechanic.  Finally, about halfway through the game, gameplay started to drag so badly that we all decided to call it quits, and this was three hours in.

! Agricola
This farming game is currently considered, quite rightly, to be one of the best games out there.  The neatest thing about it is that every game plays differently, the game scales from one to five players, and the number of players has a huge effect on how the game plays out and the strategy that every player must take.

You start the game with two family members, a two-room wooden hut, and a plot of land.  You then have fourteen turns to build up your farm.  During the game you will encounter six harvests in which you can harvest your fields, kill your farm animals for food, and feed your family.

In each turn, there is a certain set of actions available.  Each player takes turns acquiring actions, as each action is only available to one person.  Since you start with two people in your family, you get two actions.  You can always have a strategy in this game, but sometimes you must adjust your strategy very drastically because somebody before you just took the action that you needed most this turn.  That provides the first big pressure.  The game is paced so that you cannot really grow your families faster than the number of actions grows, but even late in the game it is possible for the actions that you need to be taken by someone else before your turn comes around.

Food is the other big resource crunch in the game.  At harvest time, you must have a certain about of food for each family member.  If you do not, you have to beg and that costs a lot in already scarce victory points.  Making matters worse is that you start the game with no way to produce any food but grain, and you cannot even turn grain into bread until you can buy a fireplace or oven through the "Major Improvement" action, and major improvements are not available before the first harvest.

So, it is a very tight game of trying to eek by on very limited resources while still scoring victory points at the end of the game.

! Pandemic
A very fast cooperative game in which the players are trying to cure four diseases before they wipe out humanity.  This game plays in as little as ten minutes and as much as fourty-five minutes.  It is quite possible to lose very quickly if the wrong cards turn up, but the game is not totally impossible.

This game has several big crunches.  First, on every player's turn two new instances of a virus will show up.  Second, if there are already three virus markers in any given city, a new one causes an "outbreak", in which the virus spreads to all adjacent cities.  The "outbreak track" measures the number of outbreaks, and the players lose at nine.  In an outbreak, it is likely that one outbreak will actually trigger a second in an adjacent city that is also badly infect.  This can hurt very badly.  Finally, you still have limited time before your resources run out.

I found this to be my favorite game and played it three times while there, then picked up my own copy.

<<tiddler JournalNavigation>>
<<tiddler JournalNavigation>>
For any of you who are curious, my spirituality falls along the lines of energy work and whatnot.  Here is how I currently look at part of it, specifically my chakra system, and how I relate to it.

I actually wrote this for Terri today to explain a few things to her, and I have now edited out parts that are not for general consumption.  The colors that I associate at each level have deviated somewhat from the standard system.

* Base -- dark red, associated with survival and basic needs, and also the chakra that grounds me.
* Sacral -- orange originally, but migrated entirely to green. I have expanded this to be about pleasure in general, but sexuality still dominates it. It is also, in true keeping with me, tied very tightly to my heart.
* Power -- bright yellow for me. Quite underactive. This is from where my assertiveness needs to originate.
* Heart -- Both green and pink. More pink these days than green, but I actually get both colors when I activate it. This is also the most active and most open of all my chakras, and it is always an integral part of lovemaking or healing.
* Throat -- Sky-blue in color. I still associate this with all forms of communication.
* Third Eye -- Indigo in color, and I associate it with magickal sight. Usually this one is quiescent in me, because most of my work is of a healing or pleasure nature, and those come from other places in me.
* Crown -- White, still associated with my connection to the higher spiritual world, and also the connection to the chakras above my body.

<<tiddler JournalNavigation>>
<<tiddler JournalNavigation>>
[[I read.  A lot, but not as much as some people.|Books]]  I rarely tell people what I am reading, but sometimes I cannot avoid just talking about what I have most recently read.

However, a lot of what I read is in audio form, so it is really more a matter of someone reading to me while I carry out my normal life.  Like painting.  There are rooms in my house which I can enter and instantly remember what I was listening to at the time I painted said room.  It is quite an interesting way to live.

Anyway, I figure I will also review the ones that I find most interesting.  For the next few days, I am going to make journal entries reviewing some of the most recent books that I have read.  If you have a request for my opinion on anything in particular, let me know and I will write something up.

''Just note that I am not a professional book reviewer.''

! Desire: The Tantric Path to Awakening (Daniel Odier)
I am still processing this one.  This book teaches Tantra largely as a philosophy for becoming so aware of everything around oneself that joy and pleasure are inevitable in everything involved.

I often felt that the book focused on the greatness of the feminine and relegated masculinity largely to irrelevance.  There is some caveat to it, indicating that neither feminine nor masculine energy is dictated by the form of the body, and that a person can shift from one to the other with proper awareness.  This still feels uncomfortable to me, but it parts ways from most spiritual traditions that treat one sex as absolutely superior to the other.

This is a very theoretical book.  My feeling is that there is not much in directly practical practice, but the book also comes from the perspective that once you have awoken to everything around you, there is no need for any additional practice.  This is probably a good path for people who have a lot of tools for inner work, but as such it is not all that useful to me.  For now.

! The Michael Handbook
Whether you read this book or not is pretty much dependent on what you feel you believe in.  The part that most people will probably have trouble with is the idea that all of the material in this book is channeled from a being named Michael.  This being is actually a cluster of roughly 1000 souls that have all completed their time on earth.  I believe that this is true and that the teachings in this book are helpful.

The basic assumption in this book is that each of us is a fragment of the Tao.  Even Michael is just a fragment.  We have almost all lived before, in that we define "life" as incarnate in the physical plane.  We will almost all live again.  There is a cycle of experience that we, as fragments of the Tao, are all trying to learn and to bring back to the unified whole of everything.  This "universe" is a construct put together as part of a game that we are playing with ourselves.  The game is "let's split up into a whole bunch of pieces who operate on the illusion that we are truly separate, and then see what experiences we can have as try to see past our own illusion."

This does not cover much of the book, but it is the baseline.  The rest of the book is about understanding the various personality traits we take on and how they impact our entire lives.  It is also about understanding how to make the most of those personality traits, how to understand what traits other people have taken, and so an understanding that everyone else is largely going through the same process we are.  Finally, it also emphasizes that whatever traits we ended up with, we took those traits to work with the karma we have already created or to create new karma specifically so we can have a particular set of experiences in this life.

I found this book to be relatively useful and very easy to understand.  It feels true to me, though it may seem worthless to other people around me.  Your mileage may vary.

<<tiddler JournalNavigation>>
<<tiddler JournalNavigation>>

''I am not a professional book reviewer.''

I finished this book about a week ago.  It is relatively long, but is for me an easy read.

The book is largely divided into two sections and alternates between the two.  Connie is the common element between them.  In 1976, she is in an asylum, treated very poorly, and subject to the latest in crackpot medical experiments.  At the same time, she is in psychic contact Luciente, a person in 2136 or thereabouts.  She makes periodic near-physical visits to that time and learns much about them.

Much of the interesting part of the book is about contrasting the horror of the asylum against the seemingly ideallic 2136.  I say seemingly because Luciente, her guide in that time, does explain the problems that they still face: the luxuries that they cannot have, the work they still have to do to reclaim the land destroyed by our civilization, and the war they are fighting against another civilization that is the totally horrific outcome of a totalitarian regime.  We spend blessedly little time actually looking at that other civilization.

It is an amazingly idealistic civilization, even with the problems they still face.  I felt that the people of Mattaiposette were rather annoyingly naive about how society could work any way other than their way.  The depiction of the society was actually a little heavy-handed in its idealization, though that can be forgiven considering the nearly collapsed society that Connie lived in even before going into the asylum.

[[Key attributes of Mattaipossette|Mattaiposette]]


<<tiddler JournalNavigation>>
<<tiddler JournalNavigation>>
This entry is temporarily gone.  I said some things in it that were hurtful, and so I want to revise the entry to remove such topics.

But for now, I want to sleep.
<<tiddler JournalNavigation>>
<<tiddler JournalNavigation>>
I recently spent some time thinking about ki and its uses.  I find that categorizing things makes them easier to understand, even as categorization creates divisions that may separate me from unity.  Then again, if I can understand nothing, reaching a unification of consciousness with anything is significantly harder.

I had originally intended for this to be one massive article with lots of information.  Turns out, that was a bit much and I keep being delayed as I think about what to write.  So, here is the first in a series.

To summarize, here are ways in which I know that ki can be used:

* Healing
* Pleasure
* Communion
* Protection and Attack
* Changing narrative
* Self-transformation
* Teaching

I want to explore all of these things.  They all fascinate me.  They all seem to be a good use of my time and attention.  These pages are mostly to spread my understanding so that other people who may share my understanding will more easily find me.  I invite dialogue here, and I would definitely like people with whom to practice.

[[Read this article to understand how I use the word "ki"|2009/01/22: Big changes]]

! Healing
This one is, in some ways, familiar.  Most everyone has encountered stories of prayer or positive thinking or meditation being a useful cure for various ailments.  Many people have encountered Reiki as another means.  It all amounts to the same thing.  Setting an intention and then directing ki towards meeting that intention.  The difference is in the focus, how the intention is set and how ki is directed to operate.  In prayer, the intention is usually set by invoking at least one and possibly multiple deities.  In Reiki it is set by creating a meditative space and asking that ki flow into that space to heal whatever problems are present.

The idea is the same.  It is to ask that the universal healing power be sent to a recipient for a particular purpose, whether that power comes from a deity or is an intrinsic part of the cosmos.

The general effect, though, is to balance the ki intrinsic to the person being healed.

An effective theory of illness is that illness occurs when the body's ki is out of balance, or if the body's flow is disrupted.  This disruption might happen from a variety of causes.  Viruses and bacteria are one set of possible causes.  My implication is that they do not directly cause the illness, but that they attack the body and throw it off balance, or focus the entire will of the person on destroying an unwelcome invader.  Following this theory, bringing healing in helps to re-balance or strengthen the body's ki, which aids in either destroying or making a truce with any parasitic invaders.

Another cause of imbalance is stress.  This one is more subtle because stress starts affecting cognition before the body starts breaking down.  At a small level of stress, I start to feel pressured in a particular direction.  If the stress becomes too great, I feel out of balance.  I cannot focus my thoughts, I cannot escape from the encroaching time.  I feel physically crushed and have no support to help.  This is the point at which my ki field is so out of balance that it will have to be healed before the rest of me can be healed.  If this state goes on long enough, there is nothing left to support the body, and I believe that without this life-based energy, the body just slowly loses the will to live.

When applying ki in this manner, intention is vital.  What we want is less important than the will with which we shape our world.  Touch someone with ki on a trigger point, particularly the chakras or the meridians, and your intention to heal or to harm will take form.  The exception is with Reiki which is apparently shaped by the will of the cosmos and the recipient, not by the channell.  That apparently cannot be used to harm.

I have heard stories of amazing things happening through a highly knowledgeable application of ki.  I have heard of one man who attacked a doctor of internal medicine, specializing in meridian work.  The attacker later wake up in the hospital with complete internal organ failure and no explainable cause.  He and the hospital had to hire the same doctor to come in and undo the damage.

I have heard of dislocated joints being healed immediately in a healing circle.

I have heard of a cancerous tumor being destroyed with a direct (and possibly a bit... brutal) application of ki.

I do not know how far this practice can be carried.  Maybe it can be carried all the way to the point of curing any disease or mental illness present.  Maybe... there are risks that I am unwilling to run, even with a tool like this possibly available.  Maybe that holds me back from fully realizing what this skill can provide.  Or maybe it keeps me from reaching beyond what I am ready to handle.

! Information gathering
My ideas on gathering information is, at best, vague.

My only experience has been in trying to sense ki flows in another person, particular to find the boundaries of eir aura or to look for chakras that want attention.

In theory, this is also what is happening in divination.  Communicating with my higher self or with my guides also involves ki flow, but I do not perceive the flow directly.  The same applies to astrology.  My guess is that when I enter a more receptive state, I will notice such flows more readily.

In the most dramatic example of this, I have heard of a Buddhist monk who sat silently holding a woman's hands for an hour.  He just silently listened to her, and she silently lay there.  He then walked into another room and told her doctors exactly the same diagnosis they had already made but kept secret.

<<tiddler JournalNavigation>>
<<tiddler JournalNavigation>>
This is a short book, around 160 pages long, by Andy Looney of [[Looney Labs|http://www.looneylabs.com/]].  The book's claim to fame is that it is the book which birthed the idea of Icehouse pieces and the game Icehouse, a product line at Looney Labs.

The book is relatively short, very whimsical, quite fun, but otherwise unimportant.  Mind candy, which made it a good book to read in between the other heavier books that I am reading at the moment.

So, I recommend it for fun.  Ask me if you want to borrow my copy.

<<tiddler JournalNavigation>>
<<tiddler JournalNavigation>>
http://www.austingenderweird.info/

A new community website started by Yours Truly!

<<tiddler JournalNavigation>>
<<tiddler JournalNavigation>>
On Friday, March 6th, I will be testing for Nikyu (2nd-degree white belt) in Aikido.  What this means is that I have been training for six years and plan on putting on a good show.  I invite all of my friends and family to attend this event, and I would love to have a lot of support.

The test will happen in the ballroom at the [[Hancock Recreation Center|http://www.ci.austin.tx.us/parks/hancock.htm]], from 6pm - 7:30pm.  If you arrive late, please slip in quietly through one of the side doors.

There will then be thirty minutes of general socializing while the instructors decide and then announce my fate, followed by either a celebration party or a condolences party.

And go to the [[Still Point Aikido Center website|http://www.stillpointaikido.com/]] for more information on what we are about.

<<tiddler JournalNavigation>>
<<tiddler JournalNavigation>>
WNYC's Radiolab has an episode with Zoe Keating (apparently of Rasputina), who is showing off playing Cello with a computer recording and replaying her work on the fly.

The episode is here: http://blogs.wnyc.org/radiolab/2008/08/25/quantum-cello/. I strongly recommend the section from about 5 minutes in until she stops playing... maybe 12 minutes into the episode. It is... *magnificent*.

<<tiddler JournalNavigation>>
<<tiddler JournalNavigation>>
Detritus on the internet is something that leaves me really uncomfortable.

Specifically, user accounts.  Like... how many do I have?

Not even counting various e-commerce websites I have ordered from (which require that I create an account... WHY???), I have...

* One personal website
* 2 email accounts (one for each of my identities)
* 2 active AIM accounts, and one ancient one whose password I forgot ten years ago
* 1 MSN account
* 2 Yahoo accounts (one for each of my identities)
* Jabber.org
* 1 active Okcupid account, one probably permanently disabled but not deleted
* Livejournal
* Polymatchmaker
* Gaia
* Gaia Soulmates
* LinkedIn

Bloody hell...

Is it any wonder that I resist joining new systems???  I have to keep track of all of these things.  Then I have to decide how to let new people contact me.

And no, the latest and greatest thing does not interest me as more than a curiosity.  It is usually crap.  It is usually designed to harvest my information, own everything that I send through it, and refuse to work with any other part of the internet out there.  The worst part is that lots and lots of people join it, then try to get me to join it, and thus validate the business practice of Not Playing Nicely on the internet.

Many years ago, I wanted to get everyone moved over to Jabber (or XMPP, as the protocol is known by).  Turns out that Google is doing that by creating GTalk, which speaks XMPP and thus runs on the global Jabber network.

I get the feeling that one day, some section of the internet is going to really collapse under the weight of all of this historical detritus that NEVER EVER gets deleted.

In my ideal world, that list above would look like this:

* One personal website.  Maybe a professional website.  Maybe a clear delineation between what is professional and what is personal.  Maybe a refusal to live in a culture that requires such a delineation.
* 2 email accounts (one for each of my identities... unless I end one of those identities)
* 1 little script that shows whether I am currently available for chatting.

Note what is absent.

No social networking websites.  No IM systems.  Not that I disapprove of social networking or IM, I just want it done in a particular way.

IM: contact me by email.  Make it okay to, in the morning, post "good morning" to a social mailing list.

Social Networking: all of my data is on my website in both visual and microformat form.  You have a program that crawls the web looking for this stuff.  The program works very well because there is a standard format for posting my personal information, and then designating what is part of my dating profile and what is part of my professional profile.  It actually happens that the formats already exist, but there are few programs that read them.  So far.  Oh yes.  So far.

The crazy thing about standards: you code to the standard.  So did everyone else.  Everything Just Works because we're all speaking the same language.  Wow.  Whoda thunk it?

! Notice
I guess... do not be too surprised if, when I go to decluttering my internet experience, I drop a lot of those above accounts, starting with many of the IM accounts.

<<tiddler JournalNavigation>>
<<tiddler JournalNavigation>>
So, if you are trying to avoid excuses for buying an iPhone (you know who you are)...

''Stop Reading Now.  Move On.  Just hit the close button on this entry.''

Last night I discovered an iPhone/Touch app that turns the phone into an ocarina, along with a very active community that works on sequencing music into "ocarina notation".

I proceeded to spend four hours browsing and playing.  They have "Still Alive", "Hoist the Colors", "The Inner Light", and many other songs.

...

Yeah.

On the other hand, I think the program has some fingering that a real ocarina does not.  I am pretty sure that "all holes covered" is the lowest note an ocarina can play, but certain patterns in the program play lower notes.  I will experiment, on a real ocarina, tonight.

http://ocarina.smule.com/

Yes.  In the upper right corner is a Youtube video of one guitarist and four people with iPhones playing "Stairway to Heaven".

<<tiddler JournalNavigation>>
<<tiddler JournalNavigation>>
Cycling season is well upon us.

What does it mean when 18mph no longer feels like bat-outa-hell-fast?  It means I have to work harder to get the same rush.

I attached toe holds onto my pedals today.  Distinct from clips in that clips are special pedals requiring special shoes.  These are sorta handles that go over the shoe.  Muscles that I never knew existing are now very unhappy with me.

Last night at Trudy's, I saw a drool-worthy recumbent.  The wheel base on an ordinary bike, pedals out in front of the front tire.  An adjustable tube to move the pedals into the ideal position.  Lights that were wired into in-hub dynamos.  A comfy-looking seat, though leaned too far back for my taste.  Oh, yeah...

I've got the recumbent bug again.

----
In other news, properly done, one hard drive yields two magnets.  Given the right tools, it can also yield six platters that can be glued together for an object with non-trivial rotational inertia.  The magnets are attached to my bike for safe transport home.

<<tiddler JournalNavigation>>
<<tiddler JournalNavigation>>
But, perhaps they should be documented.

So, there is a lot of information out there about syncing an iPhone with Linux, but it turns out that all of it is either limited or obsolete or both.  So, here is the solution I found for iPhone OS 3.0.

First of all, I probably have to keep iTunes on my Windows machine around just to be able to save my applications and application data.  This synchronization method covers my calendar, my contact list, and my music, which is really my day-to-day concern.

! Calendaring and Contacts
In order to do calendar and contact list, you have two options (with some suboptions):

* MobileMe
* Microsoft Exchange

MobileMe is a $99/year service provided by Apple.  On the desktop side, it seems to be entirely a browser-based service.  Maybe there is a way to get that data into native applications, but I did not research this route.

Instead, I went the Microsoft Exchange route.  And the secret here...

My "Microsoft Exchange" server is Google.  Yes.  Google.

Start out with [[Calendar and Contacts Sync|http://www.google.com/support/mobile/bin/answer.py?hl=en&answer=138740]].  That one tells you how to set up the synchronization between the phone and with Google.  It also tells you how to get your *contacts* uploaded to Google.

It might tell you how to get your calendar uploaded, but I had to go the hard way.  I do not have any calendaring application on my Windows machine, and my old Mac could not sync with Google.  (Apparently Google sync is a feature of OS 10.5, not a feature of iTunes 8.x).

Anyway, my procedure was this:

* Use iTunes to upload my contact list to Google.
* Manually enter my calendar in Google calendar.
* Get my iPhone to sync with Google.
  * When I enable Google sync, tell it to delete the data from my iPhone.

That last step there ensures that *all* of the data I have is totally synced with Google.  No local files.  And that finishes off the iPhone side of things.  The synchronization is totally automatic.

After that, there is the Linux side.

If you are running Thunderbird, I can help.  Get the Google Contacts plugin.  Configure the plugin, entering your Google login.  Then tell it how many contacts to download.  I told it to download 500, but I have only around 250 contacts.  All of these contacts go into a new address book locally.  After that, I deleted my Personal Address Book (I had no new data there).  In the Thunderbird Preferences I told it to use local address books, and then I told it to put all new outgoing email addresses into my Google address book.

That has been handled.  *whew*.

I started running Sunbird to keep track of my calendar, and it has a Google Calendar plugin.  After starting Sunbird and getting the plugin, I went to my Google calendar in my browser.  Once on the calendar page, find the list of calendars and click on "Settings".  Find the calendar that you want in Sunbird, and click on its name.  Then scroll down until you see the subscribe options.  Those options pop up a URL that you can enter into Sunbird when you add a New Calendar.

! Music

(never completed...)
<<tiddler JournalNavigation>>
<<tiddler JournalNavigation>>
One of the things that I do when I am exploring a new language is to code up a limited model of some common game that I rather enjoy.  Normally I hack out a calculator for Civilization Advances.  This time, because I had just bought Chrononauts, I decided to model the Chrononauts timeline in Clojure.

! Clojure

[[Clojure|http://clojure.org/]] is a young language in the Lisp family.  It compiles code into Java bytecode, essentially runs in a Java interpreter, and has full access to the whole Java library.  In Java, there is a library for ''everything''.

I will leave the sales pitch to the website, but I am liking it so far.  I am slightly uncomfortable with the lack of static typing, even as an option, and I am quite tweaked at how Java exceptions (which are plentiful) get printout without a stack trace.  There may be something in the system that I am forgetting.

In short, though, you only need three things to execute my code.  First, is a java interpreter and a shell to run it in.  Mac and Linux users will have no problems, Windows users are pretty much going to have to read the Clojure website to figure things out.  Second, you need [[clojure.jar|http://code.google.com/p/clojure/downloads/list]].  I recommend the 1.0.0 release.  Third, you will need chrononauts.clj and the instructions below.  Keep reading for that.

! Chrononauts

Chrononauts is a game created by [[Looney Labs|http://www.looneylabs.com/]] in which the players are time travellers.  Looney Labs owns the copyright for Chrononauts.  Further, they own the any copyright which applies to the Linchpin, Ripplepoint, and Patch descriptions that I put into this file.  It is a very good game.  I recommend you buy it:
http://wunderland.com/LooneyLabs/Chrononauts/Default.html

There are several ways to win the game, but the only way that is relevant for this module is in the "return home" scenario.  In order to return home, a player must set the timeline in such a way that his hometime is extant.  For instance, one of the characters in the game is named Werner, and his home time exists when these conditions are true:

* 1939': Fairgoers Love German Cake
* 1974': President King Takes Office
* 1991:  Soviet Union Collapses

Now, *our* timeline, or normal time, would be:

* 1939: Germany Invades Poland
* 1974: Nixon Resigns
* 1991: Soviet Union Collapses

What happened here?  Well, the mechanics will be explained further down.  Somebody flipped 1936 causing Hitler to be assassinated at the opening to the 1936 Olympics, flipped 1865 causing Lincoln to survive his assassination, flipped 1963 causing Kennedy to survive his assassination, then patched 1939 and 1974 into the new timeline.  How?  Read more and enjoy!

The timeline consists of Linchpins and Ripplepoints.  A Linchpin is a point in time that a time traveller can directly change.  A Ripplepoint cannot be directly changed but changes in response to a Linchpin.  So, "1980: John Lennon Murdered" is a Linchpin.  If flipped to "1980': John Lennon Nearly Killed", "1999: Columbine High School Massacre" will be paradoxed.

Ripplepoints will go into Paradox when their causes have been changed.  Once a ripplepoint has been Paradoxed, they may then be Patched.  Patching amounts to inserting a new reality which is consistent with the terms of Linchpin that was the cause of the reality.  So...

Once "1999: Columbine High School Massacre" has been paradoxed, it may be patched with the card "1999': Guns Banned"  The 1999' card has some extra flavor text to explain what happened: "Senator Lennon's campaign to outlaw guns results in passage of Amendment XXIX, which repeals the 2nd Amendment".

! chrononauts.clj

So, that is how the game and the timeline work.  Now for how to use the module.

This module defines events, initial-timeline, and patches.  events is simply a dictionary of the events in the game.  initial-timeline is a dictionary of the events in sorted order and with the current state of teh event.  patches is simply a dictionary of the patches for the game.

timeline is a mutable reference storing the current state of the timeline.  s-flip and s-patch are the methods that flip Linchpins and patch Ripplepoints, respectively.  Finally, tl-print will print the entire timeline as it currently appears.  Use the functions as so:

{{{
(s-flip 1865 *linchpin-states* *patch-states*)
(s-patch "1868'" *linchpin-states* *patch-states*)
(tl-print *timeline* @*linchpin-states* @*patch-states*)
(tl-print *timeline* *initial-linchpin-states* *initial-patch-states*)
}}}

Note that tl-print is not designed to take a reference.  There is nothing stateful about it, so dereference the timeline, first.

Anyway, find the code here:
[[chrononauts.clj|src/lisp/chrononauts.clj]]

Load it up in clojure with...

{{{
java -cp clojure.jar clojure.lang.Repl
(use 'chrononauts)
}}}

Then start running the commands above.  Have fun!

<<tiddler JournalNavigation>>
<<tiddler JournalNavigation>>

Total crash on the programming language front.  I thought Clojure was pretty darn cool, but I was really uncomfortable wandering around in yet another "dynamically typed" language.  Read "dynamically typed" as "duck typed" or "run time typing".

I just spent multiple hours today tracking down a type error.  It amounted to me passing a number in a very complex data structure where a string was required.  I ultimately figured it out by printing out the value of the field that was causing the exception five modules deep.  That is just not how to write world class code.

In my opinion, type errors should be found at compile time.  Always.  Never at run time.  A language that waits until run time to find type errors is broken.

So, my choices are C, Java, Haskell, and Ocaml.  Here's my analysis of the problems of each...

* C -- uber-primitive.  Polymorphism amounts to void *
* Java -- carpal tunnel
* Haskell -- advanced monad issues in big applications, and a lack of library support, and the parser library is dog slow
* Ocaml -- screwed syntax

However, of the four, Haskell and Ocaml are the two that I am really thinking of the most.  I have to decide on one of them.  I think I can get over the advanced monad issues, but I am not sure how to deal with lack of support libraries in Haskell other than to hope that other programmers decide to write stuff.

''sigh''

<<tiddler JournalNavigation>>
<<tiddler JournalNavigation>>
Friday night, I went to a party.  It was a going away party for a former lover and her boyfriend as they move out to the west coast.  They are probably half-way there by now.  The party was close to my house, so in my excitement over the new bike, I cycled there.  Not quit five miles, but the route is dark with very little traffic and I was totally surrounded by trees for much of it.

At about 1:30 in the morning I got a text message letting me know that my lovers from Dallas were about fourty miles out, so I said my goodbyes, jumped on my bike, and started the trek home.  Understand that with my bike, I am now in a position where I can Truly See the sky.  I'm used to being hunched forward and unable to see all that much... now I get to sit back.

So, on the trip home, I turned north onto a very dark road entering my subdivision, and in the midst of the darkness got to see a brilliant meteor come down.  It was very bright, had a beautiful green tinge to it, and lasted a good two seconds.  Maybe as long as three.  This was around two on Saturday morning.

This is the second meteor of true beauty that I have ever seen, and is the kind of thing that really stands out in my memory forever.  And there is something about cool weather that makes the skies even more distinctive in my mind.

I have worn a tektite since 2001.  I did not know about the energetic influences such a stone exerts until 2008, but even before that I liked wearing a stone that was so closely associated with space and with falling stars.

Incidentally, here are some [[pictures of my new bike|http://markus.alyra.org/images/2009_11_Bike/]].  I will get pictures of me on it soon.

<<tiddler JournalNavigation>>
<<tiddler JournalNavigation>>
And I managed the ride to work.  A stiff headwind slowed my progress considerably.  Except for my hands, I managed to dress just right to be comfortable for almost the entire trip.  I will attempt to buy some thicker gloves on the way home.

<<tiddler JournalNavigation>>
<<tiddler JournalNavigation>>
Just so you all know, I will be spending the entire month of February in retreat.  This will make me highly inaccessible to just about everyone until I emerge in the beginning of March.

On the other hand, I may be posting more here.  Not that I usually post much of consequence, or that there is really any one reading it.

I hope to emerge with two things....

# A reasonable map of my spirituality
# A couple small but useful pieces of code

The pieces of code are largely optional, though there is one that I really want to have written as part of a super-secret project.  I really want a reasonable map of my spirituality and a bunch of new habits around it and around my overall health.

<<tiddler JournalNavigation>>
<<tiddler JournalNavigation>>

First, the feline.

Mr. Washburn, though skittish, has started exploring the storm drains.  Or maybe he just hangs out in the storm drain right outside of my house.  Either way, he went down there Sunday during the day and refused to come back out.  Through a very stressful Sunday evening and Monday evening, I tried various techniques to coax him out.  I could get him to come out for catnip and for food, but even the slightest approach from me caused him to run right back down into the storm drain.  I was truly fearing that he had gone feral.

Then, this morning he comes to the back door and starts meowing at around 6:30.  I'm sleeping downstairs against this possibility, so I let him in.  He ate a bit, then meowed quite a lot, then fell silent.  I should have been suspicious, but instead I had gone back to sleep.  Later, I got up and found a trail of small dried leaves in my kitchen.  In my workroom, I found Washburn lying, quite happily, in the midst of the scattered full contents of a bag of catnip that I had left on my desk.

Well, that explains the silence.

! Cleanse

As part of my retreat, I have gone on a food cleanse.  This is the Standard Process 21-day cleanse.  I am in relatively good health, so I am hoping that 21 days on this will help purge some excess toxins that I have picked up over my life, help out with the little roll of fat around my belly that I cannot explain and rather dislike, reduce some of the unexplained weight gain from the last year, and instill in me some better eating habits.

Interestingly, former co-worker and his wife just finished the cleanse last Saturday, for the third time.  Apparently the results they get from it are pretty incredible, so they redo it every six months or so.  They also warned me about some really negative reactions (headaches, nausea) that can happen in the first few days, but so far I have experienced only mild headaches.  And that was at the end of the first day.

So far, the primary result has been Fresh Food Overdose.  Geez...  However, last night I made a decent soup out of a tomato, a stick of celery, salt, pepper, cumin, and garam masala.  The garam masala probably was the wrong flavor.  Tonight I took my chickpeas in ginger sauce recipe and stripped out the chickpeas to make it compliant with the cleanse.  It was quite tasty, but quite sweet, as well.  A little unexpected.  But, I have leftovers for tomorrow evening, so no need to spend hours in the kitchen then.  Technically, I am supposed to be eating only fresh food or very lightly cooked food, and I am doing a good job of that, but it is damned cold and I want something savory.

There is a protein shake that I am supposed to drink 2 - 3 times per day.  Actually, it's make a shake out of fresh fruits and vegetables, add the protein powder to it.  Until day 11 (which will be February 11th), I have almost no other protein source.  Yes, I could get protein from avocado, but I rather despise avocado.  Anyway, the protein powder adds a rather undesireable flavor, but I figured out tonight that what I find most disgusting is the thick foam that forms as part of running the blender.  So tomorrow I'm going to try just fresh juices, no or minimal blending, and see what happens.

I seem to be craving fat now, because even the microwaved breaded fish dinner that somebody did for lunch smelled really, really, really, really good.  Of course, if I am craving fat then that means I am probably also metabolizing my stores.

! Romance (and gender)

This is actually something I wrote in an email last week to several people.  I am reposting it here largely unchanged, but it is a matter for me to process.  Several days after this email I attended a workshop on Romantic Theatre and I have notes that need processing, and then they need to be integrated into the stuff here.

<<<
I plan to attend on Saturday a workshop on romance in what sounds to me like a highly ritualized form that derives from highly spiritual traditions.  On the other hand, it also sounds like it originates from those spiritual traditions that strongly emphasize the masculine/feminine split in a very heteronormative, two-gendered way.

I plan to attend in part to prove to myself that I rebel against the two-gender system with my eyes open and that my rebellion has not yet blinded me.  I also hope to learn something valuable, but I fear that I may have difficulty assimilating it.

I have met the teacher several times.  Interestingly, I suspect that I may ultimately be a lot like him in about twenty years.  I see a lot in him that feels really familiar.

A few days ago, Crow described to me a "date" that this guy recently conducted with a friend he has known for a great many years. Second-hand description, and I shall elide almost all of the details. She described an event in which he took his friend out to a nice restaurant and conducted the entire date, setting the stage, ensuring the wait staff stayed out of the way, and generally everything that goes into a perfectly masterfully orchestrated romantic evening.

Okay, all well and good, except that I perceive a great act, one that the man must carry out and that the woman gets to judge.

I may be over perceiving the gender split.  I do not think so, but I may be.

Maybe sometimes it is not?

I once had no problems figuring out what was expected of me for a romantic evening.  But, I also have to say that it always felt both forced and fake when I did it.  Now it feels even worse.  I try on occasion, but I feel a constant pressure to "perform" when I do try it, and I do not enjoy that.  The best I get is dressing nicely and taking somebody to Casa de Luz, which is not a fancy restaurant, where there are no attendants to take care of every little thing, the environment is comfortable, and where I do not feel that every action I take is being judged.  Or maybe I take someone who is judging me and I just fail to care.

Obviously, all of this stuff eats at me.  Several contradictory identifiable ideas feed this confusion, but I do not yet know which ones are true...

* I may discover that the gender split is real and that I cannot possibly be an androgyne
* If I'm a man I will always be the one expected to perform flawlessly
* Why am I still in circumstances where this is important enough to throw me into this much conflict
* Why is it that when spiritualists talk about "meeting" women (not initial meeting, but relating on the same level), it sounds more to me like "worshipping"?
* ???

There's a lot more here, but I have kinda run out of words.  Clearly I am experiencing a lot of turmoil about all of this...
<<<

When (if) I get some resolution, I will post more here.

<<tiddler JournalNavigation>>
[<img(20%,auto)[images/markus_andro_350x450.jpg]]

! Mark Humphrey, Savanni D'Gerinel

Dreamer, Shaper, Seeker, Maker

!! Contact

<html>
<ul class="vcard">
<li> <a href="http://markus.alyra.org/" class="url fn">Savanni D'Gerinel</a></li>
<li class="nickname">Mark Humphrey</li>
<li> <a href="mailto:savanni@alyra.org" class="email">Email Savanni</a>,
	<a href="mailto:markus@alyra.org" class="email">Email Markus</a> </li>
<li> Jabber: <a href="xmpp:savanni@jabber.org/" class="url">Savanni</a> </li>
</ul>
</html>

!! About Me

<<<
There is never an ordinary moment. There is always something going on.
<<<

I live in Austin, Texas, working for a small internet-related company. I keep around three animals that look like cats and are as sharp as cats but think they are human and scatter like fish when they are startled.

I was born on Friday, October 13th, 1978. At the time, my father worked for the Lawrence Livermore Laboratories in Livermore, California. Shortly after that we moved to Texas, and I have spent most of my life since then living here. I had an unfortunate side-trip to Houston for several years, a much improved side-trip to Norman and the University of Oklahoma, and I am pretty much settled into Austin for now.

Though I have not lived in very many places, this city is fairly close to my ideal. There is a strong presence of strange people, a huge emphasis on local business, and roughly the exact climate that I require to survive. Plus, I live only half an hour from the only state-sanctioned nude "beach" (rocky lakeshore) that I know of in the entire United States.

I answer to both Savanni and Markus. To my knowledge Savanni has no meaning in the English language and is not used elsewhere in the English-speaking parts of the world. If you are just meeting me I prefer that you call me Savanni. If you already know me as Markus I prefer that you migrate but it is not necessary nor will I be irritated if you do not.

!! Relationships and Gender

I am an androgyne.

What this means is that I am neither a man nor a woman. I have male anatomy. My aura may still be more masculine than feminine. I have dated primarily women. I do not fit the gender stereotypes and I do not want to be placed into the traditional gender roles. If I am ever able to transition, I will have my anatomy modified slightly, but I will not take any drastic steps to become something else. Please try to relate to me as a person, not as a "variation on the American Man template". I will respond out of habit to male pronouns and even to various other things; such as "boyfriend", "husband", and "man"; associated with being male.  I strongly prefer prefer gender-neutral pronouns and the words "partner", "friend', "lover", "watersib", and "person".

I am currently developing a network of waterkin. The actual level of involvement I have with any particular person is meant to be fluid and to change over time to whatever best suites us. People who are not currently my lovers may become so again one day. Current lovers my drift away from me. Some people enter my life even as others leave my life. This is what I want in my life. I once lived in an arrangement in which four of us were very close, we interacted with each other intimately, and were even viewed as a foursome by people outside. It was an asexual relationship for most of us, and we eventually all went our separate ways, but it is the inspiration by which I create my future.

I am polyamorous and I have been for my entire adult life. I am involved with multiple people whom I have known for various amounts of time.  I imagine that I will be happiest in a group of six to eight people some of whom are connected intimately or sexually, and some of whom are not.

Strictly speaking, what I seek is somewhat looser than a "family", in that the relationships can be allowed to change to what the two people in the relationship feel is healthiest at the time.

Yes, I am looking for lovers within that tribe. And sleeping partners, tantrikas, gamers, intellectuals, spiritualists, ki workers, fellow nudists, sacred sex practitioners, recreational cyclists, and mad scientists. For science, of course. :D Nobody has to be all of these things.

I could see assembling this tribe. I could see joining an existing tribe. I kind of have the beginnings of a tribe right now and I could see bringing more people into it.  I would like to join a couple to form for the near-term, but in that I would keep my existing relationships and I would eventually want to grow the group into something larger.

My hard boundaries are that I want for my gender identity (androgyne) to be acknowledged even if not understood, I will not be willing to relocate in the next five years, I will not get involved with anyone who is monogamous, I will not kiss or be otherwise physically intimate with someone who smells like cigarette smoke, and I will not participate in any kind of BDSM activity. Everyone else is welcome to do what they will with one another.

!! Projects and Code

I write a lot of code. I do programming for work, and then I go home and do programming on my own.

Alexandria and Vretil are a combination of two big projects related to how I store and publish information, and if I can make them work right I hope to change a small portion of the world by helping other people adopt those projects as well. Alexandria has, however, kind of fallen by the wayside. Other, more urgent and more focused, projects are demanding my attention, and what little creative energy I currently possess has been dedicated to them.  Theoretically, this site should be hosted by those two applications, but because my focus is moving elsewhere, I just found another tool that would do the job for now.

One of my many goals in life, particularly in the computer world, is to restore the glory of true ad-hoc social networking. This is a largely unattainable goal on my own, but there are many other people working on it in various capacities, and so one day we will succeed. These are the people working with vCard, OpenID, iCal, and many other technologies that focus on one system talking to another. Instead of logging into a big "social networking" website, like [[Gaia|http://www.gaia.com/]] or [[Livejournal|http://www.livejournal.com/]], you just start a program that crawls your list of websites looking for structures which tell it how to find people, interests, and ideas.

!! Alyra

Alyra is a world which I have designed and redesigned. I use it as a setting for any fantasy storytelling. At this time, no fragment of the world is published online. Problems that have arisen over the years with the slow evolution of Alexandria have made painful the process of migrating data forward. Problems in the world itself have left it badly in need of rethought and redesign.

Ideally, given the right amount of effort and imagination, Alyra will be a world that is as real to me as Middle Earth is to so many others. I have no doubt that my world will never be as deep as Tolkien's work, but the goal is to have a place for my own fantasy. Anyone else can join me for the ride.

!! A cloud of words to list my interests

Some of these are things that I am working on or thinking about myself, and some of them are concepts that I track myself. But, once listed, I seem to have a lot of interests...

* Personal Knowledge Management: [[The Dublin Core Metadata Initiative|http://www.dublincore.org/]], Getting Things Done, Living in One Text File, Organization
* Computer Technology: Computer Programming, Functional Programming Languages, Internet services, The Semantic Web
* Gaming and Storytelling: Abstract Strategy Games, Alyra, Faerie Tales, Role Playing, World Creation
* Gender Identity: [[Androgyny|http://en.wikipedia.org/wiki/Androgyny]], Genderfluidity
* Relationship Structures: Intentional Community, Polyamory, Sexuality
* Spirituality: [[Aikido|http://www.stillpointaikido.com/]], Buddhism, Chakras, Meditation, Reciprocality, Reiki, Self-awareness, Tantra, Unity Conciousness
* Quirkiness: Esperanto, Sterling Engines, Fountain Pens, Journey to the Wild Divine

!! My Favorite Books and Short Stories

* Anathem, Neil Stephenson
* [[Metatropolis (audible.com)|http://audible.com/meta]]
* Anathem, Neil Stephenson
* [[The Gentle Seduction|http://www.skyhunter.com/marcs/GentleSeduction.html]]
* Solitude, Ursula Le Guin (part of The Birthday of the World anthology)
* Coming of Age in Karhide, Ursula Le Guin (part of The Birthday of the World anthology)
* [[The Third Age of the World: Magic and Science in the 21st Century|http://www.datamodel.co.uk/Reciprocality/www.reciprocality.org/thirdage/index.html]], Alan G. Carter
* Rainbows End, Verner Vinge
* A Deepness in the Sky, Verner Vinge
* The Left Hand of Darkness, Ursula Le Guin
* Healing into Life and Death
* A Wizard of Earthsea, Ursula Le Guin
* His Dark Materials, Philip Pullman
* This Alien Shore, C. S. Friedman
* [[The House Beyond Your Sky|http://escapepod.org/2007/05/17/ep106-the-house-beyond-your-sky/]], Benjamin Rosenbaum
* Coming of Age in Karhide, Ursula Le Guin
* Woman on the Edge of Time, Marge Piercy
* Prometheus Rising, Robert Anton Wilson
* Angel Tech, Antero Ali

!! My Favorite Shows

These are actually listed in order, first of importance to me and then of pure enjoyment.

* What the Bleep Do We Know
* The Fountain
* The Lord of the Rings
* Howl's Moving Castle
* Ghost in the Shell 1 and 2
* Firefly and Serenity
* The Illusionist
* Babylon 5
* Heroes

!! Favorite Music Groups

* Lacuna Coil
* Leaves' Eyes
* Alkaemy -- They have one and only one album, "The Merlin Mystery", and it is, regrettably, out of print.
* Yanni
* Vangelis
* Diane Arkenstone
* Loreena ~McKennitt
* Yasunori Mitsuda
* Hipnautica

There is a heavy emphasis on Trance and New Agey stuff here, but I do actually like a variety of musical styles.  Even some forms of country.

Creator: Frank Swehosky <mailto:gryphon@acm.org>

One of the links from the website is Greg Henry's Aikido Terminology
Page (http://www.cs.utk.edu/~ghenry/aikido), which is a great
resource.

Japanese terms:
Ai-hanmi =  partners' open sides facing each other, versus gyaku-hanmi
Aikido = Ai (harmony/blending/fitting) Ki (energy) Do (road/path/way),
"system of self-defense which was developed to facilitate constructive
conflict resolution."
Aiki-Ryoho, Kiatsu = Aiki-style massage/therapy
Aiki-Taiso = Seidokan form
Awase = Bokken versus jo
Choyaku = a movement involving 2 steps and a pivot
Chudo = middle path, moderation
Chudon no Kamae = middle stance with sword, pointed towards throat
Dori = disarming
Dozo = please
Gedan no Kamae = Low stance with sword, offering an opening
Gotai = static, stationary, versus jutai
Gyaku-hanmi = partners' open sides facing the same side
Hai = yes
Hanmi = natural stance with one foot forward
Hanmi Handachi Waza = Tori is in seiza, uke is standing
Henka Waza = Variations or alternate techniques if the initial one was blocked
Ie = no
Irimi = split the line, often implies entering techniques
Jodan no Kamae = High stance with bokken, sword overhead
Ju = non-resistance[5] - use doors, not walls
Jutai = dynamic, moving, versus gotai
Jyu (Je) Waza = Free/unscripted responses to scripted or limited attacks
Kaeshi Waza = Reversal or counter techniques, cutting back
Katame Waza = controlling / binding techniques
Kohai = junior/apprentice/inferior student
Koho = retreat
Kokyu = breath
Koshi Waza = Hip techniques
Kumi-<x> = matching, like kumi-jo is jo vs. jo, kumi-te is matched
hands (sparring)
Kyusho = Pressure points
Ma-ai = distance / space between tori & uke
Misogi training = purification, can be harsh, from tradition of
religious background of O'Sensei
Mune tski = stomach thrust/punch
Nage = throw or person doing the throwing
Ne waza = ground grappling (Ne = floor / ground)
Omote = Forwards, front side, open
Reigi = Dojo etiquette
Sempai = senior/advanced/mentor/superior student
Shime Waza = choking techniques
Shizentai Gamae = postures and stances
Shomen = focus of training area, often has Aikido characters and a
picture of O'Sensei
Shomen Uchi = straight vertical downward cut
Shoto-o-seisu = control the first move, offer the openings
Sudori = escapes, "to pass through"
Suminmasen = Excuse me, for what I'm about to do
Suwari = both uke and tori in seiza
Tachi = live sword
Tenkan = pivot
Tski  = thrust attack
Tori = person receiving the attack
Ude-Osae = arm pinning
Uke = Attacker
Ura = backwards, rear side, hidden
Wakarimasen = I don't understand
Yokomen = circular strike to the temple
Yudansha = Dan level students
Zanshin = a relaxed awareness of the world
Zempo = advance, forward

Good definitions of martial arts terms:
Basics = the first thing learned, a starting point in teaching
Combat = people trying to kill each other
Fight = socially agreed violent conflict
Fundamentals = what makes techniques work/effective

Anatomy & Physiology:
Abduction = Movement away from the midline of the body
Adduction = Movement towards the midline of the body
Anterior = Front of the body
Carpal bones = bones in the hand
Coronal plane  = divides the front and back part of the body
Distal = on a limb, away from the trunk of the body
Extension = Straighten a joint
Flexion = Bending a joint
Kinematics = Motion without momentum or force
Kinetics =  Interactions that produce motion
Lateral = Away from midline of the body
Medial = towards the midline of the body
Midsagital plane = divides the body into right & left
Posterior = rear of body
Pronation = torque rotation of the limb outward - leads to Kotegaish with wrists
Prone = lying down, face down
Proximal = on your limb, closer to the trunk of the body
Supine = lying down, face up
Supination = torque rotation of the limb inward - leads to Eiku
Transverse plane = Waist, parallel to the ground

! 2009
* [[The Empty City (Andy Looney)|2009/02/12: The Empty City]]
* [[Woman on the Edge of Time (Marge Piercy)|8 January 2009: Woman on the Edge of Time]]
* X: A Fabulous Child's Story (Lois Gould) -- a whimsical book about a scientific experiment in which a child's gender was hidden from everyone except the child's caretakers while e was growing up.

! 2008
* Redefining Our Relationships (Wendy-o Matik)
* No Boundary (Ken Wilbur)
* The Journey to Wild Divine: The Passage
* Neverwhere (Neil Gaiman) (audio)
* The Codex (audio) -- this was terrible...
* Deception Point (Dan Brown) (audio) -- also pretty bad
* The Rule of Four (Ian Caldwell, Dustin Thomason) (audio)
* Life After Death: The Burden of Proof (Deepak Chopra) (audio)
* Thunderbird Falls (C. E. Murphy) (audio)
* Friday (Heinlein)
* Skinny Dip (Carl Hiaasen) (audio)
* Memoirs of a Geisha (audio)
* I Robot (Isaac Asimov) (audio)
* Jonathan Livingston Seagull (Richard Bach)
* The Book of Secrets (Deepak Chopra) (audio)
* Coyote Dreams (C. E. Murphy) (audio)
* Poison Study (Maria V. Snyder) (audio)
* Living the Simple Life (Elain St. James)
* Eifelheim (Michael Flynn) (audio)
* Stray (Rachel Vincent) (audio)
* Harry Potter and the ~Half-Blood Prince (J. K. Rowling)
* Pattern Recognition (William Gibson) (audio)
* The Book of the Dead (Douglas Preston, Lincoln Child) (audio)
* Middlesex (Jeffrey Eugenides) (audio)
* Faerie Wars (Herbie Brennan) (audio)
* Metatropolis (Jay Lake, Tobias Buckell, Elizabeth Bear, John Scalzi, Karl Schroeder) (audio)
* Sexual Reflexology (Mantak Chia and ???)
* [[Desire: The Tantric Path to Awakening (Daniel Odier)|09 December 2008: Books and Book Reviews]]
* [[The Michael Handbook (???)|09 December 2008: Books and Book Reviews]]

! 2007
* The Left Hand of Darkness (Ursula Le Guin)
* The Amber Spyglass (Philip Pullman)
* The Worthing Saga (Orson Scott Card) (audio)
* Freakonomics (audio)
* The Birthday of the World (Ursula Le Guin) (audio)
* Prometheus Rising (Robert Anton Wilson)
* Stardust (Niel Gaiman) (audio)
* Urban Shaman (audio)
* Devil May Cry (audio)
* Life as We Knew It (audio)
* Gifts (Ursula Le Guin) (audio)
* The Watchmen (Alan Moore)

! 2006
* Rainbows End (Verner Vinge)
* Iron Sunrise (Charles Stross)

! 2005
* American Gods (Neil Gaiman)
* Emerald Eyes (Daniel Keys Moran)
* Paper Mage
* The Chronoliths
* The Da Vinci Code (Dan Brown) (audio)
* The Last Dancer (Daniel Keys Moran)
* The Long Run (Daniel Keys Moran)
* The Summer Tree (Guy Kavriel Kay)

! 2004
* [[The Third Age of the World|http://scwizard.awardspace.com/Reciprocality/thirdage/index.html]]
* The Drawing of the Three (Stephen King)
* The Gunslinger (Stephen King)
* The Order of the Phoenix (Rowling)
* The Pragmatic Programmer
* The Seven Habits of Highly Effective People
* The Subtle Knife (Philip Pullman)
* The Wastelands (Stephen King)
* Things that Make Us Smart
* This Alien Shore
* Wizard and Glass (Stephen King)

! Read, past
* 2001 (Arthur Clark)
* 2010 (Arthur Clark)
* 2061 (Arthur Clark)
* A Deepness in the Sky (Verner Vinge)
* A Fire Upon the Deep (Verner Vinge)
* A Game of Thrones (Tad Williams)
* A Horse and His Boy (C.S. Lewis)
* A Separate Peace (John Knowles)
* Androids Dream of Electric Sheep? (Philip K. Dick)
* Archangel (Sharon Shinn)
* Beowulf
* Blood Meridian or The Evening Redness in the West
* Children of Dune (Frank Herbert)
* Children of the Mind (Orson Scott Card)
* Contact (Carl Sagan) (audio)
* Cradle (Arthur Clark)
* Death Comes for the Archbishop
* Dragon Tears
* Dune (Frank Herbert)
* Dune Messiah (Frank Herbert)
* Earthsea: A Wizard of Earthsea (Ursula Le Guin)
* Earthsea: The Farthest Shore (Ursula Le Guin)
* Earthsea: The Tombs of Atuan (Ursula Le Guin)
* Emma (Jane Austin)
* Ender's Game (Orson Scott Card)
* Eon
* Eternity
* Farenheit 451 (Ray Bradbury)
* Foundation (Isaac Asimov)
* Foundation and Empire (Isaac Asimov)
* Foundation's Edge (Isaac Asimov)
* Garden of Rama (Arthur Clark)
* Heart of Darkness
* Henry V (William Shakespeare)
* I Know Why the Caged Bird Sings (Maya Angelou)
* Interview with the Vampire (Anne Rice)
* Jehovah's Angel (Sharon Shinn)
* Jurassic Park (Michael Chriton)
* ~MacBeth (William Shakespeare)
* Memnoch the Devil (Anne Rice)
* Otherland: City of the Golden Shadow (Tad Williams)
* Otherland: Mountain of Black Glass (Tad Williams)
* Otherland: River of Blue Flame (Tad Williams)
* Prince Caspian (C.S. Lewis)
* Rama Revealed (Arthur Clark)
* Recluce: Colors of Chaos (Modesitt)
* Recluce: Fall of Angels (Modesitt)
* Recluce: The Chaos Balance (Modesitt)
* Recluce: The Death of Chaos (Modesitt)
* Recluce: The Magic Engineer (Modesitt)
* Recluce: The Magic of Recluce (Modesitt)
* Recluce: The Order War (Modesitt)
* Recluce: Towers of the Sunset (Modesitt)
* Rendezvous with Rama (Arthur Clark)
* Rendezvous with Rama 2 (Arthur Clark)
* Riftwar: A Darkness at Sethanon (Raymond Feist)
* Riftwar: Magician Apprentice (Raymond Feist)
* Riftwar: Magician Master (Raymond Feist)
* Riftwar: Prince of the Blood (Raymond Feist)
* Riftwar: Silverthorn (Raymond Feist)
* Riftwar: The King's Buccaneer (Raymond Feist)
* Sandman 1-10 (Neil Gaiman)
* Second Foundation (Isaac Asimov)
* Serpentwar: Rage of a Demon King (Raymond Feist)
* Serpentwar: Rise of a Merchant Prince (Raymond Feist)
* Serpentwar: Shadow of a Dark Queen (Raymond Feist)
* Serpentwar: Shards of a Broken Crown (Raymond Feist)
* Speaker for the Dead (Orson Scott Card)
* Sphere (Michael Chriton)
* Star Trek: 1-6
* Star Trek: A Rock and a Hard Place
* Star Trek: First Contact
* Star Trek: Generations
* Star Trek: Ghost Ship
* Star Trek: Metamorphosis
* Star Trek: Strangers from the Sky
* Star Trek: The Dark Mirror
* Star Trek: The First Adventure
* Star Trek: The Lost Years
* Star Trek: Vendetta
* Stranger in a Strange Land (Robert Heinlein)
* The Alleluia Files (Sharon Shinn)
* The Chamber of Secrets (Rowling)
* The Fellowship of the Ring (Tolkien)
* The Goblet of Fire (Rowling)
* The Golden Compass (Philip Pullman)
* The Hobbit (Tolkien)
* The Last Battle (C.S. Lewis)
* The Lion, the Witch, and the Wardrobe (C.S. Lewis)
* The Magician's Nephew (C.S. Lewis)
* The Moon is a Harsh Mistress (Robert Heinlein)
* The Moon is a Harsh Mistress (Robert Heinlein)
* The Prizoner of Azkaban (Rowling)
* The Return of the King (Tolkien)
* The Scarlett Letter (Nathaniel Hawthorn)
* The Shapechanger's Wife (Sharon Shinn)
* The Silver Chair (C.S. Lewis)
* The Sirens of Titan (Kurt Vonnegut)
* The Sorceror's Stone (Rowling)
* The Sound and the Fury (Forrester)
* The Terminal Man (Michael Chriton)
* The Two Towers (Tolkien)
* The Voyage of the Dawn Treader (C.S. Lewis)
* The Wheel of Time: ... (Robert Jordan)
* The Wheel of Time: ... (Robert Jordan)
* The Wheel of Time: Lord of Chaos (Robert Jordan)
* The Wheel of Time: The Eye of the World (Robert Jordan)
* The Wheel of Time: The Fires of Heaven (Robert Jordan)
* The Wheel of Time: The Great Hunt (Robert Jordan)
* The Wheel of Time: The Shadow Rising (Robert Jordan)
* Tigana (Guy Kavriel Kay)
* Time Enough for Love (Robert Heinlein)
* To Kill a Mockingbird
* To Sail Beyond the Sunset (Robert Heinlein)
* What Do You Care What Other People Think (Feynmann)
* Xenocide (Orson Scott Card)
<html>
<a rel="license" href="http://creativecommons.org/licenses/by-sa/3.0/us/"><img alt="Creative Commons License" style="border-width:0" src="http://i.creativecommons.org/l/by-sa/3.0/us/88x31.png" /></a><br /><span xmlns:dc="http://purl.org/dc/elements/1.1/" href="http://purl.org/dc/dcmitype/Text" property="dc:title" rel="dc:type">To Dream of Magick</span> by <a xmlns:cc="http://creativecommons.org/ns#" href="http://www.alyra.org/" property="cc:attributionName" rel="cc:attributionURL">Savanni D'Gerinel</a> is licensed under a <a rel="license" href="http://creativecommons.org/licenses/by-sa/3.0/us/">Creative Commons Attribution-Share Alike 3.0 United States License</a>.
</html>
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
* CookieJar
* SiteUrl
* PageTemplate
* StyleSheet
* JournalNavigation
You'll also need to enter your username for signing your edits: <<option txtUserName>>

<<tiddlerTweaker>>
/***
<<tiddler CookieManager>>
***/
// 30 options saved on Friday, October 17th 2008 at 15:56:04 by Savanni D'Gerinel//
//^^(edit/remove username check and/or individual option settings as desired)^^//
//{{{
	config.options.chkAllowBrowserCookies=true;
	config.options.chkAnimate=false;
	config.options.chkAutoSave=true;
	config.options.chkBackstage=false;
	config.options.chkCaseSensitiveSearch=false;
	config.options.chkConfirmDelete=true;
	config.options.chkCookieManagerAddToAdvancedOptions=true;
	config.options.chkDisplayInstrumentation=false;
	config.options.chkForceMinorUpdate=false;
	config.options.chkGenerateAnRssFeed=true;
	config.options.chkHttpReadOnly=true;
	config.options.chkImportReport=true;
	config.options.chkIncrementalSearch=true;
	config.options.chkInsertTabs=true;
	config.options.chkMonitorBrowserCookies=false;
	config.options.chkOpenInNewWindow=true;
	config.options.chkRegExpSearch=false;
	config.options.chkSaveBackups=false;
	config.options.chkSaveEmptyTemplate=false;
	config.options.chkToggleLinks=false;
	config.options.chkUsePreForStorage=true;
	config.options.txtBackupFolder="backups";
	config.options.txtCookieJar="CookieJar";
	config.options.txtEditorFocus="text";
	config.options.txtFileSystemCharSet="UTF-8";
	config.options.txtMainTab="Timeline";
	config.options.txtMaxEditRows="30";
	config.options.txtMoreTab="moreTabAll";
	config.options.txtTheme="";
	config.options.txtUserName="Savanni D'Gerinel";
//}}}
/***
|Name|CookieManagerPlugin|
|Source|http://www.TiddlyTools.com/#CookieManagerPlugin|
|Version|2.3.2|
|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|view/add/delete browser-based cookies and "bake" cookies to CookieJar tiddler for 'sticky' settings|
!!!!!Usage
<<<
This plugin provides an interactive control panel that lets you select, view, modify, or delete any of the current values for TiddlyWiki options that have been stored as local, private, //browser cookies//.  You can also use the control panel to "bake cookies", which generates a set of javascript statements that assign hard-coded option values to the TiddlyWiki internal variables that correspond to the current browser cookie settings.  These hard-coded values are then stored in the [[CookieJar]] tiddler, which is tagged with<<tag systemConfig>> so that each time the document is loaded, the baked cookie settings will be automatically applied.

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

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

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

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

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

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

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

// if removeOptionCookie() function is not defined by TW core, define it here.
if (window.removeOptionCookie===undefined) {
	window.removeOptionCookie=function(cookie) {
		var ex=new Date(); ex.setTime(ex.getTime()-1000);  // immediately expire cookie
		document.cookie = cookie+"=novalue; path=/; expires="+ex.toGMTString();
	}
}

// ... and then hijack it to add cookie blocking and monitoring messages
config.macros.cookieManager.removeOptionCookie=removeOptionCookie;
window.removeOptionCookie=function(name,force)
{
	var cmc=config.macros.cookieManager; // abbrev
	if (!cmc.getCookieList().contains(name))
		return; // not a current cookie!
	if (force || ((config.options.chkAllowBrowserCookies || name=="chkAllowBrowserCookies")
		&& !cmc.blockedCookies.contains(name) && cmc.allowBrowserCookie(name))) {
		cmc.removeOptionCookie.apply(this,arguments);
		cmc.displayStatus("deleted "+name);
	} else cmc.displayStatus("deletion of '"+name+"' is blocked");
}
//}}}
[[2010/02/02: Romance, Cleanse, and Felines]]
[[2010/01/21: Retreat]]
[[2009/12/09: Freezing but dry]]
[[2009/11/17: Magical bike moments]]
[[2009/11/12: Programming language exploration crash]]

/***
|Name|ExportTiddlersPlugin|
|Source|http://www.TiddlyTools.com/#ExportTiddlersPlugin|
|Documentation|http://www.TiddlyTools.com/#ExportTiddlersPluginInfo|
|Version|2.8.4|
|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.09.29 [2.8.4] in getData(), convert existing TW file from UTF8 to Unicode before merging to correct handling of international characters and symbols.
|please see [[ExportTiddlersPluginInfo]] for additional revision details|
2005.10.09 [0.0.0] development started
<<<
!!!!!Code
***/
//{{{
// version
version.extensions.ExportTiddlersPlugin= {major: 2, minor: 8, revision: 4, date: new Date(2008,9,29)};

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

// $(...) function: 'shorthand' convenience syntax for document.getElementById()
if (typeof($)=="undefined") { // avoid redefinition
function $() {
	var elements=new Array();
	for (var i=0; i<arguments.length; i++) {
		var element=arguments[i];
		if (typeof element=='string') element=document.getElementById(element);
		if (arguments.length==1) return element;
		elements.push(element);
	}
	return elements;
}
}

config.macros.exportTiddlers = {
	label: "export tiddlers",
	prompt: "Copy selected tiddlers to an export document",
	okmsg: "%0 tiddlers written to %1",
	failmsg: "An error occurred while creating %1",
	mergeprompt: "%0\nalready contains tiddler definitions.\n"
		+"\nPress OK to add new/revised tiddlers to current file contents."
		+"\nPress Cancel to completely replace file contents",
	mergestatus: "Merged %0 new/revised tiddlers with %1 previously saved tiddlers",
	statusmsg: "%0 tiddler%1 - %2 selected for export",
	newdefault: "export.html",
	datetimefmt: "0MM/0DD/YYYY 0hh:0mm:0ss",  // for "filter date/time" edit fields
	type_TW: "tw", type_PS: "ps", type_TX: "tx", type_NF: "nf", // file type tokens
	type_map: { // map filetype param alternatives/abbreviations to token values
		tiddlywiki:"tw", tw:"tw", wiki: "tw",
		purestore: "ps", ps:"ps", store:"ps",
		plaintext: "tx", tx:"tx", text: "tx",
		newsfeed:  "nf", nf:"nf", xml:  "nf", rss:"nf"
	},
	handler: function(place,macroName,params) {
		if (params[0]!="inline")
			{ createTiddlyButton(place,this.label,this.prompt,this.togglePanel); return; }
		var panel=this.createPanel(place);
		panel.style.position="static";
		panel.style.display="block";
	},
	createPanel: function(place) {
		var panel=$("exportPanel");
		if (panel) { panel.parentNode.removeChild(panel); }
		setStylesheet(this.css,"exportTiddlers");
		panel=createTiddlyElement(place,"span","exportPanel",null,null)
		panel.innerHTML=this.html;
		this.initFilter();
		this.refreshList(0);
		var fn=$("exportFilename");
		if (window.location.protocol=="file:" && !fn.value.length) {
			// get new target path/filename
			var newPath=getLocalPath(window.location.href);
			var slashpos=newPath.lastIndexOf("/"); if (slashpos==-1) slashpos=newPath.lastIndexOf("\\"); 
			if (slashpos!=-1) newPath=newPath.substr(0,slashpos+1); // trim filename
			fn.value=newPath+this.newdefault;
		}
		return panel;
	},
	togglePanel: function(e) {
		if (!e) var e = window.event;
		var parent=resolveTarget(e).parentNode;
		var panel = $("exportPanel");
		if (panel==undefined || panel.parentNode!=parent)
			panel=config.macros.exportTiddlers.createPanel(parent);
		var isOpen = panel.style.display=="block";
		if(config.options.chkAnimate)
			anim.startAnimating(new Slider(panel,!isOpen,e.shiftKey || e.altKey,"none"));
		else
			panel.style.display = isOpen ? "none" : "block" ;
		if (panel.style.display!="none") { // update list and set focus when panel is made visible
			config.macros.exportTiddlers.refreshList(0);
			var fn=$("exportFilename"); fn.focus(); fn.select();
		}
		e.cancelBubble = true;
		if (e.stopPropagation) e.stopPropagation();
		return(false);
	},
	css: '\
		#exportPanel {\
			display: none; position:absolute; z-index:12; width:35em; right:105%; top:6em;\
			background-color: #eee; color:#000; font-size: 8pt; line-height:110%;\
			border:1px solid black; border-bottom-width: 3px; border-right-width: 3px;\
			padding: 0.5em; margin:0em; -moz-border-radius:1em;-webkit-border-radius:1em;\
		}\
		#exportPanel a, #exportPanel td a { color:#009; display:inline; margin:0px; padding:1px; }\
		#exportPanel table { \
			width:100%; border:0px; padding:0px; margin:0px;\
			font-size:8pt; line-height:110%; background:transparent;\
		}\
		#exportPanel tr { border:0px;padding:0px;margin:0px; background:transparent; }\
		#exportPanel td { color:#000; border:0px;padding:0px;margin:0px; background:transparent; }\
		#exportPanel select { width:98%;margin:0px;font-size:8pt;line-height:110%;}\
		#exportPanel input  { width:98%;padding:0px;margin:0px;font-size:8pt;line-height:110%; }\
		#exportPanel textarea  { width:98%;padding:0px;margin:0px;overflow:auto;font-size:8pt; }\
		#exportPanel .box { \
			border:1px solid black; padding:3px; margin-bottom:5px; \
			background:#f8f8f8; -moz-border-radius:5px;-webkit-border-radius:5px; }\
		#exportPanel .topline { border-top:2px solid black; padding-top:3px; margin-bottom:5px; }\
		#exportPanel .rad { width:auto;border:0 }\
		#exportPanel .chk { width:auto;border:0 }\
		#exportPanel .btn { width:auto; }\
		#exportPanel .btn1 { width:98%; }\
		#exportPanel .btn2 { width:48%; }\
		#exportPanel .btn3 { width:32%; }\
		#exportPanel .btn4 { width:24%; }\
		#exportPanel .btn5 { width:19%; }\
	',
	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=config.macros.exportTiddlers.askForFilename(this); if (fn.length) this.previousSibling.value=fn; ">\
		</div>\
		<!-- output format -->\
		<div>\
		output file format:\
		<select id="exportFormat" size=1>\
			<option value="TW">TiddlyWiki HTML document (includes core code)</option>\
			<option value="PS">TiddlyWiki "PureStore" HTML file (tiddler data only)</option>\
			<option value="TX">TiddlyWiki plain text TXT file (tiddler source listing)</option>\
			<option value="NF">RSS NewsFeed XML file</option>\
		</select>\
		</div>\
		<!-- notes -->\
		<div>\
		notes:<br>\
		<textarea id="exportNotes" rows=3 cols=40 style="height:4em;margin-bottom:5px;" onfocus="this.select()"></textarea> \
		</div>\
		<!-- list of tiddlers -->\
		<table><tr align="left"><td>\
			select:\
			<a href="JavaScript:;" id="exportSelectAll"\
				onclick="config.macros.exportTiddlers.process(this)" title="select all tiddlers">\
				&nbsp;all&nbsp;</a>\
			<a href="JavaScript:;" id="exportSelectChanges"\
				onclick="config.macros.exportTiddlers.process(this)" title="select tiddlers changed since last save">\
				&nbsp;changes&nbsp;</a> \
			<a href="JavaScript:;" id="exportSelectOpened"\
				onclick="config.macros.exportTiddlers.process(this)" title="select tiddlers currently being displayed">\
				&nbsp;opened&nbsp;</a> \
			<a href="JavaScript:;" id="exportSelectRelated"\
				onclick="config.macros.exportTiddlers.process(this)" title="select tiddlers related to the currently selected tiddlers">\
				&nbsp;related&nbsp;</a> \
			<a href="JavaScript:;" id="exportToggleFilter"\
				onclick="config.macros.exportTiddlers.process(this)" title="show/hide selection filter">\
				&nbsp;filter&nbsp;</a>  \
		</td><td align="right">\
			<a href="JavaScript:;" id="exportListSmaller"\
				onclick="config.macros.exportTiddlers.process(this)" title="reduce list size">\
				&nbsp;&#150;&nbsp;</a>\
			<a href="JavaScript:;" id="exportListLarger"\
				onclick="config.macros.exportTiddlers.process(this)" title="increase list size">\
				&nbsp;+&nbsp;</a>\
		</td></tr></table>\
		<select id="exportList" multiple size="10" style="margin-bottom:5px;"\
			onchange="config.macros.exportTiddlers.refreshList(this.selectedIndex)">\
		</select><br>\
		</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="config.macros.exportTiddlers.process(this)" title="hide selection filter">hide</a>\
		</td></tr></table>\
		<div class="box">\
		<input type="checkbox" class="chk" id="exportFilterStart" value="1"\
			onclick="config.macros.exportTiddlers.showFilterFields(this)"> starting date/time<br>\
		<table cellpadding="0" cellspacing="0"><tr valign="center"><td width="50%">\
			<select size=1 id="exportFilterStartBy" \
				onchange="config.macros.exportTiddlers.showFilterFields(this);">\
				<option value="0">today</option>\
				<option value="1">yesterday</option>\
				<option value="7">a week ago</option>\
				<option value="30">a month ago</option>\
				<option value="file">file date</option>\
				<option value="other">other (mm/dd/yyyy hh:mm)</option>\
			</select>\
		</td><td width="50%">\
			<input type="text" id="exportStartDate" onfocus="this.select()"\
				onchange="$(\'exportFilterStartBy\').value=\'other\';">\
		</td></tr></table>\
		<input type="checkbox" class="chk" id="exportFilterEnd" value="1"\
			onclick="config.macros.exportTiddlers.showFilterFields(this)"> ending date/time<br>\
		<table cellpadding="0" cellspacing="0"><tr valign="center"><td width="50%">\
			<select size=1 id="exportFilterEndBy" \
				onchange="config.macros.exportTiddlers.showFilterFields(this);">\
				<option value="0">today</option>\
				<option value="1">yesterday</option>\
				<option value="7">a week ago</option>\
				<option value="30">a month ago</option>\
				<option value="file">file date</option>\
				<option value="other">other (mm/dd/yyyy hh:mm)</option>\
			</select>\
		</td><td width="50%">\
			<input type="text" id="exportEndDate" onfocus="this.select()"\
				onchange="$(\'exportFilterEndBy\').value=\'other\';">\
		</td></tr></table>\
		<input type="checkbox" class="chk" id=exportFilterTags value="1"\
			onclick="config.macros.exportTiddlers.showFilterFields(this)"> match tags<br>\
		<input type="text" id="exportTags" onfocus="this.select()">\
		<input type="checkbox" class="chk" id=exportFilterText value="1"\
			onclick="config.macros.exportTiddlers.showFilterFields(this)"> match titles/tiddler text<br>\
		<input type="text" id="exportText" onfocus="this.select()">\
		</div> <!--box-->\
		</div> <!--panel-->\
		<!-- action buttons -->\
		<div style="text-align:center">\
		<input type=button class="btn4" onclick="config.macros.exportTiddlers.process(this)"\
			id="exportFilter" value="apply filter">\
		<input type=button class="btn4" onclick="config.macros.exportTiddlers.process(this)"\
			id="exportStart" value="export tiddlers">\
		<input type=button class="btn4" onclick="config.macros.exportTiddlers.process(this)"\
			id="exportDelete" value="delete tiddlers">\
		<input type=button class="btn4" onclick="config.macros.exportTiddlers.process(this)"\
			id="exportClose" value="close">\
		</div><!--center-->\
	',
	process: function(which) { // process panel control interactions
		// DEBUG alert(which.id);
		var theList=$('exportList'); if (!theList) return;
		var count = 0;
		var total = store.getTiddlers('title').length;
		switch (which.id) {
			case 'exportFilter':
				count=this.filterExportList();
				var panel=$('exportFilterPanel');
				if (count==-1) { panel.style.display='block'; break; }
				$("exportStart").disabled=(count==0);
				$("exportDelete").disabled=(count==0);
				this.displayStatus(count,total);
				if (count==0) { alert("No tiddlers were selected"); panel.style.display='block'; }
				break;
			case 'exportStart':
				this.go();
				break;
			case 'exportDelete':
				this.deleteTiddlers();
				break;
			case 'exportHideFilter':
			case 'exportToggleFilter':
				var panel=$('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;
				}
				$("exportStart").disabled=(count==0);
				$("exportDelete").disabled=(count==0);
				this.displayStatus(count,total);
				if (count==0) alert("There are no unsaved changes");
				break;
			case 'exportSelectAll':
				for (var t = 0; t < theList.options.length; t++) {
					if (theList.options[t].value=="") continue;
					theList.options[t].selected=true;
					count += 1;
				}
				$("exportStart").disabled=(count==0);
				$("exportDelete").disabled=(count==0);
				this.displayStatus(count,count);
				break;
			case 'exportSelectOpened':
				for (var t = 0; t < theList.options.length; t++) theList.options[t].selected=false;
				var tiddlerDisplay = $("tiddlerDisplay"); // for TW2.1-
				if (!tiddlerDisplay) tiddlerDisplay = $("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;
					}
				}
				$("exportStart").disabled=(count==0);
				$("exportDelete").disabled=(count==0);
				this.displayStatus(count,total);
				if (count==0) alert("There are no tiddlers currently opened");
				break;
			case 'exportSelectRelated':
				// recursively build list of related tiddlers
				function getRelatedTiddlers(tid,tids) {
					var t=store.getTiddler(tid); if (!t || tids.contains(tid)) return tids;
					tids.push(t.title);
					if (!t.linksUpdated) t.changed();
					for (var i=0; i<t.links.length; i++)
						if (t.links[i]!=tid) tids=getRelatedTiddlers(t.links[i],tids);
					return tids;
				}
				// for all currently selected tiddlers, gather up the related tiddlers (including self) and select them as well
				var tids=[];
				for (var i=0; i<theList.options.length; i++)
					if (theList.options[i].selected) tids=getRelatedTiddlers(theList.options[i].value,tids);
				// select related tiddlers (includes original selected tiddlers)
				for (var i=0; i<theList.options.length; i++)
					theList.options[i].selected=tids.contains(theList.options[i].value);
				this.displayStatus(tids.length,total);
				break;
			case 'exportListSmaller':	// decrease current listbox size
				var min=5;
				theList.size-=(theList.size>min)?1:0;
				break;
			case 'exportListLarger':	// increase current listbox size
				var max=(theList.options.length>25)?theList.options.length:25;
				theList.size+=(theList.size<max)?1:0;
				break;
			case 'exportClose':
				$('exportPanel').style.display='none';
				break;
		}
	},
	displayStatus: function(count,total) {
		var txt=this.statusmsg.format([total,total!=1?'s':'',!count?"none":count==total?"all":count]);
		clearMessage();	displayMessage(txt);
		return txt;
	},
	refreshList: function(selectedIndex) {
		var theList = $("exportList"); if (!theList) return;
		// get the sort order
		var sort;
		if (!selectedIndex)   selectedIndex=0;
		if (selectedIndex==0) sort='modified';
		if (selectedIndex==1) sort='title';
		if (selectedIndex==2) sort='modified';
		if (selectedIndex==3) sort='modifier';
		if (selectedIndex==4) sort='tags';

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

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

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

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

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

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

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

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

		var show=$('exportFilterText').checked;
		$('exportText').style.display=show?"block":"none";
	},
	getFilterDate: function(val,id) {
		var result=0;
		switch (val) {
			case 'file':
				result=new Date(document.lastModified);
				break;
			case 'other':
				result=new Date($(id).value);
				break;
			default: // today=0, yesterday=1, one week=7, two weeks=14, a month=31
				var now=new Date(); var tz=now.getTimezoneOffset()*60000; now-=tz;
				var oneday=86400000;
				if (id=='exportStartDate')
					result=new Date((Math.floor(now/oneday)-val)*oneday+tz);
				else
					result=new Date((Math.floor(now/oneday)-val+1)*oneday+tz-1);
				break;
		}
		return result;
	},
	filterExportList: function() {
		var theList  = $("exportList"); if (!theList) return -1;
		var filterStart=$("exportFilterStart").checked;
		var val=$("exportFilterStartBy").value;
		var startDate=config.macros.exportTiddlers.getFilterDate(val,'exportStartDate');
		var filterEnd=$("exportFilterEnd").checked;
		var val=$("exportFilterEndBy").value;
		var endDate=config.macros.exportTiddlers.getFilterDate(val,'exportEndDate');
		var filterTags=$("exportFilterTags").checked;
		var tags=$("exportTags").value;
		var filterText=$("exportFilterText").checked;
		var text=$("exportText").value;
		if (!(filterStart||filterEnd||filterTags||filterText)) {
			alert("Please set the selection filter");
			$('exportFilterPanel').style.display="block";
			return -1;
		}
		if (filterStart&&filterEnd&&(startDate>endDate)) {
			var msg="starting date/time:\n"
			msg+=startDate.toLocaleString()+"\n";
			msg+="is later than ending date/time:\n"
			msg+=endDate.toLocaleString()
			alert(msg);
			return -1;
		}
		// if filter by tags, get list of matching tiddlers
		// use getMatchingTiddlers() (if MatchTagsPlugin is installed) for full boolean expressions
		// otherwise use getTaggedTiddlers() for simple tag matching
		if (filterTags) {
			var fn=store.getMatchingTiddlers||store.getTaggedTiddlers;
			var t=fn.apply(store,[tags]);
			var tagged=[];
			for (var i=0; i<t.length; i++) tagged.push(t[i].title);
		}
		// scan list and select tiddlers that match all applicable criteria
		var total=0;
		var count=0;
		for (var i=0; i<theList.options.length; i++) {
			// get item, skip non-tiddler list items (section headings)
			var opt=theList.options[i]; if (opt.value=="") continue;
			// get tiddler, skip missing tiddlers (this should NOT happen)
			var tiddler=store.getTiddler(opt.value); if (!tiddler) continue; 
			var sel=true;
			if ( (filterStart && tiddler.modified<startDate)
			|| (filterEnd && tiddler.modified>endDate)
			|| (filterTags && !tagged.contains(tiddler.title))
			|| (filterText && (tiddler.text.indexOf(text)==-1) && (tiddler.title.indexOf(text)==-1)))
				sel=false;
			opt.selected=sel;
			count+=sel?1:0;
			total++;
		}
		return count;
	},
	deleteTiddlers: function() {
		var list=$("exportList"); if (!list) return;
		var tids=[];
		for (i=0;i<list.length;i++)
			if (list.options[i].selected && list.options[i].value.length)
				tids.push(list.options[i].value);
		if (!confirm("Are you sure you want to delete these tiddlers:\n\n"+tids.join(', '))) return;
		store.suspendNotifications();
		for (t=0;t<tids.length;t++) {
			var tid=store.getTiddler(tids[t]); if (!tid) continue;
			var msg="'"+tid.title+"' is tagged with 'systemConfig'.\n\n";
			msg+="Removing this tiddler may cause unexpected results.  Are you sure?"
			if (tid.tags.contains("systemConfig") && !confirm(msg)) continue;
			store.removeTiddler(tid.title);
			story.closeTiddler(tid.title);
		}
		store.resumeNotifications();
		alert(tids.length+" tiddlers deleted");
		this.refreshList(0); // reload listbox
		store.notifyAll(); // update page display
	},
	go: function() {
		if (window.location.protocol!="file:") // make sure we are local
			{ displayMessage(config.messages.notFileUrlError); return; }
		// get selected tidders, target filename, target type, and notes
		var list=$("exportList"); if (!list) return;
		var tids=[]; for (var i=0; i<list.options.length; i++) {
			var opt=list.options[i]; if (!opt.selected||!opt.value.length) continue;
			var tid=store.getTiddler(opt.value); if (!tid) continue;
			tids.push(tid);
		}
		if (!tids.length) return; // no tiddlers selected
		var target = $("exportFilename").value.trim();
		if (!target.length) {
			displayMessage("A local target path/filename is required",target);
			return;
		}
		var filetype = $("exportFormat").value.toLowerCase();
		var notes=$("exportNotes").value.replace(/\n/g,"<br>");
		var total={val:0};
		var out=this.assembleFile(target,filetype,tids,notes,total);
		var link="file:///"+target.replace(/\\/g,'/');
		var samefile=link==decodeURIComponent(window.location.href);
		var p=getLocalPath(document.location.href);
		if (samefile) {
			if (config.options.chkSaveBackups) { var t=loadOriginal(p);if(t)saveBackup(p,t); }
			if (config.options.chkGenerateAnRssFeed && saveRss instanceof Function) saveRss(p);
		}
		var ok=saveFile(target,out);
		displayMessage((ok?this.okmsg:this.failmsg).format([total.val,target]),link);
	},
	plainTextHeader:
		 '// Source'+':\n//\t%0\n'
		+'// Title:\n//\t%1\n'
		+'// Subtitle:\n//\t%2\n'
		+'// Created:\n//\t%3 by %4\n'
		+'// Application:\n//\tTiddlyWiki %5 / %6 %7\n',
	plainTextTiddler:
		'\n// ----- %0 (by %1 on %2) -----\n\n%3',
	plainTextFooter:
		'',
	newsFeedHeader:
		 '<'+'?xml version="1.0"?'+'>\n'
		+'<rss version="2.0">\n'
		+'<channel>\n'
		+'<title>%1</title>\n'
		+'<link>%0</link>\n'
		+'<description>%2</description>\n'
		+'<language>en-us</language>\n'
		+'<copyright>Copyright '+(new Date().getFullYear())+' %4</copyright>\n'
		+'<pubDate>%3</pubDate>\n'
		+'<lastBuildDate>%3</lastBuildDate>\n'
		+'<docs>http://blogs.law.harvard.edu/tech/rss</docs>\n'
		+'<generator>TiddlyWiki %5 / %6 %7</generator>\n',
	newsFeedTiddler:
		'\n%0\n',
	newsFeedFooter:
		'</channel></rss>',
	pureStoreHeader:
		 '<html><body>'
		+'<style type="text/css">'
		+'	#storeArea {display:block;margin:1em;}'
		+'	#storeArea div {padding:0.5em;margin:1em;border:2px solid black;height:10em;overflow:auto;}'
		+'	#pureStoreHeading {width:100%;text-align:left;background-color:#eeeeee;padding:1em;}'
		+'</style>'
		+'<div id="pureStoreHeading">'
		+'	TiddlyWiki "PureStore" export file<br>'
		+'	Source'+': <b>%0</b><br>'
		+'	Title: <b>%1</b><br>'
		+'	Subtitle: <b>%2</b><br>'
		+'	Created: <b>%3</b> by <b>%4</b><br>'
		+'	TiddlyWiki %5 / %6 %7<br>'
		+'	Notes:<hr><pre>%8</pre>'
		+'</div>'
		+'<div id="storeArea">',
	pureStoreTiddler:
		'%0\n%1',
	pureStoreFooter:
		'</div><!--POST-BODY-START-->\n<!--POST-BODY-END--></body></html>',
	assembleFile: function(target,filetype,tids,notes,total) {
		var revised="";
		var now = new Date().toLocaleString();
		var src=convertUnicodeToUTF8(document.location.href);
		var title = convertUnicodeToUTF8(wikifyPlain("SiteTitle").htmlEncode());
		var subtitle = convertUnicodeToUTF8(wikifyPlain("SiteSubtitle").htmlEncode());
		var user = convertUnicodeToUTF8(config.options.txtUserName.htmlEncode());
		var twver = version.major+"."+version.minor+"."+version.revision;
		var v=version.extensions.ExportTiddlersPlugin; var pver = v.major+"."+v.minor+"."+v.revision;
		var headerargs=[src,title,subtitle,now,user,twver,"ExportTiddlersPlugin",pver,notes];
		switch (filetype) {
			case this.type_TX: // plain text
				var header=this.plainTextHeader.format(headerargs);
				var footer=this.plainTextFooter;
				break;
			case this.type_NF: // news feed (XML)
				headerargs[0]=store.getTiddlerText("SiteUrl","");
				var header=this.newsFeedHeader.format(headerargs);
				var footer=this.newsFeedFooter;
				break;
			case this.type_PS: // PureStore (no code)
				var header=this.pureStoreHeader.format(headerargs);
				var footer=this.pureStoreFooter;
				break;
			case this.type_TW: // full TiddlyWiki
			default:
				var currPath=getLocalPath(window.location.href);
				var original=loadFile(currPath);
				if (!original) { displayMessage(config.messages.cantSaveError); return; }
				var posDiv = locateStoreArea(original);
				if (!posDiv) { displayMessage(config.messages.invalidFileError.format([currPath])); return; }
				var header = original.substr(0,posDiv[0]+startSaveArea.length)+"\n";
				var footer = "\n"+original.substr(posDiv[1]);
				break;
		}
		var out=this.getData(target,filetype,tids);
		var revised = header+convertUnicodeToUTF8(out.join("\n"))+footer;
		// if full TW, insert page title and language attr, and reset all MARKUP blocks...
		if (filetype==this.type_TW) {
			var newSiteTitle=convertUnicodeToUTF8(getPageTitle()).htmlEncode();
			revised=revised.replaceChunk("<title"+">","</title"+">"," " + newSiteTitle + " ");
			revised=updateLanguageAttribute(revised);
			var titles=[]; for (var i=0; i<tids.length; i++) titles.push(tids[i].title);
			revised=updateMarkupBlock(revised,"PRE-HEAD",
				titles.contains("MarkupPreHead")? "MarkupPreHead" :null);
			revised=updateMarkupBlock(revised,"POST-HEAD",
				titles.contains("MarkupPostHead")?"MarkupPostHead":null);
			revised=updateMarkupBlock(revised,"PRE-BODY",
				titles.contains("MarkupPreBody")? "MarkupPreBody" :null);
			revised=updateMarkupBlock(revised,"POST-SCRIPT",
				titles.contains("MarkupPostBody")?"MarkupPostBody":null);
		}
		total.val=out.length;
		return revised;
	},
	formatItem: function(s,f,t,u) {
		if (f==this.type_TW)
			var r=s.getSaver().externalizeTiddler(s,t);
		if (f==this.type_PS)
			var r=config.macros.exportTiddlers.pureStoreTiddler.format([t.title,s.getSaver().externalizeTiddler(s,t)]);
		if (f==this.type_NF)
			var r=this.newsFeedTiddler.format([t.saveToRss(u)]);
		if (f==this.type_TX)
			var r=this.plainTextTiddler.format([t.title,t.modifier,t.modified.toLocaleString(),t.text]);
		return r||"";
	},
	getData: function(target,filetype,tids) {
		// output selected tiddlers and gather list of titles (for use with merge)
		var out=[]; var titles=[];
		var url=store.getTiddlerText("SiteUrl","");
		for (var i=0; i<tids.length; i++) {
			out.push(this.formatItem(store,filetype,tids[i],url));
			titles.push(tids[i].title);
		}
		// if TW or PureStore format, ask to merge with existing tiddlers (if any)
		if (filetype==this.type_TW || filetype==this.type_PS) {
			var text=loadFile(target);
			if (text && text.length) {
				var remoteStore=new TiddlyWiki();
				if (remoteStore.importTiddlyWiki(convertUTF8ToUnicode(text))
					&& confirm(this.mergeprompt.format([target]))) {
					var existing=remoteStore.getTiddlers("title");
					for (var i=0; i<existing.length; i++)
						if (!titles.contains(existing[i].title))
							out.push(this.formatItem(remoteStore,filetype,existing[i],url));
					displayMessage(this.mergestatus.format([tids.length,out.length-tids.length]));
				}
			}
		}
		return out;
	}
}
//}}}
<html>
<ul>
<li class="vcard"> <a href="http://www.stillpointaikido.com" class="fn org url">Still Point Aikido Center</a> </li>
<li class="vcard"> <a href="mailto:sevendaywondering@hotmail.com" rel="sweetheart" class="fn url">Terri Hudson</a> -- <span class="tags"><a href="http://kitchen.technorati.com/contacts/tag/Actress">Actress</a>, <a href="http://kitchen.technorati.com/contacts/tag/Beaded jewelry artist">Beaded jewelry artist</a>, <a href="http://kitchen.technorati.com/contacts/tag/Writer">Writer</a> </span> </li>
</html>
[<img[Chess Pieces picture|images/Chess.jpg]] Licensed under the GNU ~FDLPermission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation license, Version 1.2 or any later version published by the Free Software Foundation; with no Invariant Sections, no ~Front-Cover Texts, and no ~Back-Cover Texts. A copy of the license is included in the section entitled "GNU Free Documentation license

Just for reference, these are games that I like to play and would like to play more often. This list will obviously be updatde as my tastes change.

! Board/Card Games

* Chess
* Go
* Shadows over Camelot
* [[Homeworlds|http://icehousegames.org/wiki/?title=Homeworlds]]
* [[Gnostica|http://www.icehousegames.org/wiki/index.php?title=Gnostica]]
* Legend of the Five Rings
* Fluxx
* Munchkin
* Carcassonne
* Settlers of Catan

/***
|Name|ImagePathPlugin|
|Source|http://www.TiddlyTools.com/#ImagePathPlugin|
|Version|0.7.1|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|plugin,formatter|
|Requires||
|Overrides|'image' formatter|
|Description|Tell TiddlyWiki where to look for image files.  Permits multiple 'fallback' locations|
|Status|ALPHA - initial development/testing only - may be unstable - do not distribute|

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

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

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

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

Note: the image formatter code contained here also includes support for AttachFilePlugin extensions (if installed).  AttachFilePlugin includes its own fallback mechanism for handling embedded vs. local file vs. remote URL references to the attached binary file.  Both methods may be used: ImagePathPlugin provides fallback for images contained in tiddler content, while AttachFilePlugin works well for access to non-image binary files (or images used in CSS as backgrounds, textures, etc.)
<<<
!!!!!Examples
<<<
coming soon...
<<<
!!!!!Revisions
<<<
''2007.04.13 [0.7.1]'' in testFile(), convert any file:// references to local native format before checking for existence.
''2007.03.26 [0.7.0]'' for IE, use onError handling to trigger call to resolvePath() so it will only be invoked if the original path/file is not found by the browser-native lookup.  This avoids an unneeded call to fileExists() and the accompanying ActiveX security alert message box (as well as being slightly more efficient...)
''2007.03.25 [0.6.0]'' code cleanup (moved global functions into config.formatterHelpers) plus documentation re-write
''2007.03.24 [0.5.0]'' initial implementation - ALPHA - do not distribute
<<<
!!!!!Code
***/
//{{{
version.extensions.ImagePathPlugin= {major: 0, minor: 7, revision: 1, date: new Date(2007,4,13)};
//}}}
//{{{
// name of path definition tiddler
if (config.options.txtPathTiddler==undefined) config.options.txtPathTiddler="ImagePathList";
//}}}
//{{{
// low-level wrapper for platform-specific tests for local file existence
// returns true/false without visible error display
// Uses Components for FF and ActiveX FSO object for MSIE
// NOTE: this can cause a security warning on some browsers
config.formatterHelpers.fileExists=function(theFile) {
	var found=false;
	// DEBUG: alert('testing fileExists('+theFile+')...');
	if(window.Components) {
		try { netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); }
		catch(e) { return false; } // security access denied
		var file = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile);
		try { file.initWithPath(theFile); }
		catch(e) { return false; } // invalid directory
		found = file.exists();
	}
	else { // use ActiveX FSO object for MSIE 
		var fso = new ActiveXObject("Scripting.FileSystemObject");
		found = fso.FileExists(theFile)
	}
	// DEBUG: alert(theFile+" "+(found?"exists":"not found"));
	return found;
}
//}}}
//{{{
// higher-level logic for checking local file existence.
// with secondary check for finding relative file references
// and automatic OK of http-based references without checking local filesystem
config.formatterHelpers.testFile=function(theFile) {
	if (document.location.protocol!="file:") return true; // viewing remote document, can't test local filesystem... assume OK
	if (theFile.substr(0,5)=="http:") return true; // remote HTTP reference... assume OK
	if (theFile.substr(0,5)=="file:") theFile=getLocalPath(theFile); // convert local FILE reference to native format
	if (this.fileExists(theFile)) return true; // file exists locally... OK to use!
	// file might have been relative, add path from current document and try again
	var docPath=document.location.href;
	var slashpos=docPath.lastIndexOf("/"); if (slashpos==-1) slashpos=docPath.lastIndexOf("\\"); 
	if (slashpos!=-1 && slashpos!=docPath.length-1) docPath=docPath.substr(0,slashpos+1); // trim off filename
	if (this.fileExists(getLocalPath(docPath+theFile)))
		return true; // ah ha!... file exists relative to current document... OK to use!
	return false; // file not found on local system
}
//}}}
//{{{
// given a path/file string, check for existence and
// try alternatives (if any) defined in a tiddler
// with last-ditch using system/path from SiteUrl (if any)
config.formatterHelpers.resolvePath=function(theFile,testoriginal) {
	if (testoriginal && this.testFile(theFile)) return theFile; // FOUND FILE - use specified path/file without modification
	// get the filename portion only
	var slashpos=theFile.lastIndexOf("/"); if (slashpos==-1) slashpos=theFile.lastIndexOf("\\"); 
	var theName=(slashpos==-1)?theFile:theFile.substr(slashpos+1);
	// get list of fallbacks (if any)
	var pathText=store.getTiddlerText(config.options.txtPathTiddler);
	if (pathText && pathText.length) {
		var paths=pathText.split("\n");
		for (p=0; p<paths.length; p++) // combine path+filename until one works...
			if (this.testFile(paths[p]+theName))
				return paths[p]+theName; // FOUND FILE - use alternative path+filename
	}
	// try "last ditch" fallback using SiteURL - assumes that original path/file was relative to document location
	var siteURL=store.getTiddlerText("SiteUrl");
	if (!siteURL||!siteURL.length) return theFile; // NO FALLBACK - use original path/file and hope for the best
	// trim filename (if any) from site URL
	var slashpos=siteURL.lastIndexOf("/"); if (slashpos==-1) slashpos=siteURL.lastIndexOf("\\"); 
	if (slashpos!=-1 && slashpos!=siteURL.length-1) siteURL=siteURL.substr(0,slashpos+1);
	return siteURL+theFile; // LAST DITCH: use system/path from SiteUrl combined with original file/path
}
//}}}
//{{{
// replace standard handler for image formatter
// adds call to resolvePath() to handle fallback processing
// includes support for AttachFilePlugin as well
config.formatters[config.formatters.findByField("name","image")].handler=function(w) {
	if (!this.lookaheadRegExp)  // fixup for TW2.0.x
		this.lookaheadRegExp = new RegExp(this.lookahead,"mg");
	this.lookaheadRegExp.lastIndex = w.matchStart;
	var lookaheadMatch = this.lookaheadRegExp.exec(w.source)
	if(lookaheadMatch && lookaheadMatch.index == w.matchStart) {
		// Simple bracketted link
		var e = w.output;
		if(lookaheadMatch[5]) {
			var link = lookaheadMatch[5];
			if (!config.formatterHelpers.isExternalLink) // fixup for TW2.0.x
				var external=!store.tiddlerExists(link)&&!store.isShadowTiddler(link);
			else
				var external=config.formatterHelpers.isExternalLink(link);
			if (external) {
				if (config.macros.attach && config.macros.attach.isAttachment(link)) { // ELS - attachments
					e = createExternalLink(w.output,link);
					e.href=config.macros.attach.getAttachment(link);
					e.title = config.macros.attach.linkTooltip + link;
				} else
					e = createExternalLink(w.output,link);
			} else 
				e = createTiddlyLink(w.output,link,false,null,w.isStatic);
			addClass(e,"imageLink");
		}
		var img = createTiddlyElement(e,"img");
		if(lookaheadMatch[1])
			img.align = "left";
		else if(lookaheadMatch[2])
			img.align = "right";
		if(lookaheadMatch[3])
			img.title = lookaheadMatch[3];
		if (config.macros.attach!=undefined && config.macros.attach.isAttachment(lookaheadMatch[4])) // ELS - attachments
			img.src=config.macros.attach.getAttachment(lookaheadMatch[4]);
		else {
			if (config.browser.isIE || config.browser.isSafari) { // ELS - path processing
				// IE and Safari use browser's onError handling to check the original file...
				// avoids extra security alert messages due to use of Components/ActiveX for filesystem access
				img.onerror=(function(){this.src=config.formatterHelpers.resolvePath(this.src,false);return false;});
				img.src=lookaheadMatch[4]; // ELS - path processing
			} else {
				// if NOT IE or Safari, always check the original path/file before rendering
				img.src=config.formatterHelpers.resolvePath(lookaheadMatch[4],true);
			}
		}
		w.nextMatch = this.lookaheadRegExp.lastIndex;
	}
}
//}}}
/***
|Name|ImageSizePlugin|
|Source|http://www.TiddlyTools.com/#ImageSizePlugin|
|Version|1.1.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,formatter|
|Requires||
|Overrides|'image' formatter|
|Description|extends image syntax to add optional CSS width/height values|
!!!!!Usage
<<<
Extends standard TiddlyWiki image syntax, ''{{{[img[...]]}}}'', so you can specify CSS width/height values.

The extended syntax is:
>''{{{[img(x,y)[...]]}}}''
>where x and y are the desired width and height of the image, specified using CSS units of measurement (e.g., px, em, cm, in, or %).  Use ''auto'' for either the width or height to scale image proportionally (i.e., maintain aspect ratio).  You may also calculate a CSS value on-the-fly by using //evaluated javascript//, enclosed between """{{""" and """}}""", e.g, {{{({{widthFunction()}},{{heightFunction()}})}}}.

Note: this plugin also includes enhancements to support:
*[[AttachFilePluginFormatters]] (embed image files as text-encoded tiddlers)
* [[ImagePathPlugin]] (fallback locations for missing images)
Please refer to those plugins for details...
<<<
!!!!!Examples
<<<
{{{
[<img(34%,auto)[images/meow.gif]]
[<img(21%,auto)[images/meow.gif]]
[<img(13%,auto)[images/meow.gif]]
[<img(8%,auto)[images/meow.gif]]
[<img(5%,auto)[images/meow.gif]]
[<img(3%,auto)[images/meow.gif]]
[<img(2%,auto)[images/meow.gif]]
[img(1%,auto)[images/meow.gif]]
}}}
[<img(34%,auto)[images/meow.gif]]
[<img(21%,auto)[images/meow.gif]]
[<img(13%,auto)[images/meow.gif]]
[<img(8%,auto)[images/meow.gif]]
[<img(5%,auto)[images/meow.gif]]
[<img(3%,auto)[images/meow.gif]]
[<img(2%,auto)[images/meow.gif]]
[img(1%,auto)[images/meow.gif]]
{{clear block{}}}
<<<
!!!!!Revisions
<<<
2008.01.19 [1.1.0] added support for evaluated width/height values!!
2008.01.18 [1.0.1] code cleanup plus improved regexp for matching "(width,height)" by eliminating hard-coded recognition of [px,em,cm,in,%] CSS units.  Syntax now accepts ANY values for width/height, and leaves it to the browser's CSS processing to handle any invalid values.
2008.01.17 [1.0.0] initial release
<<<
!!!!!Code
***/
//{{{
version.extensions.ImageSizePlugin= {major: 1, minor: 1, revision: 0, date: new Date(2008,1,19)};

// replace standard handler for image formatter
// note: includes modifications for [[AttachFilePluginFormatters]] AND [[ImagePathPlugin]]
var f=config.formatters.findByField("name","image");
config.formatters[f].match="\\[[<>]?[Ii][Mm][Gg](?:\\([^,]*,[^\\)]*\\))?\\[";
config.formatters[f].lookaheadRegExp=/\[([<]?)(>?)[Ii][Mm][Gg](\([^,]*,[^\)]*\))?\[(?:([^\|\]]+)\|)?([^\[\]\|]+)\](?:\[([^\]]*)\])?\]/mg;
config.formatters[f].handler=function(w) {
	this.lookaheadRegExp.lastIndex = w.matchStart;
	var lookaheadMatch = this.lookaheadRegExp.exec(w.source)
	if(lookaheadMatch && lookaheadMatch.index == w.matchStart) {
		var floatLeft=lookaheadMatch[1];
		var floatRight=lookaheadMatch[2];
		var XY=lookaheadMatch[3];
		var tooltip=lookaheadMatch[4];
		var src=lookaheadMatch[5];
		var link=lookaheadMatch[6];
		// Simple bracketted link
		var e = w.output;
		if(link) { // LINKED IMAGE
			if (config.formatterHelpers.isExternalLink(link)) {
				if (config.macros.attach && config.macros.attach.isAttachment(link)) {
					// see [[AttachFilePluginFormatters]]
					e = createExternalLink(w.output,link);
					e.href=config.macros.attach.getAttachment(link);
					e.title = config.macros.attach.linkTooltip + link;
				} else
					e = createExternalLink(w.output,link);
			} else 
				e = createTiddlyLink(w.output,link,false,null,w.isStatic);
			addClass(e,"imageLink");
		}
		var img = createTiddlyElement(e,"img");
		if(floatLeft) img.align="left"; else if(floatRight) img.align="right"; // FLOAT LEFT/RIGHT
		if(XY) { // CUSTOM SIZE with optional EVAL'ED width/height ({{...}},{{...}})
			var parts=XY.replace(/[\(\)]/g,'').split(","); var x=parts[0]; var y=parts[1];
			if (x.substr(0,2)=="{{") {
				try{img.style.width=eval(x.substr(2,x.length-4));}
				catch(e){displayMessage(e.description||e.toString())}
			} else img.style.width=x;

			if (y.substr(0,2)=="{{") {
				try{img.style.height=eval(y.substr(2,y.length-4));}
				catch(e){displayMessage(e.description||e.toString())}
			} else img.style.height=y;
		}
		if(tooltip) img.title = tooltip; // TOOLTIP
		// GET IMAGE SOURCE (get attachment or resolve fallback path as needed)
		if (config.macros.attach && config.macros.attach.isAttachment(src))
			src=config.macros.attach.getAttachment(src); // see [[AttachFilePluginFormatters]]
		else if (config.formatterHelpers.resolvePath) { // see [[ImagePathPlugin]]
			// Note: IE and Safari use onError to call resolvePath() only if initial lookup fails
			// (avoids security messages for initial filesystem access)... otherwise, attempt to
			// resolve the original path/file before initial rendering
			if (config.browser.isIE || config.browser.isSafari) {
				img.onerror=(function(){
					this.src=config.formatterHelpers.resolvePath(this.src,false);
					return false;
				});
			} else
				src=config.formatterHelpers.resolvePath(lookaheadMatch[5],true);
		}
		img.src=src; // RENDER IMAGE
		w.nextMatch = this.lookaheadRegExp.lastIndex;
	}
}
//}}}
/***
|Name|ImportTiddlersPlugin|
|Source|http://www.TiddlyTools.com/#ImportTiddlersPlugin|
|Documentation|http://www.TiddlyTools.com/#ImportTiddlersPluginInfo|
|Version|4.4.0|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|plugin|
|Requires||
|Overrides|config.macros.importTiddlers.handler|
|Description|interactive controls for import/export with filtering.|
This plugin lets you selectively combine tiddlers from any two TiddlyWiki documents.  An interactive control panel lets you pick a document to import from, and then select which tiddlers to import, with prompting for skip, rename, merge or replace actions when importing tiddlers that match existing titles.  Automatically add tags to imported tiddlers so they are easy to find later on.  Generates a detailed report of import 'history' in ImportedTiddlers.
!!!!!Documentation
<<<
see [[ImportTiddlersPluginInfo]] for details
<<<
!!!!!interactive control panel:
<<<
<<importTiddlers inline>>
{{clear{
^^(see also: [[ImportTiddlers]] shadow tiddler)^^}}}
<<<
!!!!!Installation Notes
<<<
* As of 6/27/2007, "patch" functions that provide backward-compatibility with TW2.1.x and earlier have been split into a separate [[ImportTiddlersPluginPatch]] tiddler to reduce installation overhead for //this// plugin.  You only need to install the additional plugin tiddler when using ImportTiddlersPlugin in documents using TW2.1.x or earlier.
* As of 3/21/2007, the interactive {{{<<importTiddlers>>}}} and non-interactive {{{<<loadTiddlers>>}}} macro definitions and related code have been split into separate [[ImportTiddlersPlugin]] and [[LoadTiddlersPlugin]] to permit selective installation of either the interactive and/or non-interactive macro functions.
* Quick Installation Tip: If you are using an unmodified version of TiddlyWiki (core release version <<version>>), you can get a new, empty TiddlyWiki with the Import Tiddlers plugin pre-installed (''[[download from here|TW+ImportExport.html]]''), and then simply import all your content from your old document into this new, empty document.
<<<
!!!!!Revisions
<<<
2008.09.30 [4.4.0] added fallback definition of merge() for use with TW2.0.x and TW1.2.x
2008.08.12 [4.3.3] rewrite backstage and shadow tiddler definitions for easier customization
|please see [[ImportTiddlersPluginInfo]] for additional revision details|
2005.07.20 [1.0.0] Initial Release
<<<
!!!!!Code
***/
//{{{
version.extensions.ImportTiddlersPlugin= {major: 4, minor: 4, revision: 0, date: new Date(2008,8,30)};

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

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

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

// use shadow tiddler content in backstage panel
if (config.tasks) config.tasks.importTask.content="<<tiddler ImportTiddlers>>" // TW2.2 or above

// $(...) function: 'shorthand' convenience syntax for document.getElementById()
if (typeof($)=="undefined") { // avoid redefinition
window.$ = function() {
	var elements=new Array();
	for (var i=0; i<arguments.length; i++) {
		var element=arguments[i];
		if (typeof element=='string') element=document.getElementById(element);
		if (arguments.length==1) return element;
		elements.push(element);
	}
	return elements;
}
}
//}}}
//{{{
// backward-compatiblity for TW2.0.x and TW1.2.x
if (config.macros.importTiddlers==undefined)
	config.macros.importTiddlers={};
if (typeof merge=="undefined") {
	function merge(dst,src,preserveExisting) {
		for(var i in src)
			{ if(!preserveExisting || dst[i] === undefined) dst[i] = src[i]; }
		return dst;
	}
}
if (config.browser.isGecko===undefined)
	config.browser.isGecko=(config.userAgent.indexOf('gecko')!=-1);
//}}}
//{{{
merge(config.macros.importTiddlers,{
	label: "import tiddlers",
	prompt: "Copy tiddlers from another document",
	openMsg: "Opening %0",
	openErrMsg: "Could not open %0 - error=%1",
	readMsg: "Read %0 bytes from %1",
	foundMsg: "Found %0 tiddlers in %1",
	filterMsg: "Filtered %0 tiddlers matching '%1'",
	summaryMsg: "%0 tiddler%1 in the list",
	summaryFilteredMsg: "%0 of %1 tiddler%2 in the list",
	plural: "s are",
	single: " is",
	countMsg: "%0 tiddlers selected for import",
	processedMsg: "Processed %0 tiddlers",
	importedMsg: "Imported %0 of %1 tiddlers from %2",
	loadText: "please load a document...",
	closeText: "close",
	doneText: "done",
	startText: "import",
	stopText: "stop",
	local: true,		// default to import from local file
	src: "",		// path/filename or URL of document to import (retrieved from SiteUrl)
	proxy: "",		// URL for remote proxy script (retrieved from SiteProxy)
	useProxy: false,	// use specific proxy script in front of remote URL
	inbound: null,		// hash-indexed array of tiddlers from other document
	newTags: "",		// text of tags added to imported tiddlers
	addTags: true,		// add new tags to imported tiddlers
	listsize: 10,		// # of lines to show in imported tiddler list
	importTags: true,	// include tags from remote source document when importing a tiddler
	keepTags: true,		// retain existing tags when replacing a tiddler
	sync: false,		// add 'server' fields to imported tiddlers (for sync function)
	lastFilter: "",		// most recent filter (URL hash) applied
	lastAction: null,	// most recent collision button performed
	index: 0,		// current processing index in import list
	sort: ""		// sort order for imported tiddler listbox
});
//}}}
//{{{
// replace core macro handler
if (config.macros.importTiddlers.coreHandler==undefined)
	config.macros.importTiddlers.coreHandler=config.macros.importTiddlers.handler; // save built-in handler
config.macros.importTiddlers.handler = function(place,macroName,params,wikifier,paramString,tiddler) {
	if (!params[0] || params[0].toLowerCase()=='core') { // default to built in
		if (config.macros.importTiddlers.coreHandler)
			config.macros.importTiddlers.coreHandler.apply(this,arguments);
		else 
			createTiddlyButton(place,this.label,this.prompt,onClickImportMenu);
	} else if (params[0]=='link') { // show link to floating panel
		createTiddlyButton(place,params[1]||this.label,params[2]||this.prompt,onClickImportMenu);
	} else if (params[0]=='inline') {// show panel as INLINE tiddler content
		createImportPanel(place);
		$("importPanel").style.position="static";
		$("importPanel").style.display="block";
	} else if (config.macros.loadTiddlers)
		config.macros.loadTiddlers.handler(place,macroName,params); // any other params: loadtiddlers
}
//}}}
//{{{
// Handle link click to create/show/hide control panel
function onClickImportMenu(e)
{
	if (!e) var e = window.event;
	var parent=resolveTarget(e).parentNode;
	var panel = $("importPanel");
	if (panel==undefined || panel.parentNode!=parent)
		panel=createImportPanel(parent);
	var isOpen = panel.style.display=="block";
	if(config.options.chkAnimate)
		anim.startAnimating(new Slider(panel,!isOpen,e.shiftKey || e.altKey,"none"));
	else
		panel.style.display = isOpen ? "none" : "block" ;
	e.cancelBubble = true;
	if (e.stopPropagation) e.stopPropagation();
	return(false);
}
//}}}
//{{{
// Create control panel: HTML, CSS
function createImportPanel(place) {
	var cmi=config.macros.importTiddlers; // abbreviation
	var panel=$("importPanel");
	if (panel) { panel.parentNode.removeChild(panel); }
	setStylesheet(cmi.css,"importTiddlers");
	panel=createTiddlyElement(place,"span","importPanel",null,null)
	panel.innerHTML=cmi.html;
	refreshImportList();
	var siteURL=store.getTiddlerText("SiteUrl"); if (!siteURL) siteURL="";
	$("importSourceURL").value=siteURL;
	cmi.src=siteURL;
	var siteProxy=store.getTiddlerText("SiteProxy"); if (!siteProxy) siteProxy="SiteProxy";
	$("importSiteProxy").value=siteProxy;
	cmi.proxy=siteProxy;
	if (config.browser.isGecko) { // FF3 FIXUP
		$("fileImportSource").style.display="none";
		$("importLocalPanelFix").style.display="block";
	}
	return panel;
}
//}}}
//{{{
config.macros.importTiddlers.css = '\
#importPanel {\
	display: none; position:absolute; z-index:11; width:35em; right:105%; top:3em;\
	background-color: #eee; color:#000; font-size: 8pt; line-height:110%;\
	border:1px solid black; border-bottom-width: 3px; border-right-width: 3px;\
	padding: 0.5em; margin:0em; -moz-border-radius:1em;-webkit-border-radius:1em;\
}\
#importPanel a, #importPanel td a { color:#009; display:inline; margin:0px; padding:1px; }\
#importPanel table { width:100%; border:0px; padding:0px; margin:0px; font-size:8pt; line-height:110%; background:transparent; }\
#importPanel tr { border:0px;padding:0px;margin:0px; background:transparent; }\
#importPanel td { color:#000; border:0px;padding:0px;margin:0px; background:transparent; }\
#importPanel select { width:100%;margin:0px;font-size:8pt;line-height:110%;}\
#importPanel input  { width:98%;padding:0px;margin:0px;font-size:8pt;line-height:110%}\
#importPanel .box { border:1px solid #000; background-color:#eee; padding:3px 5px; margin-bottom:5px; -moz-border-radius:5px;-webkit-border-radius:5px;}\
#importPanel .topline { border-top:1px solid #999; padding-top:2px; margin-top:2px; }\
#importPanel .rad { width:auto; }\
#importPanel .chk { width:auto; margin:1px;border:0; }\
#importPanel .btn { width:auto; }\
#importPanel .btn1 { width:98%; }\
#importPanel .btn2 { width:48%; }\
#importPanel .btn3 { width:32%; }\
#importPanel .btn4 { width:23%; }\
#importPanel .btn5 { width:19%; }\
#importPanel .importButton { padding: 0em; margin: 0px; font-size:8pt; }\
#importPanel .importListButton { padding:0em 0.25em 0em 0.25em; color: #000000; display:inline }\
#backstagePanel #importPanel { left:10%; right:auto; }\
';
//}}}
//{{{
config.macros.importTiddlers.html = '\
<!-- source and report -->\
<table><tr><td align=left>\
	import from\
	<input type="radio" class="rad" name="importFrom" id="importFromFile" value="file" CHECKED\
		onclick="onClickImportButton(this,event)" title="show file controls"> local file\
	<input type="radio" class="rad" name="importFrom" id="importFromWeb"  value="http"\
		onclick="onClickImportButton(this,event)" title="show web controls"> web server\
</td><td align=right>\
	<input type=checkbox class="chk" id="chkImportReport" checked\
		onClick="config.options[\'chkImportReport\']=this.checked;"> create report\
</td></tr></table>\
\
<div class="box" id="importSourcePanel" style="margin:.5em">\
<div id="importLocalPanel" style="display:block;margin-bottom:2px;"><!-- import from local file  -->\
enter or browse for source path/filename<br>\
<input type="file" id="fileImportSource" size=57 style="width:100%"\
	onKeyUp="config.macros.importTiddlers.src=this.value"\
	onChange="config.macros.importTiddlers.src=this.value;$(\'importLoad\').onclick()">\
<div id="importLocalPanelFix" style="display:none"><!-- FF3 FIXUP -->\
	<input type="text" id="fileImportSourceFix" style="width:90%"\
		title="Enter a path/file to import"\
		onKeyUp="config.macros.importTiddlers.src=this.value"\
		onChange="config.macros.importTiddlers.src=this.value; $(\'importLoad\').onclick()">\
	<input type="button" id="fileImportSourceFixButton" style="width:7%" value="..."\
		title="Select a path/file to import"\
		onClick="var r=config.macros.importTiddlers.askForFilename(this); if (!r||!r.length) return;\
			$(\'fileImportSourceFix\').value=r;\
			config.macros.importTiddlers.src=r;\
			$(\'importLoad\').onclick()">\
</div><!--end FF3 FIXUP-->\
</div><!--end local-->\
<div id="importHTTPPanel" style="display:none;margin-bottom:2px;"><!-- import from http server -->\
<table><tr><td align=left>\
	enter a URL or <a href="javascript:;" id="importSelectFeed"\
		onclick="onClickImportButton(this,event)" title="select a pre-defined \'systemServer\' URL">\
		select a server</a><br>\
</td><td align=right>\
	<input type="checkbox" class="chk" id="importUsePassword"\
		onClick="config.macros.importTiddlers.usePassword=this.checked;\
			config.macros.importTiddlers.showPanel(\'importIDPWPanel\',this.checked,true);">password\
	<input type="checkbox" class="chk" id="importUseProxy"\
		onClick="config.macros.importTiddlers.useProxy=this.checked;\
			config.macros.importTiddlers.showPanel(\'importSiteProxy\',this.checked,true);">proxy\
</td></tr></table>\
<input type="text" id="importSiteProxy" style="display:none;margin-bottom:1px" onfocus="this.select()" value="SiteProxy"\
	onKeyUp="config.macros.importTiddlers.proxy=this.value"\
	onChange="config.macros.importTiddlers.proxy=this.value;">\
<input type="text" id="importSourceURL" onfocus="this.select()" value="SiteUrl"\
	onKeyUp="config.macros.importTiddlers.src=this.value"\
	onChange="config.macros.importTiddlers.src=this.value;">\
<div id="importIDPWPanel" style="text-align:center;margin-top:2px;display:none";>\
username: <input type=text id="txtImportID" style="width:25%" \
	onChange="config.options.txtRemoteUsername=this.value;">\
 password: <input type=password id="txtImportPW" style="width:25%" \
	onChange="config.options.txtRemotePassword=this.value;">\
</div><!--end idpw-->\
</div><!--end http-->\
</div><!--end source-->\
\
<div class="box" id="importSelectPanel" style="display:none;margin:.5em;">\
<table><tr><td align=left>\
select:\
<a href="javascript:;" id="importSelectAll"\
	onclick="onClickImportButton(this);return false;" title="SELECT all tiddlers">\
	all</a>\
&nbsp;<a href="javascript:;" id="importSelectNew"\
	onclick="onClickImportButton(this);return false;" title="SELECT tiddlers not already in destination document">\
	added</a>\
&nbsp;<a href="javascript:;" id="importSelectChanges"\
	onclick="onClickImportButton(this);return false;" title="SELECT tiddlers that have been updated in source document">\
	changes</a>\
&nbsp;<a href="javascript:;" id="importSelectDifferences"\
	onclick="onClickImportButton(this);return false;" title="SELECT tiddlers that have been added or are different from existing tiddlers">\
	differences</a>\
</td><td align=right>\
<a href="javascript:;" id="importListSmaller"\
	onclick="onClickImportButton(this);return false;" title="SHRINK list size">\
	&nbsp;&#150;&nbsp;</a>\
<a href="javascript:;" id="importListLarger"\
	onclick="onClickImportButton(this);return false;" title="GROW list size">\
	&nbsp;+&nbsp;</a>\
<a href="javascript:;" id="importListMaximize"\
	onclick="onClickImportButton(this);return false;" title="MAXIMIZE/RESTORE list size">\
	&nbsp;=&nbsp;</a>\
</td></tr></table>\
<select id="importList" size=8 multiple\
	onchange="setTimeout(\'refreshImportList(\'+this.selectedIndex+\')\',1)">\
	<!-- NOTE: delay refresh so list is updated AFTER onchange event is handled -->\
</select>\
<div style="text-align:center">\
	<a href="javascript:;"\
		title="click for help using filters..."\
		onclick="alert(\'A filter consists of one or more space-separated combinations of:\\n\\ntiddler titles\\ntag:[[tagvalue]]\\ntag:[[tag expression]] (requires MatchTagsPlugin)\\nstory:[[TiddlerName]]\\nsearch:[[searchtext]]\\n\\nUse a blank filter for all tiddlers.\')"\
	>filter</a>\
	<input type="text" id="importLastFilter" style="margin-bottom:1px; width:65%"\
		title="Enter a combination of one or more filters. Use a blank filter for all tiddlers."\
		onfocus="this.select()" value=""\
		onKeyUp="config.macros.importTiddlers.lastFilter=this.value"\
		onChange="config.macros.importTiddlers.lastFilter=this.value;">\
	<input type="button" id="importApplyFilter" style="width:20%" value="apply"\
		title="filter list of tiddlers to include only those that match certain criteria"\
		onclick="onClickImportButton(this)">\
	</div>\
</div><!--end select-->\
\
<div class="box" id="importOptionsPanel" style="text-align:center;margin:.5em;display:none;">\
	apply tags: <input type=checkbox class="chk" id="chkImportTags" checked\
		onClick="config.macros.importTiddlers.importTags=this.checked;">from source&nbsp;\
	<input type=checkbox class="chk" id="chkKeepTags" checked\
		onClick="config.macros.importTiddlers.keepTags=this.checked;">keep existing&nbsp;\
	<input type=checkbox class="chk" id="chkAddTags" \
		onClick="config.macros.importTiddlers.addTags=this.checked;\
			config.macros.importTiddlers.showPanel(\'txtNewTags\',this.checked,true);\
			if (this.checked) $(\'txtNewTags\').focus();">add tags<br>\
	<input type=text id="txtNewTags" style="margin-top:4px;display:none;" size=15\ onfocus="this.select()" \
		title="enter tags to be added to imported tiddlers" \
		onKeyUp="config.macros.importTiddlers.newTags=this.value;\
		$(\'chkAddTags\').checked=this.value.length>0;" autocomplete=off>\
	<nobr><input type=checkbox class="chk" id="chkSync" \
		onClick="config.macros.importTiddlers.sync=this.checked;">\
		link imported tiddlers to source document (for sync later)</nobr>\
</div><!--end options-->\
\
<div id="importButtonPanel" style="text-align:center">\
	<input type=button id="importLoad"	class="importButton btn3" value="open"\
		title="load listbox with tiddlers from source document"\
		onclick="onClickImportButton(this)">\
	<input type=button id="importOptions"	class="importButton btn3" value="options..."\
		title="set options for tags, sync, etc."\
		onclick="onClickImportButton(this)">\
	<input type=button id="importStart"	class="importButton btn3" value="import"\
		title="start/stop import of selected source tiddlers into current document"\
		onclick="onClickImportButton(this)">\
	<input type=button id="importClose"	class="importButton btn3" value="done"\
		title="clear listbox or hide control panel"\
		onclick="onClickImportButton(this)">\
</div>\
\
<div class="none" id="importCollisionPanel" style="display:none;margin:.5em 0 .5em .5em;">\
	<table><tr><td style="width:65%" align="left">\
		<table><tr><td align=left>\
			tiddler already exists:\
		</td><td align=right>\
			<input type=checkbox class="chk" id="importApplyToAll" \
			onclick="$(\'importRename\').disabled=this.checked;"\
			checked>apply to all\
		</td></tr></table>\
		<input type=text id="importNewTitle" size=15 autocomplete=off">\
	</td><td style="width:34%" align="center">\
		<input type=button id="importMerge"\
			class="importButton" style="width:47%" value="merge"\
			title="append the incoming tiddler to the existing tiddler"\
			onclick="onClickImportButton(this)"><!--\
		--><input type=button id="importSkip"\
			class="importButton" style="width:47%" value="skip"\
			title="do not import this tiddler"\
			onclick="onClickImportButton(this)"><!--\
		--><br><input type=button id="importRename"\
			class="importButton" style="width:47%" value="rename"\
			title="rename the incoming tiddler"\
			onclick="onClickImportButton(this)"><!--\
		--><input type=button id="importReplace"\
			class="importButton" style="width:47%" value="replace"\
			title="discard the existing tiddler"\
			onclick="onClickImportButton(this)">\
	</td></tr></table>\
</div><!--end collision-->\
';
//}}}
//{{{
// process control interactions
function onClickImportButton(which,event)
{
	var cmi=config.macros.importTiddlers; // abbreviation

	var list = $('importList');
	if (!list) return;
	var thePanel = $('importPanel');
	var theCollisionPanel = $('importCollisionPanel');
	var theNewTitle = $('importNewTitle');
	var count=0;
	switch (which.id)
		{
		case 'importFromFile':	// show local panel
		case 'importFromWeb':	// show HTTP panel
			cmi.local=(which.id=='importFromFile');
			cmi.showPanel('importLocalPanel',cmi.local);
			cmi.showPanel('importHTTPPanel',!cmi.local);
			break;
		case 'importOptions':	// show/hide options panel
			cmi.showPanel('importOptionsPanel',$('importOptionsPanel').style.display=='none');
			break;
		case 'fileImportSource':
		case 'importLoad':		// load import source into hidden frame
			importReport();		// if an import was in progress, generate a report
			cmi.inbound=null;	// clear the imported tiddler buffer
			refreshImportList();	// reset/resize the listbox
			if (cmi.src=="") break;
			// Load document, read it's DOM and fill the list
			cmi.loadRemoteFile(cmi.src,cmi.filterTiddlerList);
			break;
		case 'importSelectFeed':	// select a pre-defined systemServer feed URL
			var p=Popup.create(which); if (!p) return;
			var tids=store.getTaggedTiddlers('systemServer');
			if (!tids.length)
				createTiddlyText(createTiddlyElement(p,'li'),'no pre-defined server feeds');
			for (var t=0; t<tids.length; t++) {
				var u=store.getTiddlerSlice(tids[t].title,"URL");
				var d=store.getTiddlerSlice(tids[t].title,"Description");
				if (!d||!d.length) d=store.getTiddlerSlice(tids[t].title,"description");
				if (!d||!d.length) d=u;
				createTiddlyButton(createTiddlyElement(p,'li'),tids[t].title,d,
					function(){
						var u=this.getAttribute('url');
						$('importSourceURL').value=u;
						config.macros.importTiddlers.src=u;
						$('importLoad').onclick();
					},
					null,null,null,{url:u});
			}
			Popup.show(p,false);
			event.cancelBubble = true;
			if (event.stopPropagation) event.stopPropagation();
			return(false);
			// create popup with feed list
			// onselect, insert feed URL into input field.
			break;
		case 'importSelectAll':		// select all tiddler list items (i.e., not headings)
			importReport();		// if an import was in progress, generate a report
			for (var t=0,count=0; t < list.options.length; t++) {
				if (list.options[t].value=="") continue;
				list.options[t].selected=true;
				count++;
			}
			clearMessage(); displayMessage(cmi.countMsg.format([count]));
			$('importStart').disabled=!count;
			break;
		case 'importSelectNew':		// select tiddlers not in current document
			importReport();		// if an import was in progress, generate a report
			for (var t=0,count=0; t < list.options.length; t++) {
				list.options[t].selected=false;
				if (list.options[t].value=="") continue;
				list.options[t].selected=!store.tiddlerExists(list.options[t].value);
				count+=list.options[t].selected?1:0;
			}
			clearMessage(); displayMessage(cmi.countMsg.format([count]));
			$('importStart').disabled=!count;
			break;
		case 'importSelectChanges':		// select tiddlers that are updated from existing tiddlers
			importReport();		// if an import was in progress, generate a report
			for (var t=0,count=0; t < list.options.length; t++) {
				list.options[t].selected=false;
				if (list.options[t].value==""||!store.tiddlerExists(list.options[t].value)) continue;
				for (var i=0; i<cmi.inbound.length; i++) // find matching inbound tiddler
					{ var inbound=cmi.inbound[i]; if (inbound.title==list.options[t].value) break; }
				list.options[t].selected=(inbound.modified-store.getTiddler(list.options[t].value).modified>0); // updated tiddler
				count+=list.options[t].selected?1:0;
			}
			clearMessage(); displayMessage(cmi.countMsg.format([count]));
			$('importStart').disabled=!count;
			break;
		case 'importSelectDifferences':		// select tiddlers that are new or different from existing tiddlers
			importReport();		// if an import was in progress, generate a report
			for (var t=0,count=0; t < list.options.length; t++) {
				list.options[t].selected=false;
				if (list.options[t].value=="") continue;
				if (!store.tiddlerExists(list.options[t].value)) { list.options[t].selected=true; count++; continue; }
				for (var i=0; i<cmi.inbound.length; i++) // find matching inbound tiddler
					{ var inbound=cmi.inbound[i]; if (inbound.title==list.options[t].value) break; }
				list.options[t].selected=(inbound.modified-store.getTiddler(list.options[t].value).modified!=0); // changed tiddler
				count+=list.options[t].selected?1:0;
			}
			clearMessage(); displayMessage(cmi.countMsg.format([count]));
			$('importStart').disabled=!count;
			break;
		case 'importApplyFilter':	// filter list to include only matching tiddlers
			importReport();		// if an import was in progress, generate a report
			clearMessage();
			if (!cmi.all) // no tiddlers loaded = "0 selected"
				{ displayMessage(cmi.countMsg.format([0])); return false; }
			var hash=$('importLastFilter').value;
			cmi.inbound=cmi.filterByHash("#"+hash,cmi.all);
			refreshImportList();	// reset/resize the listbox
			break;
		case 'importStart':		// initiate the import processing
			importReport();		// if an import was in progress, generate a report
			$('importApplyToAll').checked=false;
			$('importStart').value=cmi.stopText;
			if (cmi.index>0) cmi.index=-1; // stop processing
			else cmi.index=importTiddlers(0); // or begin processing
			importStopped();
			break;
		case 'importClose':		// unload imported tiddlers or hide the import control panel
			// if imported tiddlers not loaded, close the import control panel
			if (!cmi.inbound) { thePanel.style.display='none'; break; }
			importReport();		// if an import was in progress, generate a report
			cmi.inbound=null;	// clear the imported tiddler buffer
			refreshImportList();	// reset/resize the listbox
			break;
		case 'importSkip':	// don't import the tiddler
			cmi.lastAction=which;
			var theItem	= list.options[cmi.index];
			for (var j=0;j<cmi.inbound.length;j++)
			if (cmi.inbound[j].title==theItem.value) break;
			var theImported = cmi.inbound[j];
			theImported.status='skipped after asking';			// mark item as skipped
			theCollisionPanel.style.display='none';
			cmi.index=importTiddlers(cmi.index+1);	// resume with NEXT item
			importStopped();
			break;
		case 'importRename':		// change name of imported tiddler
			cmi.lastAction=which;
			var theItem		= list.options[cmi.index];
			for (var j=0;j<cmi.inbound.length;j++)
			if (cmi.inbound[j].title==theItem.value) break;
			var theImported		= cmi.inbound[j];
			theImported.status	= 'renamed from '+theImported.title;	// mark item as renamed
			theImported.set(theNewTitle.value,null,null,null,null);		// change the tiddler title
			theItem.value		= theNewTitle.value;			// change the listbox item text
			theItem.text		= theNewTitle.value;			// change the listbox item text
			theCollisionPanel.style.display='none';
			cmi.index=importTiddlers(cmi.index);	// resume with THIS item
			importStopped();
			break;
		case 'importMerge':	// join existing and imported tiddler content
			cmi.lastAction=which;
			var theItem	= list.options[cmi.index];
			for (var j=0;j<cmi.inbound.length;j++)
			if (cmi.inbound[j].title==theItem.value) break;
			var theImported	= cmi.inbound[j];
			var theExisting	= store.getTiddler(theItem.value);
			var theText	= theExisting.text+'\n----\n^^merged from: ';
			theText		+='[['+cmi.src+'#'+theItem.value+'|'+cmi.src+'#'+theItem.value+']]^^\n';
			theText		+='^^'+theImported.modified.toLocaleString()+' by '+theImported.modifier+'^^\n'+theImported.text;
			var theDate	= new Date();
			var theTags	= theExisting.getTags()+' '+theImported.getTags();
			theImported.set(null,theText,null,theDate,theTags);
			theImported.status   = 'merged with '+theExisting.title;	// mark item as merged
			theImported.status  += ' - '+theExisting.modified.formatString("MM/DD/YYYY 0hh:0mm:0ss");
			theImported.status  += ' by '+theExisting.modifier;
			theCollisionPanel.style.display='none';
			cmi.index=importTiddlers(cmi.index);	// resume with this item
			importStopped();
			break;
		case 'importReplace':		// substitute imported tiddler for existing tiddler
			cmi.lastAction=which;
			var theItem		  = list.options[cmi.index];
			for (var j=0;j<cmi.inbound.length;j++)
			if (cmi.inbound[j].title==theItem.value) break;
			var theImported     = cmi.inbound[j];
			var theExisting	  = store.getTiddler(theItem.value);
			theImported.status  = 'replaces '+theExisting.title;		// mark item for replace
			theImported.status += ' - '+theExisting.modified.formatString("MM/DD/YYYY 0hh:0mm:0ss");
			theImported.status += ' by '+theExisting.modifier;
			theCollisionPanel.style.display='none';
			cmi.index=importTiddlers(cmi.index);	// resume with THIS item
			importStopped();
			break;
		case 'importListSmaller':		// decrease current listbox size, minimum=5
			if (list.options.length==1) break;
			list.size-=(list.size>5)?1:0;
			cmi.listsize=list.size;
			break;
		case 'importListLarger':		// increase current listbox size, maximum=number of items in list
			if (list.options.length==1) break;
			list.size+=(list.size<list.options.length)?1:0;
			cmi.listsize=list.size;
			break;
		case 'importListMaximize':	// toggle listbox size between current and maximum
			if (list.options.length==1) break;
			list.size=(list.size==list.options.length)?cmi.listsize:list.options.length;
			break;
		}
}
//}}}
//{{{
config.macros.importTiddlers.showPanel=function(place,show,skipAnim) {
	if (typeof place == "string") var place=$(place);
	if (!place||!place.style) return;
	if(!skipAnim && anim && config.options.chkAnimate) anim.startAnimating(new Slider(place,show,false,"none"));
	else place.style.display=show?"block":"none";
}
//}}}
//{{{
function refreshImportList(selectedIndex)
{
	var cmi=config.macros.importTiddlers; // abbreviation

	var list  = $("importList");
	if (!list) return;
	// if nothing to show, reset list content and size
	if (!cmi.inbound) 
	{
		while (list.length > 0) { list.options[0] = null; }
		list.options[0]=new Option(cmi.loadText,"",false,false);
		list.size=cmi.listsize;

		// toggle buttons and panels
		$('importLoad').disabled=false;
		$('importLoad').style.display='inline';
		$('importStart').disabled=true;
		$('importOptions').disabled=true;
		$('importOptions').style.display='none';
		$('fileImportSource').disabled=false;
		$('importFromFile').disabled=false;
		$('importFromWeb').disabled=false;
		$('importStart').value=cmi.startText;
		$('importClose').value=cmi.doneText;
		$('importSelectPanel').style.display='none';
		$('importOptionsPanel').style.display='none';
		return;
	}
	// there are inbound tiddlers loaded...
	// toggle buttons and panels
	$('importLoad').disabled=true;
	$('importLoad').style.display='none';
	$('importOptions').style.display='inline';
	$('importOptions').disabled=false;
	$('fileImportSource').disabled=true;
	$('importFromFile').disabled=true;
	$('importFromWeb').disabled=true;
	$('importClose').value=cmi.closeText;
	if ($('importSelectPanel').style.display=='none')
		cmi.showPanel('importSelectPanel',true);

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

	// get the alphasorted list of tiddlers
	var tiddlers=cmi.inbound;
	tiddlers.sort(function (a,b) {if(a['title'] == b['title']) return(0); else return (a['title'] < b['title']) ? -1 : +1; });
	// clear current list contents
	while (list.length > 0) { list.options[0] = null; }
	// add heading and control items to list
	var i=0;
	var indent=String.fromCharCode(160)+String.fromCharCode(160);
	if (cmi.all.length==tiddlers.length)
		var summary=cmi.summaryMsg.format([tiddlers.length,(tiddlers.length!=1)?cmi.plural:cmi.single]);
	else
		var summary=cmi.summaryFilteredMsg.format([tiddlers.length,cmi.all.length,(cmi.all.length!=1)?cmi.plural:cmi.single]);
	list.options[i++]=new Option(summary,"",false,false);
	list.options[i++]=new Option(((cmi.sort=="title"   )?">":indent)+' [by title]',"",false,false);
	list.options[i++]=new Option(((cmi.sort=="modified")?">":indent)+' [by date]',"",false,false);
	list.options[i++]=new Option(((cmi.sort=="tags")?">":indent)+' [by tags]',"",false,false);
	// output the tiddler list
	switch(cmi.sort) {
		case "title":
			for(var t = 0; t < tiddlers.length; t++)
				list.options[i++] = new Option(tiddlers[t].title,tiddlers[t].title,false,false);
			break;
		case "modified":
			// sort descending for newest date first
			tiddlers.sort(function (a,b) {if(a['modified'] == b['modified']) return(0); else return (a['modified'] > b['modified']) ? -1 : +1; });
			var lastSection = "";
			for(var t = 0; t < tiddlers.length; t++) {
				var tiddler = tiddlers[t];
				var theSection = tiddler.modified.toLocaleDateString();
				if (theSection != lastSection) {
					list.options[i++] = new Option(theSection,"",false,false);
					lastSection = theSection;
				}
				list.options[i++] = new Option(indent+indent+tiddler.title,tiddler.title,false,false);
			}
			break;
		case "tags":
			var theTitles = {}; // all tiddler titles, hash indexed by tag value
			var theTags = new Array();
			for(var t=0; t<tiddlers.length; t++) {
				var title=tiddlers[t].title;
				var tags=tiddlers[t].tags;
				if (!tags || !tags.length) {
					if (theTitles["untagged"]==undefined) { theTags.push("untagged"); theTitles["untagged"]=new Array(); }
					theTitles["untagged"].push(title);
				}
				else for(var s=0; s<tags.length; s++) {
					if (theTitles[tags[s]]==undefined) { theTags.push(tags[s]); theTitles[tags[s]]=new Array(); }
					theTitles[tags[s]].push(title);
				}
			}
			theTags.sort();
			for(var tagindex=0; tagindex<theTags.length; tagindex++) {
				var theTag=theTags[tagindex];
				list.options[i++]=new Option(theTag,"",false,false);
				for(var t=0; t<theTitles[theTag].length; t++)
					list.options[i++]=new Option(indent+indent+theTitles[theTag][t],theTitles[theTag][t],false,false);
			}
			break;
		}
	list.selectedIndex=selectedIndex;		  // select current control item
	if (list.size<cmi.listsize) list.size=cmi.listsize;
	if (list.size>list.options.length) list.size=list.options.length;
}
//}}}
//{{{
// re-entrant processing for handling import with interactive collision prompting
function importTiddlers(startIndex)
{
	var cmi=config.macros.importTiddlers; // abbreviation

	if (!cmi.inbound) return -1;

	var list = $('importList');
	if (!list) return;
	var t;
	// if starting new import, reset import status flags
	if (startIndex==0)
		for (var t=0;t<cmi.inbound.length;t++)
			cmi.inbound[t].status="";
	for (var i=startIndex; i<list.options.length; i++)
		{
		// if list item is not selected or is a heading (i.e., has no value), skip it
		if ((!list.options[i].selected) || ((t=list.options[i].value)==""))
			continue;
		for (var j=0;j<cmi.inbound.length;j++)
			if (cmi.inbound[j].title==t) break;
		var inbound = cmi.inbound[j];
		var theExisting = store.getTiddler(inbound.title);
		// avoid redundant import for tiddlers that are listed multiple times (when 'by tags')
		if (inbound.status=="added")
			continue;
		// don't import the "ImportedTiddlers" history from the other document...
		if (inbound.title=='ImportedTiddlers')
			continue;
		// if tiddler exists and import not marked for replace or merge, stop importing
		if (theExisting && (inbound.status.substr(0,7)!="replace") && (inbound.status.substr(0,5)!="merge"))
			return i;
		// assemble tags (remote + existing + added)
		var newTags = "";
		if (cmi.importTags)
			newTags+=inbound.getTags()	// import remote tags
		if (cmi.keepTags && theExisting)
			newTags+=" "+theExisting.getTags(); // keep existing tags
		if (cmi.addTags && cmi.newTags.trim().length)
			newTags+=" "+cmi.newTags; // add new tags
		inbound.set(null,null,null,null,newTags.trim());
		// set the status to 'added' (if not already set by the 'ask the user' UI)
		inbound.status=(inbound.status=="")?'added':inbound.status;
		// set sync fields
		if (cmi.sync) {
			if (!inbound.fields) inbound.fields={}; // for TW2.1.x backward-compatibility
			inbound.fields["server.page.revision"]=inbound.modified.convertToYYYYMMDDHHMM();
			inbound.fields["server.type"]="file";
			inbound.fields["server.host"]=(cmi.local?"file://":"")+cmi.src;
		}
		// do the import!
		store.suspendNotifications();
		store.saveTiddler(inbound.title, inbound.title, inbound.text, inbound.modifier, inbound.modified, inbound.tags, inbound.fields, true, inbound.created);
                store.fetchTiddler(inbound.title).created = inbound.created; // force creation date to imported value (needed for TW2.1.x and earlier)
		store.resumeNotifications();
		}
	return(-1);	// signals that we really finished the entire list
}
function importStopped()
{
	var cmi=config.macros.importTiddlers; // abbreviation
	var list = $('importList');
	var theNewTitle = $('importNewTitle');
	if (!list) return;
	if (cmi.index==-1){ 
		$('importStart').value=cmi.startText;
		importReport();		// import finished... generate the report
	} else {
		// import collision...
		// show the collision panel and set the title edit field
		$('importStart').value=cmi.stopText;
		cmi.showPanel('importCollisionPanel',true);
		theNewTitle.value=list.options[cmi.index].value;
		if ($('importApplyToAll').checked
			&& cmi.lastAction
			&& cmi.lastAction.id!="importRename") {
			onClickImportButton(cmi.lastAction);
		}
	}
}
//}}}
//{{{
function importReport()
{
	var cmi=config.macros.importTiddlers; // abbreviation
	if (!cmi.inbound) return;

	// if import was not completed, the collision panel will still be open... close it now.
	var panel=$('importCollisionPanel'); if (panel) panel.style.display='none';

	// get the alphasorted list of tiddlers
	var tiddlers = cmi.inbound;
	// gather the statistics
	var count=0; var total=0;
	for (var t=0; t<tiddlers.length; t++) {
		if (!tiddlers[t].status || !tiddlers[t].status.trim().length) continue;
		if (tiddlers[t].status.substr(0,7)!="skipped") count++;
		total++;
	}
	// generate a report
	if (total) displayMessage(cmi.processedMsg.format([total]));
	if (count && config.options.chkImportReport) {
		// get/create the report tiddler
		var theReport = store.getTiddler('ImportedTiddlers');
		if (!theReport) { theReport= new Tiddler(); theReport.title = 'ImportedTiddlers'; theReport.text  = ""; }
		// format the report content
		var now = new Date();
		var newText = "On "+now.toLocaleString()+", "+config.options.txtUserName
		newText +=" imported "+count+" tiddler"+(count==1?"":"s")+" from\n[["+cmi.src+"|"+cmi.src+"]]:\n";
		if (cmi.addTags && cmi.newTags.trim().length)
			newText += "imported tiddlers were tagged with: \""+cmi.newTags+"\"\n";
		newText += "<<<\n";
		for (var t=0; t<tiddlers.length; t++) if (tiddlers[t].status) newText += "#[["+tiddlers[t].title+"]] - "+tiddlers[t].status+"\n";
		newText += "<<<\n";
		// update the ImportedTiddlers content and show the tiddler
		theReport.text	 = newText+((theReport.text!="")?'\n----\n':"")+theReport.text;
		theReport.modifier = config.options.txtUserName;
		theReport.modified = new Date();
                store.saveTiddler(theReport.title, theReport.title, theReport.text, theReport.modifier, theReport.modified, theReport.tags, theReport.fields);
		story.displayTiddler(null,theReport.title,1,null,null,false);
		story.refreshTiddler(theReport.title,1,true);
	}
	// reset status flags
	for (var t=0; t<cmi.inbound.length; t++) cmi.inbound[t].status="";
	// mark document as dirty and let display update as needed
	if (count) { store.setDirty(true); store.notifyAll(); }
	// always show final message when tiddlers were actually loaded
	if (count) displayMessage(cmi.importedMsg.format([count,tiddlers.length,cmi.src.replace(/%20/g," ")]));
}
//}}}
//{{{
// // File and XMLHttpRequest I/O
config.macros.importTiddlers.askForFilename=function(here) {
	var msg=here.title; // use tooltip as dialog box message
	var path=getLocalPath(document.location.href);
	var slashpos=path.lastIndexOf("/"); if (slashpos==-1) slashpos=path.lastIndexOf("\\"); 
	if (slashpos!=-1) path = path.substr(0,slashpos+1); // remove filename from path, leave the trailing slash
	var file="";
	var result="";
	if(window.Components) { // moz
		try {
			netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');

			var nsIFilePicker = window.Components.interfaces.nsIFilePicker;
			var picker = Components.classes['@mozilla.org/filepicker;1'].createInstance(nsIFilePicker);
			picker.init(window, msg, nsIFilePicker.modeOpen);
			var thispath = Components.classes['@mozilla.org/file/local;1'].createInstance(Components.interfaces.nsILocalFile);
			thispath.initWithPath(path);
			picker.displayDirectory=thispath;
			picker.defaultExtension='html';
			picker.defaultString=file;
			picker.appendFilters(nsIFilePicker.filterAll|nsIFilePicker.filterText|nsIFilePicker.filterHTML);
			if (picker.show()!=nsIFilePicker.returnCancel) var result=picker.file.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;
}

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

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

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

config.macros.importTiddlers.filterByHash=function(src,tiddlers)
{
	var hashpos=src.lastIndexOf("#"); if (hashpos==-1) return tiddlers;
	var hash=src.substr(hashpos+1); if (!hash.length) return tiddlers;
	var tids=[];
	var params=hash.parseParams("anon",null,true,false,false);
	for (var p=1; p<params.length; p++) {
		switch (params[p].name) {
			case "anon":
			case "open":
				tids.pushUnique(params[p].value);
				break;
			case "tag":
				if (store.getMatchingTiddlers) { // for boolean expressions - see MatchTagsPlugin
					var r=store.getMatchingTiddlers(params[p].value,null,tiddlers);
					for (var t=0; t<r.length; t++) tids.pushUnique(r[t].title);
				} else for (var t=0; t<tiddlers.length; t++)
					if (tiddlers[t].isTagged(params[p].value))
						tids.pushUnique(tiddlers[t].title);
				break;
			case "story":
				for (var t=0; t<tiddlers.length; t++)
					if (tiddlers[t].title==params[p].value) {
						tiddlers[t].changed();
						for (var s=0; s<tiddlers[t].links.length; s++)
							tids.pushUnique(tiddlers[t].links[s]);
						break;
					}
				break;
			case "search":
				for (var t=0; t<tiddlers.length; t++)
					if (tiddlers[t].text.indexOf(params[p].value)!=-1)
						tids.pushUnique(tiddlers[t].title);
				break;
		}
	}
	var matches=[];
	for (var t=0; t<tiddlers.length; t++)
		if (tids.contains(tiddlers[t].title))
			matches.push(tiddlers[t]);
	displayMessage(config.macros.importTiddlers.filterMsg.format([matches.length,hash]));
	config.macros.importTiddlers.lastFilter=hash;
	return matches;
}
//}}}
On Tuesday, February 17, 2009 11:37:07 AM, Savanni D'Gerinel imported 1 tiddler from
[[E:\pim\pkm.html|E:\pim\pkm.html]]:
<<<
#[[2009/02/17: Austin Gender Weird]] - added
<<<

----
On Tuesday, January 27, 2009 2:50:56 PM, Savanni D'Gerinel imported 1 tiddler from
[[http://www.tiddlytools.com/|http://www.tiddlytools.com/]]:
<<<
#[[TiddlerTweakerPlugin]] - added
<<<

----
On Tuesday, December 09, 2008 1:11:44 PM, Savanni D'Gerinel imported 2 tiddlers from
[[E:\pim\pkm.html|E:\pim\pkm.html]]:
<<<
#[[WikifyPlugin]] - added
#[[WikifyPluginInfo]] - added
<<<

----
On Tuesday, December 09, 2008 12:58:48 PM, Savanni D'Gerinel imported 4 tiddlers from
[[E:\pim\pkm.html|E:\pim\pkm.html]]:
<<<
#[[StorySaverPlugin]] - added
#[[StorySaverPluginInfo]] - added
#[[StoryViewerPlugin]] - added
#[[StoryViewerPluginInfo]] - added
<<<

----
On Tuesday, December 09, 2008 12:15:30 PM, Savanni D'Gerinel imported 1 tiddler from
[[E:\pim\pkm.html|E:\pim\pkm.html]]:
<<<
#[[Books]] - added
<<<

----
On Tuesday, November 25, 2008 8:57:48 AM, Savanni D'Gerinel imported 2 tiddlers from
[[E:\pim\pkm.html|E:\pim\pkm.html]]:
<<<
#[[ImagePathPlugin]] - added
#[[ImageSizePlugin]] - added
<<<

----
On Thursday, November 20, 2008 12:23:54 PM, Savanni D'Gerinel imported 1 tiddler from
[[E:\pim\pkm.html|E:\pim\pkm.html]]:
<<<
#[[Aikido Terms]] - added
<<<

----
On Tuesday, November 11, 2008 9:31:34 AM, Savanni D'Gerinel imported 1 tiddler from
[[E:\pim\pkm.html|E:\pim\pkm.html]]:
<<<
#[[TaggerPlugin]] - added
<<<

----
On Tuesday, November 11, 2008 9:29:46 AM, Savanni D'Gerinel imported 1 tiddler from
[[E:\pim\pkm.html|E:\pim\pkm.html]]:
<<<
#[[RenameTagsPlugin]] - added
<<<

----
On Thursday, November 06, 2008 5:00:37 PM, Savanni D'Gerinel imported 7 tiddlers from
[[E:\pim\Website\homeimprovement\index.html|E:\pim\Website\homeimprovement\index.html]]:
<<<
#[[05 August 2008: Day 1... Complete!]] - added
#[[06 August 2008: Day 2... Complete!]] - added
#[[07 August 2008: Day three... Complete!]] - added
#[[08 August 2008: Day Four... OMG WOW!]] - added
#[[11 August 2008: Day Whatever... Library-Office Finished!]] - added
#[[14 August 2008: Because once just was not enough...]] - added
#[[26 August 2008: Late night motivation]] - added
<<<

----
On Thursday, November 06, 2008 5:00:07 PM, Savanni D'Gerinel imported 4 tiddlers from
[[E:\pim\Website\pkm\index.html|E:\pim\Website\pkm\index.html]]:
<<<
#[[10 July 2007: A Touch of Hyperbole]] - added
#[[14 June 2007: Introduction to my Passion]] - added
#[[20 August 2007: Living In One Text File]] - added
#[[25 June 2007: Organization]] - added
<<<
----
<<storyViewer journal previous>>
<<wikify "[[Feedback|mailto:savanni@alyra.org?subject=%0]]" title>>
----
[img[images/icon.jpg]]

! Journal
<<storyViewer journal last>>

! About Me
[[About Me]]
[[Friends and Affiliations]]
[[Games I Like to Play]]
[[Books]]
[[Still Point Aikido Center|http://www.stillpointaikido.com/]]
[[Austin Gender Weird|http://www.austingenderweird.info/]]

[[Mark Humphrey|mailto:markus@alyra.org]]
[[Savanni D'Gerinel|mailto:savanni@alyra.org]]

! Galleries
* [[Some of my cats|images/2007_10_Cats]]
* [[Texas Renaissance Fair, 2007|images/2007_11_TRF/]]
* [[Flagstone Patio, March 2008|images/2008_03_Patio/]]
* [[Library-Office|images/2008_Library/]]
* [[Meditation Room|images/2008_Meditation/]]
* [[Painting|images/2008_09_Family_Painting/]]
* [[Halloween, 2008|images/2008_10_Halloween/]]
* [[Christmas Lights, 2008|images/2008_12_Lights/]]
* [[Biofamily Portraits, 2009|images/2009_01_Biofamily/]]
* [[The New Bike|images/2009_11_Bike/]]

! Tools
[[Configuration]]
DefaultTiddlers
----
<<wikify "[[Feedback|mailto:savanni@alyra.org?subject=%0]]" title>>
----

If you have not read //Woman on the Edge of Time//, ''this contains spoilers''.  Otherwise, enjoy and feel free to debate.  Consider trying to migrate to some of these ideals.

! Villages and work
* Small dispersed villages.  Individuals have their own very small homes.  Most structures and activities, including food and child rearring, are communal in nature.  Even their brooder, where children are conceived and developed up to the point of birth (a matter of concern for me) is communal.  It is largely automated, but there are always people there to monitor the machinery.
* No money.  No jobs involving money management.
* Nobody really "owns" anything.  Everyone has a small private space to live in, but most everything is communal property.  Bicycles at the bike rack on the edge of the village are available for anyone who needs them.
* Everyone is expected to spend some time working, and generally everyone wants to.  Nobody has to spend nearly as much time working as we do now, except during harvest season.  Anyone who does not pull their own weight starts building up resentment from the community and may eventually be asked to leave.  All additional time is spent socializing, creating art, playing, taking care of children, teaching, or any of the other varieties of activity that are not necessary for immediate survival.

! Children
* Every child has three parents.  Two of them will nurse the child.  Gender is irrelevant in this case.  Since no child is born biologically, the ability to nurse is given by hormonal injections (this raises an alarm for me).  Further, every child is wanted because the three parents have to agree that they want a child, then must apply to become parents, then they must wait for the new child to be born.
* Population is strictly limited and is even hinted to still be decreasing.  For this reason, no new child may be conceived until somebody else dies.
* If the relationship between a child and one of its parents deteriorates too greatly, the community will intervene to find a new parent for the child.
* Children generally separate from their parents around 12 to 14 years old.  They go through a rite of passage that involves surviving in the wild, alone, for one week.  For three months after this separation, no conversation is allowed between the child and eir parents, in order to break the old parenting pattern.  This person is no longer considered a child and is expected to begin contributing to the community.
* The very old spend a lot of time teaching children.
* Children are taught reaction control techniques starting at a very young age.  Using biofeedback teachniques, they learn how to prevent violent outbursts.

! Medicine
This was left rather vague in the book.  I got the feeling that there was a great deal of psychic talent in these groups and so much medical care was able to be done through energy healing.  They still had enough technology to intervene that way in the case of an acute crisis, but I got the feeling that they have much more in common with the holistic health movements of today than with anything like the medical establishment.

! Government
* Authority in the form of city, local, regional, and very large councils is made up of people chosen by lot.  Apparently nobody is exempt from being part of the random selection, but nobody gets to campaign.  Every council has two people set aside to advocate for different aspects of the environment.
* All decisions made by authority seem to affect only group resource allocation, environmental preservation and replacing a child's parent if the relationship between a child and one of the parents degrades to something harmful.  The councils are a very, very light touch on society.
* Nobody is allowed to have the floor for more than five minutes.  Generally, decisions are made by arguing until a vote is taken.
* Any time two different groups are in conflict on a decision, the group that ultimately wins the decision invites the loser to a celebration to remind everyone that they are all working together and that they can still have fun together.

! Relationships
* The only formal relationship I saw was the formal creation of a group of three parents for a new child.
* Sexual relationships form and end at the will of the individuals involved.  Homosexual relationships are just as common as heterosexual relationships.  It seems that some people do have a preference one way or the other, but it also seems that the preference is only rarely a hard preferenc.
* Sexual and emotional monogamy is largely unheard of.  In some cases, the community may encourage a relationship to end if it becomes co-dependent or starts impeding the growth of one or both partners.  Conflict between metamours is resolved through public discussion, and some encouragement that the metamours in conflict spend more time in dialogue.  //Incidentally, this is the kind of society I wish to participate in.  Theoretically, I can, given a certain level of safety precautions.//
* Gender has become irrelevant.  The only pronouns ever used (except during what looks like an editorial mistake) are "person" and "per".  I never quite figured out the pattern to determine which would be used.  //I nearly lust after this kind of society and may start referring to people in this way entirely.//

----
<<wikify "[[Feedback|mailto:savanni@alyra.org?subject=%0]]" title>>
----
<!--{{{-->
<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 refresh='content' tiddler='CC-BySa'></div>
<div id='sidebarOptions' refresh='content' tiddler='SideBarOptions'></div>
<div refresh='content' force='true' tiddler='TagCloud'></div>
<div id='sidebarTabs' refresh='content' force='true' tiddler='SideBarTabs'></div>
</div>
<div id='displayArea'>
<div id='messageArea'></div>
<div id='tiddlerDisplay'></div>
</div>
<!--}}}-->
dreamer, shaper, seeker, maker
To Dream of Magick
http://markus.alyra.org/
/***
|Name|StorySaverPlugin|
|Source|http://www.TiddlyTools.com/#StorySaverPlugin|
|Documentation|http://www.TiddlyTools.com/#StorySaverPluginInfo|
|Version|1.4.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|MarkupPostBody|
|Overrides|confirmExit(), getParameters()|
|Description|save/restore current tiddler view between browser sessions|
This plugin automatically saves a list of the currently viewed tiddlers (the "story") in a local cookie, {{{txtSavedStory}}} and then opens those tiddlers when the document is subsequently reloaded... the tiddlers you were viewing in the last browser session are automatically redisplayed in the next session, allowing you to quickly resume working with the document from the same place you left off!!

In addition to automatic cookie-based story tracking, the plugin also provides {{{<<saveStory>>}}} and {{{<<openStory>>}}} macros that allow you to quickly save the current story definition to a tiddler, and then re-display saved stories using simple, one-click command links or droplists.
!!!!!Documentation
>see [[StorySaverPluginInfo]]
!!!!!Revisions
<<<
2008.09.07 [1.4.3] added removeCookie() function for compatibility with [[CookieManagerPlugin]]
2008.07.11 [1.4.2] in confirmExit(), corrected bracketing for titles containing spaces
2008.03.10 [*.*.*] plugin size reduction: documentation moved to [[StorySaverPluginInfo]]
|please see [[StorySaverPluginInfo]] for additional revision details|
2007.10.05 [1.0.0] initial release.   Moved [[SetDefaultTiddlers]] inline script and rewrote as a {{{<<saveStory>>}}} macro.
<<<
!!!!!Code
***/
//{{{
version.extensions.StorySaverPlugin= {major: 1, minor: 4, revision: 3, date: new Date(2008,9,7)};
//}}}
// // ''save or clear story cookie on exit:''
//{{{
// if removeCookie() function is not defined by TW core, define it here.
if (window.removeCookie===undefined) {
	window.removeCookie=function(name) {
		document.cookie = name+'=; expires=Thu, 01-Jan-1970 00:00:01 UTC; path=/;'; 
	}
}

if (config.options.chkSaveStory==undefined) config.options.chkSaveStory=false; 
if (window.coreTweaks_confirmExit==undefined) {
	window.coreTweaks_confirmExit=window.confirmExit;
	window.confirmExit=function() {
		if (config.options.chkSaveStory) { // save cookie
			var links=[];
			story.forEachTiddler(function(title,element){links.push('[['+title+']]');});
			config.options.txtSavedStory=links.join(" ");
			saveOptionCookie("txtSavedStory");
		} else removeCookie("txtSavedStory");
		return window.coreTweaks_confirmExit.apply(this,arguments);
	}
}
//}}}
/***
''apply saved story on startup:'' //important note: the following code is actually located in [[MarkupPostBody]].  This is because it needs to supercede the core's getParameters() function, which is called BEFORE plugins are loaded, preventing the normal plugin-based hijack method from working, while code loaded into [[MarkupPostBody]] will be processed as soon as the document is read, even before the TW main() function is invoked.//
<<tiddler MarkupPostBody>>
***/
// // MACRO definitions
//{{{
config.macros.saveStory = {
	label: "set default tiddlers",
	defaultTiddler: "DefaultTiddlers",
	prompt: "store a list of currently displayed tiddlers in another tiddler",
	askMsg: "Enter the name of a tiddler in which to save the current story:",
	tag: "story",
	handler: function(place,macroName,params,wikifier,paramString,tiddler) {
		var tid=params[0]?params[0]:"DefaultTiddlers";
		var label=params[1]?params[1]:this.label;
		var tip=params[2]?params[2]:this.prompt;
		var btn=createTiddlyButton(place,label,tip,this.setTiddler,"button");
		btn.setAttribute("tid",tid);
	},
	setTiddler: function() {
		// get list of current open tiddlers
		var tids=[];
		story.forEachTiddler(function(title,element){tids.push("[["+title+"]]")}); // always put titles in brackets
		// get target tiddler
		var tid=this.getAttribute("tid");
		if (!tid || tid=="ask") {
			tid=prompt(config.macros.saveStory.askMsg,config.macros.saveStory.defaultTiddler);
			if (!tid || !tid.length) return; // cancelled by user
		}
		if(store.tiddlerExists(tid) && !confirm(config.messages.overwriteWarning.format([tid]))) return;
		tids=tids.join("\n"); // separate tiddler links by newlines for easier reading
		var t=store.getTiddler(tid); var tags=t?t.tags:[]; tags.push(config.macros.saveStory.tag);
		store.saveTiddler(tid,tid,tids,config.options.txtUserName,new Date(),tags,t?t.fields:null);
		story.displayTiddler(null,tid); story.refreshTiddler(tid,null,true);
		displayMessage(tid+" has been "+(t?"updated":"created"));
	}
}
//}}}

//{{{
if (config.options.chkStoryFold==undefined) config.options.chkStoryFold=true;
if (config.options.chkStoryClose==undefined) config.options.chkStoryClose=true;
config.macros.openStory = {
	label: "open story: %0",
	prompt: "open the set of tiddlers listed in: '%0'",
	popuplabel: "stories",
	popupprompt: "view a set of tiddlers",
	tag: "story",
	selectprompt: "select a story...",
	optionsprompt: "viewing options...",
	foldcmd: "[%0] fold story",
	foldprompt: "fold story tiddlers when opening a story",
	closecmd: "[%0] close others",
	closeprompt: "close other tiddlers when opening a story",
	addcmd: "add a story...",
	addprompt: "create a new story",
	handler: function(place,macroName,params,wikifier,paramString,tiddler) {
		if (params[0].toLowerCase()=="list") return this.createList(place,params);
		else if (params[0].toLowerCase()=="popup") return this.createPopup(place,params);
		else this.createButton(place,params);
	},
	showStory: function(tid) {
		var tids=[];
		var tagged=store.getTaggedTiddlers(tid,"title");
		if (tagged.length) // if tiddler IS a tag, use tagged tiddlers as story
			for (var t=0; t<tagged.length; t++) tids.push(tagged[t].title);
		else { // get tiddler list from content
			var t=store.getTiddler(tid);
			if (t) { if (!t.linksUpdated) t.changed(); tids=t.links; }
		}
		// see [[CollapseTiddlersPlugin]] for more info, re: folding tiddlers
		var template=null;
		if (config.options.chkStoryFold) template="CollapsedTemplate";
		if (!store.tiddlerExists("CollapsedTemplate")) template=null;
		if (config.options.chkStoryClose) story.closeAllTiddlers();
		story.displayTiddlers(null,tids,template);
	},
	createButton: function(place,params) {
		var tid=params[0]?params[0]:"";
		var label=params[1]?params[1]:this.label; label=label.format([tid]);
		var tip=params[2]?params[2]:this.prompt; tip=tip.format([tid]);
		var fn=function(){config.macros.openStory.showStory(this.getAttribute("tid"))};
		var btn=createTiddlyButton(place,label,tip,fn,"button");
		btn.setAttribute("tid",tid);
	},
	createPopup: function(place,params) {
		var label=params[1]?params[1]:this.popuplabel;
		var tip=params[2]?params[2]:this.popupprompt;
		var btn=createTiddlyButton(place,label,tip,this.showPopup,"button");
	},
	showPopup: function(ev) { var e=ev||window.event;
		var indent="\xa0\xa0";
		var p=Popup.create(this); if (!p) return false;
		createTiddlyText(createTiddlyElement(p,"li"),config.macros.openStory.selectprompt);
		var stories=store.getTaggedTiddlers("story","title");
		for (var s=0; s<stories.length; s++) {
			var label=indent+stories[s].title;
			var tip=config.macros.openStory.prompt.format([stories[s].title]);
			var fn=function(){config.macros.openStory.showStory(this.getAttribute("tid"))};
			var btn=createTiddlyButton(createTiddlyElement(p,"li"),label,tip,fn,"button");
			btn.setAttribute("tid",stories[s].title);
		}
		createTiddlyText(createTiddlyElement(p,"li"),config.macros.openStory.optionsprompt);
		if (store.tiddlerExists("CollapsedTemplate")) {
			var label=indent+config.macros.openStory.foldcmd.format([config.options.chkStoryFold?"x":"\xa0\xa0"]);
			var tip=config.macros.openStory.foldprompt;
			var fn=function(){config.options.chkStoryFold=!config.options.chkStoryFold;saveOptionCookie('chkStoryFold')};
			var btn=createTiddlyButton(createTiddlyElement(p,"li"),label,tip,fn,"button");
		}
		var label=indent+config.macros.openStory.closecmd.format([config.options.chkStoryClose?"x":"\xa0\xa0"]);
		var tip=indent+config.macros.openStory.closeprompt;
		var fn=function(){config.options.chkStoryClose=!config.options.chkStoryClose;saveOptionCookie('chkStoryClose')};
		var btn=createTiddlyButton(createTiddlyElement(p,"li"),label,tip,fn,"button");
		if (!readOnly) {
			var label=config.macros.openStory.addcmd;
			var tip=config.macros.openStory.addprompt;
			var fn=config.macros.saveStory.setTiddler;
			createTiddlyElement(createTiddlyElement(p,"li"),"hr");
			var btn=createTiddlyButton(createTiddlyElement(p,"li"),label,tip,fn,"button");
		}
		Popup.show(p,false);
		e.cancelBubble=true;if(e.stopPropagation)e.stopPropagation();
		return false;
	},
	createList: function(place,params) {
		var s=createTiddlyElement(place,"select",null,"storyListbox");
		s.size=1;
		s.onchange=function() {
			if (this.value=="_fold") {
				config.options.chkStoryFold=!config.options.chkStoryFold; saveOptionCookie('chkStoryFold');
				config.macros.openStory.refreshList();
			} else if (this.value=="_close") {
				config.options.chkStoryClose=!config.options.chkStoryClose; saveOptionCookie('chkStoryClose');
				config.macros.openStory.refreshList();
			} else if (this.value=="_add")
				config.macros.saveStory.setTiddler.apply(this,arguments);
			else config.macros.openStory.showStory(this.value);
		}
		setStylesheet(".storyListbox { width:100%; }", "StorySaverStyles");
		store.addNotification(null,this.refreshList); this.refreshList();
		return;
	},
	refreshList: function() {
		var indent="\xa0\xa0\xa0\xa0";
		var lists=document.getElementsByTagName("select");
		for (var i=0; i<lists.length; i++) { if (lists[i].className!="storyListbox") continue;
			var here=lists[i];
			while (here.length) here.options[0]=null; // remove current list items
			here.options[here.length]=new Option(config.macros.openStory.selectprompt,"",true,true);
			var stories=store.getTaggedTiddlers("story","title");
			for (var s=0; s<stories.length; s++)
				here.options[here.length]=new Option(indent+stories[s].title,stories[s].title,false,false);
			if (!readOnly)
				here.options[here.length]=new Option(config.macros.openStory.addcmd,"_add",false,false);
			here.options[here.length]=new Option(config.macros.openStory.optionsprompt,"",false,false);
			if (store.tiddlerExists("CollapsedTemplate")) {
				var msg=config.macros.openStory.foldcmd.format([config.options.chkStoryFold?"x":"\xa0\xa0"]);
				here.options[here.length]=new Option(indent+msg,"_fold",false,false);
			}
			var msg=config.macros.openStory.closecmd.format([config.options.chkStoryClose?"x":"\xa0\xa0"]);
			here.options[here.length]=new Option(indent+msg,"_close",false,false);
		}
	}
}
//}}}
/***
|Name|StorySaverPlugin|
|Source|http://www.TiddlyTools.com/#StorySaverPlugin|
|Documentation|http://www.TiddlyTools.com/#StorySaverPluginInfo|
|Version|1.4.2|
|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|MarkupPostBody|
|Overrides|confirmExit(), getParameters()|
|Description|documentation for StorySaverPlugin|
This plugin automatically saves a list of the currently viewed tiddlers (the "story") in a local cookie, {{{txtSavedStory}}} and then opens those tiddlers when the document is subsequently reloaded... the tiddlers you were viewing in the last browser session are automatically redisplayed in the next session, allowing you to quickly resume working with the document from the same place you left off!!

In addition to automatic cookie-based story tracking, the plugin also provides {{{<<saveStory>>}}} and {{{<<openStory>>}}} macros that allow you to quickly save the current story definition to a tiddler, and then re-display saved stories using simple, one-click command links or droplists.
!!!!!Usage
<<<
If a document URL does not contain a 'paramifier' (i.e., a "#..." suffix), then the saved story cookie (if any) will be used ''//as if//'' it had been entered as a 'permaview' (e.g., a "#tiddler tiddler tiddler..." suffix on the URL), bypassing the [[DefaultTiddlers]] definition.  This behavior is automatically applied whenever the plugin is installed in your document.  You can enable/disable the automatic cookie-based StorySaver feature by using the checkbox below:
>''<<option chkSaveStory>> enable StorySaverPlugin''
>//usage:// {{{<<option chkSaveStory>>}}}
You can also temporarily //bypass// the redisplay of a saved story ''without disabling the StorySaver cookie'' by including a trailing "#" at the end of the document URL.  This will cause your document to be loaded into the browser without displaying //any// initial tiddlers at all.  Alternatively, you can enter {{{#story:storyname}}} on the end of the URL (e.g., {{{#story:DefaultTiddlers}}}) to display any specific saved story, regardless of the value of the cookie-based saved story.

__''saveStory macro:''__
The {{{<<saveStory>>}}} macro lets you write the list of currently viewed tiddlers to a specified tiddler name (e.g., "DefaultTiddlers", "MyFavorites", etc.).  Tiddlers containing saved stories are automatically tagged with <<tag story>>, so that they can be recognized by the {{{<<storyViewer>>}}} macro (see [[StoryViewerPlugin]]).  The syntax for the {{{<<saveStory>>}}} macro is:
{{{
<<saveStory storyname label tooltip>>  or   <<saveStory ask label tooltip>>
}}}
where:
* ''storyname''<br>is the target tiddler in which to save the current story.  If you use the keyword, ''ask'', in place of the tiddlername, you will be prompted to enter a tiddler title when saving the story (default: DefaultTiddlers).
* ''label''<br>is the command link text (default: "set default tiddlers").
* ''tooltip''<br>is the command mouseover guide-text (default: "store a list of currently displayed tiddlers in another tiddler").

__''openStory macro:''__
To redisplay a saved story, the {{{<<openStory>>}}} macro can be used to embed either a droplist of all saved stories, or a link for a specified story.  Selecting from the droplist or clicking the link opens the corresponding set of tiddlers.  
{{{
<<openStory list>> OR <<openStory popup label tooltip>> OR <<openStory storyname label tooltip>>
}}}
where:
* ''list''<br>shows a droplist of all saved stories, plus additional commands/viewing options.  Selecting a story opens the corresponding tiddlers.
* ''popup''<br>shows a popup display containing a list of all saved stories, plus additional commands/viewing options.  Selecting a story opens the corresponding tiddlers.  ''label'' and ''tooltip'' are optional and provide alternative display text and 'mouseover' help text, respectively.
* ''storyname''<br>is a tiddler containing a saved story.  //Note: ''You can also use a tag value as a storyname.''  Instead of reading the tiddler list from the contents of the storyname tiddler, the story view will be composed of all tiddlers tagged with the specified tag value.//
* ''label''<br>is the command link text (default: "open story: %0", where %0 is replaced by the storyname).
* ''tooltip''<br>is the command mouseover guide-text (default: "open the set of tiddlers listed in: '%0'"),

__''PermaView command link enhancement:''__
In order to further aide in saving/restoring the list of tiddlers currently being viewed, the core {{{<<permaview>>}}} command has been enhanced, so its link value always includes the current story view tiddler list as a paramifier in the URL.  This let you quickly use the browser's right-click menu directly on the permalink command text to "bookmark this link...".  Depending upon your system, you may also be able to drag the 'permaview' link directly from the page and drop it onto your desktop to create an instant permaview-bearing URL shortcut icon.
<<<
!!!!!Examples
<<<
*{{{<<saveStory TestStory "save a test story">>}}}<br>{{smallform{<<saveStory TestStory "save a test story">>}}}
*{{{<<openStory TestStory>>}}}<br><<openStory TestStory>>
*{{{<<openStory list>>}}}<br>{{smallform{<<openStory list>>}}}
*{{{<<openStory popup label tooltip>>}}}<br>{{smallform{<<openStory popup>>}}}
<<<
!!!!!Revisions
<<<
2008.07.11 [1.4.2] in confirmExit(), corrected bracketing for titles containing spaces
2008.03.10 [*.*.*] plugin size reduction: documentation moved to [[StorySaverPluginInfo]]
2008.01.01 [1.4.1] sort list of stories alphabetically
2008.01.01 [1.4.0] added option to display a popup instead of a droplist control.  (Provides more compact presentation)
2007.12.31 [1.3.1] instead of readBracketedList(), use internal tiddler.links[] to retrieve story list from tiddler content. Allows more flexible formatting of story tiddler content: anything content that is not a tiddler link is automatically filtered out of the list.
2007.10.23 [1.3.0] split {{{<<storyViewer>>}}} macro definition into stand-alone [[StoryViewerPlugin]] to allow separate installation of story saving vs. story viewing features.
2007.10.21 [1.2.0] added {{{<<openStory>>}}} and {{{<<storyViewer>>}}} macros.
2007.10.20 [1.1.0] in setTiddler(), automatically add "story" tag to saved story tiddlers
2007.10.18 [1.0.1] added default initialization for chkSaveStory option value.  Also, in setTiddler(), call displayTiddler() after saving story to ensure that altered tiddler is shown to the user.
2007.10.05 [1.0.0] initial release.   Moved [[SetDefaultTiddlers]] inline script and rewrote as a {{{<<saveStory>>}}} macro.  Moved permaview "mouseover HREF" enhancement from [[CoreTweaks]].
<<<
/***
|Name|StoryViewerPlugin|
|Source|http://www.TiddlyTools.com/#StoryViewerPlugin|
|Documentation|http://www.TiddlyTools.com/#StoryViewerPluginInfo|
|Version|1.2.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|view tiddlers in a saved story, one at a time, using a droplist or "first/previous/next/last" links|
A "saved story" is a tiddler that contains a whitespace-separated list of tiddler titles.  The {{{<<storyViewer>>}}} macro allows you to quickly ''display //and// navigate between the tiddlers in a saved story'', one at a time, using a droplist containing tiddler titles or individual "first/previous/next/last" text links.
!!!!!Documentation
> see [[StoryViewerPluginInfo]]
!!!!!Revisions
<<<
2008.06.05 [1.2.0] added custom story paramifier to extract story titles from tiddler links instead of using parseParams.<br>  Permits use of links from any tiddler as a story, even if it contains wiki-syntax formatting in addition to list of tiddler titles
|please see [[StoryViewerPluginInfo]] for additional revision details|
2007.10.23 [1.0.0] Initial release, split {{{<<storyViewer>>}}} macro definition from [[StorySaverPlugin]] to allow separate installation of story saving vs. story viewing features.
<<<
!!!!!Code
***/
//{{{
version.extensions.StoryViewerPlugin= {major: 1, minor: 2, revision: 0, date: new Date(2008,6,5)};
//}}}
//{{{
config.macros.storyViewer = {
	tag: "story",
	storynotfoundmsg: "'%0' is an empty or unrecognized story",
	firstcmd: "first",
	firstbutton: "<<",
	firstmsg: "display first tiddler in story '%0'",
	nextcmd: "next",
	nextbutton: ">",
	nextmsg: "display next tiddler in story '%0'",
	previouscmd: "previous",
	previousbutton: "<",
	previousmsg: "display previous tiddler in story '%0'",
	lastcmd: "last",
	lastbutton: ">>",
	lastmsg: "display last tiddler in story '%0'",
	refreshmsg: "redisplay '%0'",
	refreshmsg: "",
	handler: function(place,macroName,params,wikifier,paramString,tiddler) {

		// get name of current tiddler (if any)
		var here=story.findContainingTiddler(place);
		if (here) var tid=here.getAttribute("tiddler");

		var storyname="";
		var p=params.shift();
		if (!p || p=='first'||p=='previous'||p=='here'||p=='next'||p=='last'||p=='list'||p=='links') {
			// find story from current tiddler name
			if (!tid) return; // not in a tiddler... do nothing!
			var stories=store.getTaggedTiddlers(this.tag);
			if (!stories) return;
			for (var s=0; s<stories.length; s++) {
				if (!stories[s].linksUpdated) stories[s].changed();
				var tids=stories[s].links;
				if (tids.contains(tid)) { storyname=stories[s].title; break; }
			}
			if (!storyname.length) return; // current tiddler is not part of a saved story
		}
		else { storyname=p; p=params.shift(); } // user-specified story name

		// get story from tiddler
		var tids=[];
		var tagged=store.getTaggedTiddlers(storyname,"excludeLists");
		if (tagged.length) // if storyname is a tag, get tagged tiddlers rather than links
			for (var t=0; t<tagged.length; t++) tids.push(tagged[t].title);
		else {
			var t=store.getTiddler(storyname);
			if (t && !t.linksUpdated) t.changed();
			var tids=t?t.links:[];
		}
		var i=0;
		switch (p) {
			case 'first':
				i=0;
				break;
			case 'previous':
				if (!tid) return; // not in a tiddler
				i=tids.indexOf(tid);
				if (i==-1) { i=0; break; } // not in story, link to start of story
				i--; if (i<0) i=0;
				break;
			case 'here': // display a refresh link for current tiddler (even if not in a story)
				if (!tid) return; // not in a tiddler
				var label=tid; if (params[0]) label=params.shift();
				createTiddlyButton(place,label,this.refreshmsg.format([tid]),
					function(){ story.refreshTiddler(story.findContainingTiddler(place).getAttribute("tiddler"), null,true); });
				return; 
			case 'next':
				if (!tid) return; // not in a tiddler
				i=tids.indexOf(tid);
				if (i==-1) { i=0; break; } // not in story, link to start of story
				i++; if (i>tids.length-1) i=tids.length-1;
				break;
			case 'last':
				i=tids.length-1;
				break;
			case 'links':
				var out="{{center{{{floatleft{";
				out+="<<storyViewer [["+storyname+"]] first first>> &nbsp; ";
				out+="<<storyViewer [["+storyname+"]] previous previous>> &nbsp; ";
				out+="}}}{{floatright{";
				out+=" &nbsp; <<storyViewer [["+storyname+"]] next next>>";
				out+=" &nbsp; <<storyViewer [["+storyname+"]] last last>>";
				out+="}}}";
				out+=" &nbsp;(story: [["+storyname+"]])&nbsp; ";
				out+="}}}";
				wikify(out,place);
				return;
			case 'list':
			default:
				var nobuttons=false;
				if (params[0]) nobuttons=(params[0].toLowerCase()=="nobuttons");
				if (nobuttons) params.shift();
				var allbuttons=false;
				if (params[0]) allbuttons=(params[0].toLowerCase()=="allbuttons");
				if (allbuttons) params.shift();
				var onlybuttons=false;
				if (params[0]) onlybuttons=(params[0].toLowerCase()=="onlybuttons");
				if (onlybuttons) params.shift();
				var h="";
				h+='<form style="display:inline">';
				if ((!nobuttons||onlybuttons) && allbuttons) {
					h+='<input type="button" value="'+this.firstbutton+'" ';
					h+='	style="padding:0" title="'+this.firstmsg.format([storyname])+'"';
					h+=' onclick="this.form.list.selectedIndex=1; this.form.list.onchange();">';
				}
				if (!nobuttons||onlybuttons) {
					h+='<input type="button" value="'+this.previousbutton+'" ';
					h+='	style="padding:0 0.3em" title="'+this.previousmsg.format([storyname])+'"';
					h+=' onclick="var i=this.form.list.selectedIndex-1; ';
					h+='	if (i<1) i=1; this.form.list.selectedIndex=i; this.form.list.onchange();">';
				}
				h+='<select size="1" name="list"';
				if (onlybuttons) h+=' style="display:none;"';
				h+=' onchange="if (this.value) story.displayTiddler(this,this.value);">';
				h+='<option value="">'+storyname+'...</option>';
				for (i=0; i<tids.length; i++) {
					h+='<option '+
						(tids[i]==tid?'selected ':'')+
						'value="'+tids[i]+'">\xa0\xa0'+tids[i]+'</option>';
				}
				h+='</select>';
				if (!nobuttons||onlybuttons) {
					h+='<input type="button" value="'+this.nextbutton+'" ';
					h+='	style="padding:0 0.3em" title="'+this.nextmsg.format([storyname])+'"';
					h+=' onclick="var i=this.form.list.selectedIndex+1; ';
					h+='	if (i>this.form.list.options.length-1) i=this.form.list.options.length-1; ';
					h+='	this.form.list.selectedIndex=i; this.form.list.onchange();">';
				}
				if ((!nobuttons||onlybuttons) && allbuttons) {
					h+='<input type="button" value="'+this.lastbutton+'" ';
					h+='	style="padding:0" title="'+this.lastmsg.format([storyname])+'"';
					h+=' onclick="this.form.list.selectedIndex=this.form.list.options.length-1; this.form.list.onchange();">';
				}
				h+='</form>';
				createTiddlyElement(place,"span").innerHTML=h;
				return;
		}
		// override default labelling with specified text (if any)
		var label=tids[i]; if (params[0]) label=params.shift();
		if (tid==tids[i]) { // self-referential links turn into 'refresh links'
			var btn=createTiddlyButton(place,null,this.refreshmsg.format([tid]),
				function() { story.refreshTiddler(story.findContainingTiddler(place).getAttribute("tiddler"),null,true); });
			wikify(label,btn); 
		}
		else // create link
			wikify(label,createTiddlyLink(place,tids[i],false));
	}
}
//}}}
//{{{
config.paramifiers.story = {
	onstart: function(v) {
		var t=store.getTiddler(v); if (t) t.changed();
		var list=t?t.links:store.getTiddlerText(v,"").parseParams("open",null,false);
		story.displayTiddlers(null,list);
	}
};
//}}}
/***
|Name|StoryViewerPluginInfo|
|Source|http://www.TiddlyTools.com/#StoryViewerPlugin|
|Documentation|http://www.TiddlyTools.com/#StoryViewerPluginInfo|
|Version|1.2.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|documentation|
|Requires||
|Overrides||
|Description|documentation for StoryViewerPlugin|
A "saved story" is a tiddler that contains a whitespace-separated list of tiddler titles.  The {{{<<storyViewer>>}}} macro allows you to quickly ''display //and// navigate between the tiddlers in a saved story'', one at a time, using a droplist containing tiddler titles or individual "first/previous/next/last" text links.
!!!!!Usage
<<<
You can define a saved story by hand-creating a tiddler containing a whitespace-separated list of tiddler titles, e.g., [[DefaultTiddlers]], [[DocumentInfo]], etc.) and tagging that tiddler with <<tag story>>, so that it will be recognized by the {{{<<storyViewer>>}}} macro.  ''You can also use the {{{<<saveStory>>}}} macro (see [[StorySaverPlugin]]), which automatically creates saved stories based on the tiddlers that are currently being viewed.''

The syntax for the {{{<<storyViewer>>}}} macro is:
{{{
<<storyViewer storyname action buttonoption>>
}}}
where:
* ''storyname''<br>is a tiddler containing a saved story.  If you omit the storyname parameter, the plugin will attempt to identify a suitable story by locating the current tiddler title within a saved story tiddler.  The story view controls are not displayed unless the current tiddler title is explicitly found in at least one saved story.  //Note: ''You can also use any tag value as a storyname.''  Instead of reading the tiddler list from the contents of the storyname tiddler, the story view will be composed of all tiddlers tagged with the specified tag value.//
*  ''action'' is one of the following keywords:
** ''list''<br>displays a droplist of tiddlers for the specified story, along with previous/next pushbuttons on either side of the list.  When using the ''list'' action, you may also specify an //optional// parameter to indicate which buttons will appear when using the droplist display:
*** ''allbuttons''<br>displays buttons for first/last as well as previous/next.
*** ''nobuttons''<br>displays the droplist without any buttons
*** ''onlybuttons''<br>hides the droplist and shows just the buttons
** ''first'', ''previous'', ''here'', ''next'', or ''last''<br>displays an individual link to the indicated tiddler within the story. The next/previous links are automatically calculated relative to the current tiddler, while ''here'' displays the current tiddler name as a link that refreshes (re-renders) the tiddler when clicked.
** ''links''<br>displays the complete set of links (first, previous, next and last) with just one convenient macro invocation, allowing you to quickly and easily embed story navigation links into any tiddler content.

You can also embed the {{{<<storyViewer>>}}} macro directly in the ViewTemplate:
{{{
<span class='floatright smallform' macro='storyViewer list allbuttons'></span>
}}}
If you omit the storyname parameter in the template-based macro, it will automatically display the story navigation interface for those tiddlers that are contained in a saved story, while omitting those controls/links for tiddler that are NOT included in a saved story.
<<<
!!!!!Examples
<<<
*{{{<<storyViewer DocumentInfo>>}}}<br>{{smallform{<<storyViewer DocumentInfo>>}}}
*{{{<<storyViewer systemConfig list allbuttons>>}}} //(uses a tag as a storyname)//<br>{{smallform{<<storyViewer systemConfig list allbuttons>>}}}
*{{{<<storyViewer systemConfig links>>}}} //(uses a tag as a storyname)//<br><<storyViewer systemConfig links>>
<<<
!!!!!Revisions
<<<
2008.06.05 [1.2.0] added custom story paramifier to extract story titles from tiddler links instead of using parseParams.  Permits use of links from any tiddler as a story, even if it contains wiki-syntax formatting in addition to list of tiddler titles
2008.03.10 [*.*.*] plugin size reduction: documentation moved to [[StoryViewerPluginInfo]]
2007.12.31 [1.1.0] instead of readBracketedList(), use internal tiddler.links[] to retrieve story list from tiddler content.  Allows more flexible formatting of story tiddler content.
2007.12.04 [*.*.*] update for TW2.3.0: replaced deprecated core functions, regexps, and macros
2007.10.23 [1.0.0] Initial release, split {{{<<storyViewer>>}}} macro definition from [[StorySaverPlugin]] to allow separate installation of story saving vs. story viewing features.
<<<
.thumbnail {
  width: 5%;
}
/***
|''Name:''|TableSortingPlugin|
|''Description:''|Dynamically sort tables by clicking on column headers|
|''Author:''|Saq Imtiaz ( lewcid@gmail.com )|
|''Source:''|http://tw.lewcid.org/#TableSortingPlugin|
|''Code Repository:''|http://tw.lewcid.org/svn/plugins|
|''Version:''|2.02|
|''Date:''|25-01-2008|
|''License:''|[[Creative Commons Attribution-ShareAlike 3.0 License|http://creativecommons.org/licenses/by-sa/3.0/]]|
|''~CoreVersion:''|2.2.3|
!!Usage:
* Make sure your table has a header row
** {{{|Name|Phone Number|Address|h}}}<br> Note the /h/ that denote a header row 
* Give the table a class of 'sortable'
** {{{
|sortable|k
|Name|Phone Number|Address|h
}}}<br>Note the /k/ that denotes a class name being assigned to the table.
* To disallow sorting by a column, place {{{<<nosort>>}}} in it's header
* To automatically sort a table by a column, place {{{<<autosort>>}}} in the header for that column
** Or to sort automatically but in reverse order, use {{{<<autosort reverse>>}}}

!!Example:
|sortable|k
|Name |Salary |Extension |Performance |File Size |Start date |h
|ZBloggs, Fred |$12000.00 |1353 |+1.2 |74.2Kb |Aug 19, 2003 21:34:00 |
|ABloggs, Fred |$12000.00 |1353 |1.2 |3350b |09/18/2003 |
|CBloggs, Fred |$12000 |1353 |1.200 |55.2Kb |August 18, 2003 |
|DBloggs, Fred |$12000.00 |1353 |1.2 |2100b |07/18/2003 |
|Bloggs, Fred |$12000.00 |1353 |01.20 |6.156Mb |08/17/2003 05:43 |
|Turvey, Kevin |$191200.00 |2342 |-33 |1b |02/05/1979 |
|Mbogo, Arnold |$32010.12 |2755 |-21.673 |1.2Gb |09/08/1998 |
|Shakespeare, Bill |£122000.00|3211 |6 |33.22Gb |12/11/1961 |
|Shakespeare, Hamlet |£9000 |9005 |-8 |3Gb |01/01/2002 |
|Fitz, Marvin |€3300.30 |5554 |+5 |4Kb |05/22/1995 |

***/
// /%
//!BEGIN-PLUGIN-CODE
config.tableSorting = {
	
	darrow: "\u2193",
	
	uarrow: "\u2191",
	
	getText : function (o) {
		var p = o.cells[SORT_INDEX];
		return p.innerText || p.textContent || '';
	},
	
	sortTable : function (o,rev) {
		SORT_INDEX = o.getAttribute("index");
		var c = config.tableSorting;
		var T = findRelated(o.parentNode,"TABLE");
		if(T.tBodies[0].rows.length<=1) 
			return;
		var itm = "";
		var i = 0;
		while (itm == "" && i < T.tBodies[0].rows.length) {
			itm = c.getText(T.tBodies[0].rows[i]).trim();
			i++;
		}
		if (itm == "") 
			return; 	
		var r = [];
		var S = o.getElementsByTagName("span")[0];		
		c.fn = c.sortAlpha; 
		if(!isNaN(Date.parse(itm)))
			c.fn = c.sortDate; 
		else if(itm.match(/^[$|£|€|\+|\-]{0,1}\d*\.{0,1}\d+$/)) 
			c.fn = c.sortNumber; 
		else if(itm.match(/^\d*\.{0,1}\d+[K|M|G]{0,1}b$/)) 
			c.fn = c.sortFile; 
		for(i=0; i<T.tBodies[0].rows.length; i++) {
			 r[i]=T.tBodies[0].rows[i]; 
		} 
		r.sort(c.reSort);
		if(S.firstChild.nodeValue==c.darrow || rev) {
			r.reverse();
			S.firstChild.nodeValue=c.uarrow;
		} 
		else 
			S.firstChild.nodeValue=c.darrow;
		var thead = T.getElementsByTagName('thead')[0]; 
		var headers = thead.rows[thead.rows.length-1].cells;
		for(var k=0; k<headers.length; k++) {
			if(!hasClass(headers[k],"nosort"))
				addClass(headers[k].getElementsByTagName("span")[0],"hidden");
		}
		removeClass(S,"hidden");
		for(i=0; i<r.length; i++) { 
			T.tBodies[0].appendChild(r[i]);
			c.stripe(r[i],i);
			for(var j=0; j<r[i].cells.length;j++){
				removeClass(r[i].cells[j],"sortedCol");
			}
			addClass(r[i].cells[SORT_INDEX],"sortedCol");
		}
	},
	
	stripe : function (e,i){
		var cl = ["oddRow","evenRow"];
		i&1? cl.reverse() : cl;
		removeClass(e,cl[1]);
		addClass(e,cl[0]);
	},
	
	sortNumber : function(v) {
		var x = parseFloat(this.getText(v).replace(/[^0-9.-]/g,''));
		return isNaN(x)? 0: x;
	},
	
	sortDate : function(v) {
		return Date.parse(this.getText(v));
	},

	sortAlpha : function(v) {
		return this.getText(v).toLowerCase();
	},
	
	sortFile : function(v) { 		
		var j, q = config.messages.sizeTemplates, s = this.getText(v);
		for (var i=0; i<q.length; i++) {
			if ((j = s.toLowerCase().indexOf(q[i].template.replace("%0\u00a0","").toLowerCase())) != -1)
				return q[i].unit * s.substr(0,j);
		}
		return parseFloat(s);
	},
	
	reSort : function(a,b){
		var c = config.tableSorting;
		var aa = c.fn(a);
		var bb = c.fn(b);
		return ((aa==bb)? 0 : ((aa<bb)? -1:1));
	}
};

Story.prototype.tSort_refreshTiddler = Story.prototype.refreshTiddler;
Story.prototype.refreshTiddler = function(title,template,force,customFields,defaultText){
	var elem = this.tSort_refreshTiddler.apply(this,arguments);
	if(elem){
		var tables = elem.getElementsByTagName("TABLE");
		var c = config.tableSorting;
		for(var i=0; i<tables.length; i++){
			if(hasClass(tables[i],"sortable")){
				var x = null, rev, table = tables[i], thead = table.getElementsByTagName('thead')[0], headers = thead.rows[thead.rows.length-1].cells;
				for (var j=0; j<headers.length; j++){
					var h = headers[j];
					if (hasClass(h,"nosort"))
						continue;
					h.setAttribute("index",j);
					h.onclick = function(){c.sortTable(this); return false;};
					h.ondblclick = stopEvent;
					if(h.getElementsByTagName("span").length == 0)
						createTiddlyElement(h,"span",null,"hidden",c.uarrow); 
					if(!x && hasClass(h,"autosort")) {
						x = j;
						rev = hasClass(h,"reverse");
					}
				}
				if(x)
					c.sortTable(headers[x],rev);		
			}
		}
	}
	return elem; 
};

setStylesheet("table.sortable span.hidden {visibility:hidden;}\n"+
	"table.sortable thead {cursor:pointer;}\n"+
	"table.sortable .nosort {cursor:default;}\n"+
	"table.sortable td.sortedCol {background:#ffc;}","TableSortingPluginStyles");

function stopEvent(e){
	var ev = e? e : window.event;
	ev.cancelBubble = true;
	if (ev.stopPropagation) ev.stopPropagation();
	return false;	
}	

config.macros.nosort={
	handler : function(place){
		addClass(place,"nosort");
	}	
};

config.macros.autosort={
	handler : function(place,m,p,w,pS){
		addClass(place,"autosort"+" "+pS);		
	}	
};
//!END-PLUGIN-CODE
// %/
! Categories
<<tagCloud E.A.S.E systemConfig ImportExportPackage DiscoveryPackage IFramePackage DarkBlueTheme BookmarkPackage pluginInfo NavigationPackage ColorPalette Extensions TaskPackage InputPackage MediaPackage systemConfigDisable Favorite Plugin lewcidExtension TaggerPlugin template excludeLists IconPackage journal>>
/***
|Name|TagCloudPlugin|
|Source|http://www.TiddlyTools.com/#TagCloudPlugin|
|Version|1.2.0|
|Author|Eric Shulman|
|Original Author|Clint Checketts|
|License|unknown|
|~CoreVersion|2.1|
|Type|plugin|
|Requires||
|Overrides||
|Description|present a 'cloud' of tags using proportional font display|
!Usage
<<<
{{{<<tagCloud>>}}}
> show all tags in the document
{{{<<tagCloud tag tag tag...>>}}}
> show all tags except those listed as parameters
{{{<<tagCloud =tagvalue>>}}}
> show only tags that are themselves tagged with the indicated tag value (i.e., ~TagglyTagging usage)
<<<
!Examples
<<<
{{{<<tagCloud>>}}}
<<tagCloud>>
----
{{{<<tagCloud =package>>}}}
<<tagCloud =package>>
<<<
!Revisions
<<<
2008.09.05 [1.2.0] ELS: added '=tagname' parameter to include only tags that are themselves tagged with the specified value (i.e., ~TagglyTagging usage)
2008.07.03 [1.1.0] ELS: added 'segments' property to macro object.  Extensive code cleanup
<<<
!Code
***/
//{{{
version.extensions.TagCloudPlugin= {major: 1, minor: 2 , revision: 0, date: new Date(2008,9,5)};
//Created by Clint Checketts, contributions by Jonny Leroy and Eric Shulman

config.shadowTiddlers.TagCloud="<<tagCloud>>";

setStylesheet("\
	.tagCloud span{height: 3.5em;margin: 3px;}\
	.tagCloud1{font-size: 80%;}\
	.tagCloud2{font-size: 100%;}\
	.tagCloud3{font-size: 120%;}\
	.tagCloud4{font-size: 150%;}\
	.tagCloud5{font-size: 180%;}\
	.tagCloud6{font-size: 200%;}\
	",
	"tagCloudsStyles");

config.macros.tagCloud = {
	noTags: "No tag cloud created because there are no tags.",
	tooltip: "%1 tiddlers tagged with '%0'",
	segments: 5,
	handler: function(place,macroName,params) {

		var tags=store.getTags();

		if (params.length) {
			if (params[0].substr(0,1)=="=") {
				// include only specifically tagged tags
				var tagged=store.getTaggedTiddlers(params[0].substr(1));
				for (var t=0; t<tagged.length; t++)
					tagged[t]=tagged[t].title;
				for (var t=0; t<tags.length; t++)
					if (!tagged.contains(tags[t][0])) tags[t][0]="";
			} else {
				// include all tags except those listed as params
				for (var t=0; t<tags.length; t++)
					if (params.contains(tags[t][0])) tags[t][0]="";
			}
		}

		// get maximum number of tags to calculate tagCloud segment sizes
		var mostTags=0;
		for (var t=0; t<tags.length; t++) if (tags[t][0].length > 0)
			if (tags[t][1]>mostTags) mostTags=tags[t][1];
		var tagSegment=mostTags/config.macros.tagCloud.segments;

		// output
		var tagCloudWrapper = createTiddlyElement(place,"div",null,"tagCloud",null);
		if(!tags.length)
			createTiddlyElement(tagCloudWrapper,"span",null,null,this.noTags);
		else for (var t=0; t<tags.length; t++) if (tags[t][0].length > 0){
			tagCloudWrapper.appendChild(document.createTextNode(" "));
			var theTag = createTiddlyButton(tagCloudWrapper,
				tags[t][0],this.tooltip.format(tags[t]),onClickTag,
				"tagCloudtag tagCloud" + (Math.round(tags[t][1]/tagSegment)+1));
			theTag.setAttribute("tag",tags[t][0]);
		}
	}
};
//}}}
/***
|''Name:''|~TaggerPlugin|
|''Version:''|1.0.1 (2006-06-01)|
|''Source:''|http://tw.lewcid.org//#TaggerPlugin|
|''Author:''|SaqImtiaz|
|''Description:''|Provides a drop down listing current tiddler tags, and allowing toggling of tags.|
|''Documentation:''|[[TaggerPluginDocumentation]]|
|''Source Code:''|[[TaggerPluginSource]]|
|''~TiddlyWiki:''|Version 2.0.8 or better|
***/
// /%
config.tagger={defaults:{label:"Tags: ",tooltip:"Manage tiddler tags",taglist:"true",excludeTags:"",notags:"tiddler has no tags",aretags:"current tiddler tags:",toggletext:"add tags:"}};config.macros.tagger={};config.macros.tagger.arrow=(document.all?"â–¼":"â–¾");config.macros.tagger.handler=function(_1,_2,_3,_4,_5,_6){var _7=config.tagger.defaults;var _8=_5.parseParams("tagman",null,true);var _9=((_8[0].label)&&(_8[0].label[0])!=".")?_8[0].label[0]+this.arrow:_7.label+this.arrow;var _a=((_8[0].tooltip)&&(_8[0].tooltip[0])!=".")?_8[0].tooltip[0]:_7.tooltip;var _b=((_8[0].taglist)&&(_8[0].taglist[0])!=".")?_8[0].taglist[0]:_7.taglist;var _c=((_8[0].exclude)&&(_8[0].exclude[0])!=".")?(_8[0].exclude[0]).readBracketedList():_7.excludeTags.readBracketedList();if((_8[0].source)&&(_8[0].source[0])!="."){var _d=_8[0].source[0];}if(_d&&!store.getTiddler(_d)){return false;}var _e=function(e){if(!e){var e=window.event;}var _11=Popup.create(this);var _12=store.getTags();var _13=new Array();for(var i=0;i<_12.length;i++){_13.push(_12[i][0]);}if(_d){var _15=store.getTiddler(_d);_13=_15.tags.sort();}var _16=_6.tags.sort();var _17=function(_18,_19,_1a){var sp=createTiddlyElement(createTiddlyElement(_11,"li"),"span",null,"tagger");var _1c=createTiddlyButton(sp,_18,_1a+" '"+_19+"'",taggerOnToggle,"button","toggleButton");_1c.setAttribute("tiddler",_6.title);_1c.setAttribute("tag",_19);insertSpacer(sp);if(window.createTagButton_orig_mptw){createTagButton_orig_mptw(sp,_19)}else{createTagButton(sp,_19);}};createTiddlyElement(_11,"li",null,"listTitle",(_6.tags.length==0?_7.notags:_7.aretags));for(var t=0;t<_16.length;t++){_17("[x]",_16[t],"remove tag ");}createTiddlyElement(createTiddlyElement(_11,"li"),"hr");if(_b!="false"){createTiddlyElement(_11,"li",null,"listTitle",_7.toggletext);for(var i=0;i<_13.length;i++){if(!_6.tags.contains(_13[i])&&!_c.contains(_13[i])){_17("[ ]",_13[i],"add tag ");}}createTiddlyElement(createTiddlyElement(_11,"li"),"hr");}var _1f=createTiddlyButton(createTiddlyElement(_11,"li"),("Create new tag"),null,taggerOnToggle);_1f.setAttribute("tiddler",_6.title);if(_d){_1f.setAttribute("source",_d);}Popup.show(_11,false);e.cancelBubble=true;if(e.stopPropagation){e.stopPropagation();}return (false);};createTiddlyButton(_1,_9,_a,_e,"button","taggerDrpBtn");};window.taggerOnToggle=function(e){var tag=this.getAttribute("tag");var _22=this.getAttribute("tiddler");var _23=store.getTiddler(_22);if(!tag){var _24=prompt("Enter new tag:","");if(_24!=""&&_24!=null){var tag=_24;if(this.getAttribute("source")){var _26=store.getTiddler(this.getAttribute("source"));_26.tags.pushUnique(_24);}}else{return false;}}if(!_23||!_23.tags){store.saveTiddler(_22,_22,"",config.options.txtUserName,new Date(),tag);}else{if(_23.tags.find(tag)==null){_23.tags.push(tag);}else{if(!_24){_23.tags.splice(_23.tags.find(tag),1);}}store.saveTiddler(_23.title,_23.title,_23.text,_23.modifier,_23.modified,_23.tags);}story.refreshTiddler(_22,null,true);if(config.options.chkAutoSave){saveChanges();}return false;};setStylesheet(".tagger a.button {font-weight: bold;display:inline; padding:0px;}\n"+".tagger #toggleButton {padding-left:2px; padding-right:2px; margin-right:1px; font-size:110%;}\n"+"#nestedtagger {background:#2E5ADF; border: 1px solid #0331BF;}\n"+".popup .listTitle {color:#000;}\n"+"","TaggerStyles");window.lewcidTiddlerSwapTag=function(_27,_28,_29){for(var i=0;i<_27.tags.length;i++){if(_27.tags[i]==_28){_27.tags[i]=_29;return true;}}return false;};window.lewcidRenameTag=function(e){var tag=this.getAttribute("tag");var _2d=prompt("Rename tag '"+tag+"' to:",tag);if((_2d==tag)||(_2d==null)){return false;}if(store.tiddlerExists(_2d)){if(confirm(config.messages.overwriteWarning.format([_2d.toString()]))){story.closeTiddler(_2d,false,false);}else{return null;}}tagged=store.getTaggedTiddlers(tag);if(tagged.length!=0){for(var j=0;j<tagged.length;j++){lewcidTiddlerSwapTag(tagged[j],tag,_2d);}}if(store.tiddlerExists(tag)){store.saveTiddler(tag,_2d);}if(document.getElementById("tiddler"+tag)){var _2f=document.getElementById(story.idPrefix+tag);var _30=story.positionTiddler(_2f);var _31=document.getElementById(story.container);story.closeTiddler(tag,false,false);story.createTiddler(_31,_30,_2d,null);story.saveTiddler(_2d);}if(config.options.chkAutoSave){saveChanges();}return false;};window.onClickTag=function(e){if(!e){var e=window.event;}var _34=resolveTarget(e);var _35=(!isNested(_34));if((Popup.stack.length>1)&&(_35==true)){Popup.removeFrom(1);}else{if(Popup.stack.length>0&&_35==false){Popup.removeFrom(0);}}var _36=(_35==false)?"popup":"nestedtagger";var _37=createTiddlyElement(document.body,"ol",_36,"popup",null);Popup.stack.push({root:this,popup:_37});var tag=this.getAttribute("tag");var _39=this.getAttribute("tiddler");if(_37&&tag){var _3a=store.getTaggedTiddlers(tag);var _3b=[];var li,r;for(r=0;r<_3a.length;r++){if(_3a[r].title!=_39){_3b.push(_3a[r].title);}}var _3d=config.views.wikified.tag;if(_3b.length>0){var _3e=createTiddlyButton(createTiddlyElement(_37,"li"),_3d.openAllText.format([tag]),_3d.openAllTooltip,onClickTagOpenAll);_3e.setAttribute("tag",tag);createTiddlyElement(createTiddlyElement(_37,"li"),"hr");for(r=0;r<_3b.length;r++){createTiddlyLink(createTiddlyElement(_37,"li"),_3b[r],true);}}else{createTiddlyText(createTiddlyElement(_37,"li",null,"disabled"),_3d.popupNone.format([tag]));}createTiddlyElement(createTiddlyElement(_37,"li"),"hr");var h=createTiddlyLink(createTiddlyElement(_37,"li"),tag,false);createTiddlyText(h,_3d.openTag.format([tag]));createTiddlyElement(createTiddlyElement(_37,"li"),"hr");var _40=createTiddlyButton(createTiddlyElement(_37,"li"),("Rename tag '"+tag+"'"),null,lewcidRenameTag);_40.setAttribute("tag",tag);}Popup.show(_37,false);e.cancelBubble=true;if(e.stopPropagation){e.stopPropagation();}return (false);};if(!window.isNested){window.isNested=function(e){while(e!=null){var _42=document.getElementById("contentWrapper");if(_42==e){return true;}e=e.parentNode;}return false;};}config.shadowTiddlers.TaggerPluginDocumentation="The documentation is available [[here.|http://tw.lewcid.org/#TaggerPluginDocumentation]]";config.shadowTiddlers.TaggerPluginSource="The uncompressed source code is available [[here.|http://tw.lewcid.org/#TaggerPluginSource]]";
// %/
/***
|Name|TiddlerTweakerPlugin|
|Source|http://www.TiddlyTools.com/#TiddlerTweakerPlugin|
|Version|2.3.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 multiple tiddlers and modify author, created, modified and/or tag values|
~TiddlerTweaker is a tool for TiddlyWiki authors.  It allows you to select multiple tiddlers from a listbox, either by direct interaction or automatically matching specific criteria.  You can then modify the creator, author, created, modified and/or tag values of those tiddlers using a compact set of form fields.  The values you enter into the fields simultantously overwrite the existing values in all tiddlers you have selected.
!!!!!Usage
<<<
{{{<<tiddlerTweaker>>}}}
{{smallform{<<tiddlerTweaker>>}}}
By default, any tags you enter into the TiddlerTweaker will //replace// the existing tags in all the tiddlers you have selected.  However, you can also use TiddlerTweaker to quickly filter specified tags from the selected tiddlers, while leaving any other tags assigned to those tiddlers unchanged:
>Any tag preceded by a "+" (plus) or "-" (minus), will be added or removed from the existing tags //instead of replacing the entire tag definition// of each tiddler (e.g., enter "-excludeLists" to remove that tag from all selected tiddlers.  When using this syntax, care should be taken to ensure that //every// tag is preceded by "+" or "-", to avoid inadvertently overwriting any other existing tags on the selected tiddlers.  (note: the "+" or "-" prefix on each tag value is NOT part of the tag value, and is only used by TiddlerTweaker to control how that tag value is processed)
Important Notes:
* Inasmuch as TiddlerTweaker is a 'power user' tool that can perform 'batch' functions (operating on many tiddlers at once), you should always have a recent backup of your document (or "save changes" just *before* tweaking the tiddlers), just in case you "shoot yourself in the foot".
* By design, TiddlerTweaker does NOT update the 'modified' date of tiddlers simply by making changes to the tiddler's values.  A tiddler's dates are ONLY updated when the corresponding 'created' and/or 'modified' checkboxes are selected and you enter new values for those dates.  As a general rule, after using TiddlerTweaker, always ''//remember to save your document//'' when you are done, even though the tiddler timeline tab may not show any recently modified tiddlers.
* Because you may be changing the values on many tiddlers simultaneously, selecting and updating all tiddlers in a document operation may take a while and your browser might warn about an "unresponsive script"... you should give it a whole bunch of time to 'continue'... it should complete the processing... eventually.
<<<
!!!!!Revisions
<<<
2009.01.22 [2.3.0] added support for text pattern find/replace
2008.10.27 [2.2.3] in setTiddlers(), fixed Safari bug by replacing static Array.concat(...) with new Array().concat(...)
2008.09.07 [2.2.2] added removeCookie() function for compatibility with [[CookieManagerPlugin]]
2008.05.12 [2.2.1] replace built-in backstage "tweak" task with tiddler tweaker control panel (moved from BackstageTweaks)
2008.01.13 [2.2.0] added "auto-selection" links: all, changed, tags, title, text
2007.12.26 [2.1.0] added support for managing 'creator' custom field (see [[CoreTweaks]])
2007.11.01 [2.0.3] added config.options.txtTweakerSortBy for cookie-based persistence of list display order preference setting.
2007.09.28 [2.0.2] in settiddlers() and deltiddlers(), added suspend/resume notification handling (improves performance when operating on multiple tiddlers)
2007.08.03 [2.0.1] added shadow definition for [[TiddlerTweaker]] tiddler for use as parameter references with {{{<<tiddler>>, <<slider>> or <<tabs>>}}} macros.
2007.08.03 [2.0.0] converted from inline script
2006.01.01 [1.0.0] initial release
<<<
!!!!!Code
***/
//{{{
version.extensions.TiddlerTweakerPlugin= {major: 2, minor: 3, revision: 0, date: new Date(2009,1,22)};

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

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

if (config.options.txtTweakerSortBy==undefined) config.options.txtTweakerSortBy="modified";

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

config.macros.tiddlerTweaker = {
	html: '<form style="display:inline"><!--\
		--><table style="padding:0;margin:0;border:0;width:100%"><tr valign="top" style="padding:0;margin:0;border:0"><!--\
		--><td style="text-align:center;white-space:nowrap;width:99%;padding:0;margin:0;border:0"><!--\
			--><font size=-2><div style="text-align:left;"><span style="float:right"><!--\
			-->&nbsp; <a href="javascript:;" \
				title="select all tiddlers"\
				onclick="\
				var f=this; while (f&&f.nodeName.toLowerCase()!=\'form\')f=f.parentNode;\
				for (var t=0; t<f.list.options.length; t++)\
					if (f.list.options[t].value.length) f.list.options[t].selected=true;\
				config.macros.tiddlerTweaker.selecttiddlers(f.list);\
				return false">all</a><!--\
			-->&nbsp; <a href="javascript:;" \
				title="select tiddlers that are new/changed since the last file save"\
				onclick="\
				var lastmod=new Date(document.lastModified);\
				var f=this; while (f&&f.nodeName.toLowerCase()!=\'form\')f=f.parentNode;\
				for (var t=0; t<f.list.options.length; t++) {\
					var tid=store.getTiddler(f.list.options[t].value);\
					f.list.options[t].selected=tid&&tid.modified>lastmod;\
				}\
				config.macros.tiddlerTweaker.selecttiddlers(f.list);\
				return false">changed</a><!--\
			-->&nbsp; <a href="javascript:;" \
				title="select tiddlers with at least one matching tag"\
				onclick="\
				var t=prompt(\'Enter space-separated tags (match ONE)\');\
				if (!t||!t.length) return false;\
				var tags=t.readBracketedList();\
				var f=this; while (f&&f.nodeName.toLowerCase()!=\'form\')f=f.parentNode;\
				for (var t=0; t<f.list.options.length; t++) {\
					f.list.options[t].selected=false;\
					var tid=store.getTiddler(f.list.options[t].value);\
					if (tid&&tid.tags.containsAny(tags)) f.list.options[t].selected=true;\
				}\
				config.macros.tiddlerTweaker.selecttiddlers(f.list);\
				return false">tags</a><!--\
			-->&nbsp; <a href="javascript:;" \
				title="select tiddlers whose titles include matching text"\
				onclick="\
				var txt=prompt(\'Enter a title (or portion of a title) to match\');\
				if (!txt||!txt.length) return false;\
				var f=this; while (f&&f.nodeName.toLowerCase()!=\'form\')f=f.parentNode;\
				for (var t=0; t<f.list.options.length; t++) {\
					f.list.options[t].selected=f.list.options[t].value.indexOf(txt)!=-1;\
				}\
				config.macros.tiddlerTweaker.selecttiddlers(f.list);\
				return false">titles</a><!--\
			-->&nbsp; <a href="javascript:;" \
				title="select tiddlers containing matching text"\
				onclick="\
				var txt=prompt(\'Enter tiddler text (content) to match\');\
				if (!txt||!txt.length) return false;\
				var f=this; while (f&&f.nodeName.toLowerCase()!=\'form\')f=f.parentNode;\
				for (var t=0; t<f.list.options.length; t++) {\
					var tt=store.getTiddlerText(f.list.options[t].value,\'\');\
					f.list.options[t].selected=(tt.indexOf(txt)!=-1);\
				}\
				config.macros.tiddlerTweaker.selecttiddlers(f.list);\
				return false">text</a> &nbsp;<!--\
			--></span><span>select tiddlers</span><!--\
			--></div><!--\
			--></font><select multiple name=list size="11" style="width:99.99%" \
				title="use click, shift-click and/or ctrl-click to select multiple tiddler titles" \
				onclick="config.macros.tiddlerTweaker.selecttiddlers(this)" \
				onchange="config.macros.tiddlerTweaker.setfields(this)"><!--\
			--></select><br><!--\
			-->show<input type=text size=1 value="11" \
				onchange="this.form.list.size=this.value; this.form.list.multiple=(this.value>1);"><!--\
			-->by<!--\
			--><select name=sortby size=1 \
				onchange="config.macros.tiddlerTweaker.init(this.form,this.value)"><!--\
			--><option value="title">title</option><!--\
			--><option value="size">size</option><!--\
			--><option value="modified">modified</option><!--\
			--><option value="created">created</option><!--\
			--></select><!--\
			--><input type="button" value="refresh" \
				onclick="config.macros.tiddlerTweaker.init(this.form,this.form.sortby.value)"<!--\
			--> <input type="button" name="stats" disabled value="totals..." \
				onclick="config.macros.tiddlerTweaker.stats(this)"><!--\
		--></td><td style="white-space:nowrap;padding:0;margin:0;border:0;width:1%"><!--\
			--><div style="text-align:left"><font size=-2>&nbsp;modify values</font></div><!--\
			--><table border=0 style="width:100%;padding:0;margin:0;border:0;"><tr style="padding:0;border:0;"><!--\
			--><td style="padding:1px;border:0;white-space:nowrap"><!--\
				--><input type=checkbox name=settitle unchecked \
					title="allow changes to tiddler title (rename tiddler)" \
					onclick="this.form.title.disabled=!this.checked">title<!--\
			--></td><td style="padding:1px;border:0;white-space:nowrap"><!--\
				--><input type=text name=title size=35 style="width:98%" disabled><!--\
			--></td></tr><tr style="padding:0;border:0;"><td style="padding:1px;border:0;white-space:nowrap"><!--\
				--><input type=checkbox name=setcreator unchecked \
					title="allow changes to tiddler creator" \
					onclick="this.form.creator.disabled=!this.checked">created by<!--\
			--></td><td style="padding:1px;border:0;white-space:nowrap"><!--\
				--><input type=text name=creator size=35 style="width:98%" disabled><!--\
			--></td></tr><tr style="padding:0;border:0;"><td style="padding:1px;border:0;white-space:nowrap"><!--\
				--><input type=checkbox name=setwho unchecked \
					title="allow changes to tiddler author" \
					onclick="this.form.who.disabled=!this.checked">modified by<!--\
			--></td><td style="padding:1px;border:0;white-space:nowrap"><!--\
				--><input type=text name=who size=35 style="width:98%" disabled><!--\
			--></td></tr><tr style="padding:0;border:0;"><td style="padding:1px;border:0;white-space:nowrap"><!--\
				--><input type=checkbox name=setcdate unchecked \
					title="allow changes to created date" \
					onclick="var f=this.form; f.cm.disabled=f.cd.disabled=f.cy.disabled=f.ch.disabled=f.cn.disabled=!this.checked"><!--\
				-->created on<!--\
			--></td><td style="padding:1px;border:0;white-space:nowrap"><!--\
				--><input type=text name=cm size=2 style="width:2em;padding:0;text-align:center" disabled><!--\
				--> / <input type=text name=cd size=2 style="width:2em;padding:0;text-align:center" disabled><!--\
				--> / <input type=text name=cy size=4 style="width:3em;padding:0;text-align:center" disabled><!--\
				--> at <input type=text name=ch size=2 style="width:2em;padding:0;text-align:center" disabled><!--\
				--> : <input type=text name=cn size=2 style="width:2em;padding:0;text-align:center" disabled><!--\
			--></td></tr><tr style="padding:0;border:0;"><td style="padding:1px;border:0;white-space:nowrap"><!--\
				--><input type=checkbox name=setmdate unchecked \
					title="allow changes to modified date" \
					onclick="var f=this.form; f.mm.disabled=f.md.disabled=f.my.disabled=f.mh.disabled=f.mn.disabled=!this.checked"><!--\
				-->modified on<!--\
			--></td><td style="padding:1px;border:0;white-space:nowrap"><!--\
				--><input type=text name=mm size=2 style="width:2em;padding:0;text-align:center" disabled><!--\
				--> / <input type=text name=md size=2 style="width:2em;padding:0;text-align:center" disabled><!--\
				--> / <input type=text name=my size=4 style="width:3em;padding:0;text-align:center" disabled><!--\
				--> at <input type=text name=mh size=2 style="width:2em;padding:0;text-align:center" disabled><!--\
				--> : <input type=text name=mn size=2 style="width:2em;padding:0;text-align:center" disabled><!--\
			--></td></tr><tr style="padding:0;border:0;"><td style="padding:1px;border:0;white-space:nowrap"><!--\
				--><input type=checkbox name=replacetext unchecked\
					title="find/replace matching text" \
					onclick="this.form.pattern.disabled=this.form.replacement.disabled=!this.checked">replace text<!--\
			--></td><td style="padding:1px;border:0;white-space:nowrap"><!--\
				--><input type=text name=pattern size=15 value="" style="width:40%" disabled \
					title="enter TEXT PATTERN (regular expression)"> with <!--\
				--><input type=text name=replacement size=15 value="" style="width:40%" disabled \
					title="enter REPLACEMENT TEXT"><!--\
			--></td></tr><tr style="padding:0;border:0;"><td style="padding:1px;border:0;white-space:nowrap"><!--\
				--><input type=checkbox name=settags checked \
					title="allow changes to tiddler tags" \
					onclick="this.form.tags.disabled=!this.checked">tags<!--\
			--></td><td style="padding:1px;border:0;white-space:nowrap"><!--\
				--><input type=text name=tags size=35 value="" style="width:98%" \
					title="enter new tags or use \'+tag\' and \'-tag\' to add/remove tags from existing tags"><!--\
			--></td></tr></table><!--\
			--><div style="text-align:center"><!--\
			--><nobr><input type=button name=display disabled style="width:32%" value="display tiddlers" \
				onclick="config.macros.tiddlerTweaker.displaytiddlers(this)"><!--\
			--> <input type=button name=del disabled style="width:32%" value="delete tiddlers" \
				onclick="config.macros.tiddlerTweaker.deltiddlers(this)"><!--\
			--> <input type=button name=set disabled style="width:32%" value="update tiddlers" \
				onclick="config.macros.tiddlerTweaker.settiddlers(this)"></nobr><!--\
			--></div><!--\
		--></td></tr></table><!--\
		--></form><span style="display:none"><!--content replaced by tiddler "stats"--></span>\
	',
	handler: function(place,macroName,params,wikifier,paramString,tiddler) {
		var span=createTiddlyElement(place,"span");
		span.innerHTML=this.html;
		this.init(span.firstChild,config.options.txtTweakerSortBy);
	},
	init: function(f,sortby) { // initialize form controls
		if (!f) return; // form might not be rendered yet...
		while (f.list.options[0]) f.list.options[0]=null; // empty current list content
		var tids=store.getTiddlers(sortby);
		if (sortby=="size") // descending order (largest tiddlers listed first)
			tids.sort(function(a,b) {return a.text.length > b.text.length ? -1 : (a.text.length == b.text.length ? 0 : +1);});
		for (i=0; i<tids.length; i++) {
			var label=tids[i].title; var value=tids[i].title;
			if (sortby=="modified" || sortby=="created") {
				label=tids[tids.length-i-1][sortby].formatString("YY.0MM.0DD 0hh:0mm ")+tids[tids.length-i-1].title;
				value=tids[tids.length-i-1].title;
			}
			if (sortby=="size") label="["+tids[i].text.length+"] "+label;
			f.list.options[f.list.length]=new Option(label,value,false,false);
		}
		f.title.value=f.who.value=f.creator.value=f.tags.value="";
		f.cm.value=f.cd.value=f.cy.value=f.ch.value=f.cn.value="";
		f.mm.value=f.md.value=f.my.value=f.mh.value=f.mn.value="";
		f.stats.disabled=f.set.disabled=f.del.disabled=f.display.disabled=true;
		f.settitle.disabled=false;
		config.options.txtTweakerSortBy=sortby; // remember current setting
		f.sortby.value=sortby; // sync droplist selection with current setting
		if (sortby!="modified") // non-default preference... save cookie
			saveOptionCookie("txtTweakerSortBy");
		else removeCookie("txtTweakerSortBy"); // default preference... clear cookie
	},
	selecttiddlers: function(here) { // enable/disable tweaker fields based on number of items selected
		// count how many tiddlers are selected
		var f=here.form; var list=f.list;
		var c=0; for (i=0;i<list.length;i++) if (list.options[i].selected) c++;
		if (c>1) f.title.disabled=true;
		if (c>1) f.settitle.checked=false;
		f.set.disabled=(c==0);
		f.del.disabled=(c==0);
		f.display.disabled=(c==0);
		f.settitle.disabled=(c>1);
		f.stats.disabled=(c==0);
		var msg=(c==0)?'select tiddlers':(c+' tiddler'+(c!=1?'s':'')+' selected');
		here.previousSibling.firstChild.firstChild.nextSibling.innerHTML=msg;
		if (c) clearMessage(); else displayMessage("no tiddlers selected");
	},
	setfields: function(here) { // set tweaker edit fields from first selected tiddler
		var f=here.form;
		if (!here.value.length) {
			f.title.value=f.who.value=f.creator.value=f.tags.value="";
			f.cm.value=f.cd.value=f.cy.value=f.ch.value=f.cn.value="";
			f.mm.value=f.md.value=f.my.value=f.mh.value=f.mn.value="";
			return;
		}
		var tid=store.getTiddler(here.value); if (!tid) return;
		f.title.value=tid.title;
		f.who.value=tid.modifier;
		f.creator.value=tid.fields['creator']||''; // custom field - might not exist
		f.tags.value=tid.tags.join(' ');
		var c=tid.created; var m=tid.modified;
		f.cm.value=c.getMonth()+1;
		f.cd.value=c.getDate();
		f.cy.value=c.getFullYear();
		f.ch.value=c.getHours();
		f.cn.value=c.getMinutes();
		f.mm.value=m.getMonth()+1;
		f.md.value=m.getDate();
		f.my.value=m.getFullYear();
		f.mh.value=m.getHours();
		f.mn.value=m.getMinutes();
	},
	settiddlers: function(here) {
		var f=here.form; var list=f.list;
		var tids=[];
		for (i=0;i<list.length;i++) if (list.options[i].selected) tids.push(list.options[i].value);
		if (!tids.length) { alert("please select at least one tiddler"); return; }
		var cdate=new Date(f.cy.value,f.cm.value-1,f.cd.value,f.ch.value,f.cn.value);
		var mdate=new Date(f.my.value,f.mm.value-1,f.md.value,f.mh.value,f.mn.value);
		if (tids.length>1 && !confirm("Are you sure you want to update these tiddlers:\n\n"+tids.join(', '))) return;
		store.suspendNotifications();
		for (t=0;t<tids.length;t++) {
			var tid=store.getTiddler(tids[t]); if (!tid) continue;
			var title=!f.settitle.checked?tid.title:f.title.value;
			var who=!f.setwho.checked?tid.modifier:f.who.value;
			var text=tid.text;
			if (f.replacetext.checked) text=text.replace(new RegExp(f.pattern.value,'mg'),f.replacement.value);
			var tags=tid.tags;
			if (f.settags.checked) { 
				var intags=f.tags.value.readBracketedList();
				var addtags=[]; var deltags=[]; var reptags=[];
				for (i=0;i<intags.length;i++) {
					if (intags[i].substr(0,1)=='+')
						addtags.push(intags[i].substr(1));
					else if (intags[i].substr(0,1)=='-')
						deltags.push(intags[i].substr(1));
					else
						reptags.push(intags[i]);
				}
				if (reptags.length)
					tags=reptags;
				if (addtags.length)
					tags=new Array().concat(tags,addtags);
				if (deltags.length)
					for (i=0;i<deltags.length;i++)
						{ var pos=tags.indexOf(deltags[i]); if (pos!=-1) tags.splice(pos,1); }
			}
			if (!f.setcdate.checked) cdate=tid.created;
			if (!f.setmdate.checked) mdate=tid.modified;
			store.saveTiddler(tid.title,title,text,who,mdate,tags,tid.fields);
			if (f.setcreator.checked) store.setValue(tid.title,'creator',f.creator.value); // set creator
			if (f.setcdate.checked) tid.assign(null,null,null,null,null,cdate); // set create date
		}
		store.resumeNotifications();
		this.init(f,f.sortby.value);
	},
	displaytiddlers: function(here) {
		var f=here.form; var list=f.list;
		var tids=[];
		for (i=0; i<list.length;i++) if (list.options[i].selected) tids.push(list.options[i].value);
		if (!tids.length) { alert("please select at least one tiddler"); return; }
		story.displayTiddlers(story.findContainingTiddler(f),tids)
	},
	deltiddlers: function(here) {
		var f=here.form; var list=f.list;
		var tids=[];
		for (i=0;i<list.length;i++) if (list.options[i].selected) tids.push(list.options[i].value);
		if (!tids.length) { alert("please select at least one tiddler"); return; }
		if (!confirm("Are you sure you want to delete these tiddlers:\n\n"+tids.join(', '))) return;
		store.suspendNotifications();
		for (t=0;t<tids.length;t++) {
			var tid=store.getTiddler(tids[t]); if (!tid) continue;
			if (tid.tags.contains("systemConfig"))
				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();
		this.init(f,f.sortby.value);
	},
	stats: function(here) {
		var f=here.form; var list=f.list; var tids=[]; var out=''; var tot=0;
		var target=f.nextSibling;
		for (i=0;i<list.length;i++) if (list.options[i].selected) tids.push(list.options[i].value);
		if (!tids.length) { alert("please select at least one tiddler"); return; }
		for (t=0;t<tids.length;t++) {
			var tid=store.getTiddler(tids[t]); if (!tid) continue;
			out+='[['+tid.title+']] '+tid.text.length+'\n'; tot+=tid.text.length;
		}
		var avg=tot/tids.length;
		out=tot+' bytes in '+tids.length+' selected tiddlers ('+avg+' bytes/tiddler)\n<<<\n'+out+'<<<\n';
		removeChildren(target);
		target.innerHTML="<hr><font size=-2><a href='javascript:;' style='float:right' "
			+"onclick='this.parentNode.parentNode.style.display=\"none\"'>close</a></font>";
		wikify(out,target);
		target.style.display="block";
	}
};
//}}}
/***
|Name|WikifyPlugin|
|Source|http://www.TiddlyTools.com/#WikifyPlugin|
|Documentation|http://www.TiddlyTools.com/#WikifyPluginInfo|
|Version|1.1.1|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|plugin|
|Requires||
|Overrides||
|Description|substitute fields, slices, or computed values into a wiki-syntax format string and render results dynamically|
The {{{<<wikify>>}}} macro allows you to easily retrieve values from custom tiddler fields, tiddler slices, computed values (using javascript) or just plain old literals, and assemble them into small bits of generated wiki-syntax text content that can be rendered directly into a tiddler, or used in the ViewTemplate or EditTemplate to add dynamically-generated content to each tiddler.

The {{{<<wikiCalc>>}}} macro performs the same processing as {{{<<wikify>>}}} and, in addition, passes the assembled text content through javascript's {{{eval()}}} function before rendering the results.  This allows you to, for example, construct and compute mathematical expressions that use input values extracted from tiddler fields or slices.
!!!!!Documentation
> see [[WikifyPluginInfo]]
!!!!!Revisions
<<<
2008.03.08 [1.1.1] size reduction: documentation moved to [[WikifyPluginInfo]]
|please see [[WikifyPluginInfo]] for additional revision details|
2007.06.22 [1.0.0] initial release
<<<
!!!!!Code
***/
//{{{
version.extensions.WikifyPlugin= {major: 1, minor: 1, revision: 1, date: new Date(2008,3,8)};

config.macros.wikify={
	handler: function(place,macroName,params,wikifier,paramString,tiddler) {
		var fmt=params.shift();
		var values=[];
		var out="";
		if (!fmt.match(/\%[0-9]/g) && params.length) // format has no markers, just join all params with spaces
			out=fmt+" "+params.join(" ");
		else { // format param has markers, get values and perform substitution
			while (p=params.shift()) values.push(this.getFieldReference(place,p));
			out=fmt.format(values);
		}
		if (macroName=="wikiCalc") out=eval(out).toString();
		wikify(out,place);
	},
	getFieldReference: function(place,p) { // "slicename::tiddlername" or "fieldname@tiddlername" or "fieldname"
		if (typeof p != "string") return p; // literal non-string value... just return it...
		var parts=p.split(config.textPrimitives.sliceSeparator);
		if (parts.length==2) {// maybe a slice reference?
			var tid=parts[0]; var slice=parts[1];
			if (!tid || !tid.length || tid=="here") { // no target (or "here"), use containing tiddler
				tid=story.findContainingTiddler(place);
				if (tid) tid=tid.getAttribute("tiddler")
				else tid="SiteSlices"; // fallback for 'non-tiddler' areas (e.g, header, sidebar, etc.)
			}
			var val=store.getTiddlerSlice(tid,slice);  // get tiddler slice value
		}
		if (val==undefined) {// not a slice, or slice not found, maybe a field reference?
			var parts=p.split("@");
			var field=parts[0];
			if (!field || !field.length) field="checked"; // missing fieldname, fallback: checked@tiddlername
			var tid=parts[1];
			if (!tid || !tid.length || tid=="here") { // no target (or "here"), use containing tiddler
				tid=story.findContainingTiddler(place);
				if (tid) tid=tid.getAttribute("tiddler")
				else tid="SiteFields"; // fallback for 'non-tiddler' areas (e.g, header, sidebar, etc.)
			}
			var val=store.getValue(tid,field);
		}
		// not a slice or field, or slice/field not found... use param value as-is
		return val===undefined?p:val;
	}
}
//}}}
//{{{
// define alternative macroName for triggering pre-rendering call to eval()
config.macros.wikiCalc=config.macros.wikify;
//}}}
/***
|Name|WikifyPlugin|
|Source|http://www.TiddlyTools.com/#WikifyPlugin|
|Documentation|http://www.TiddlyTools.com/#WikifyPluginInfo|
|Version|1.1.1|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|documentation|
|Requires||
|Overrides||
|Description|documentation for WikifyPlugin|
The {{{<<wikify>>}}} macro allows you to easily retrieve values from custom tiddler fields, tiddler slices, computed values (using javascript) or just plain old literals, and assemble them into small bits of generated wiki-syntax text content that can be rendered directly into a tiddler, or used in the ViewTemplate or EditTemplate to add dynamically-generated content to each tiddler.

The {{{<<wikiCalc>>}}} macro performs the same processing as {{{<<wikify>>}}} and, in addition, passes the assembled text content through javascript's {{{eval()}}} function before rendering the results.  This allows you to, for example, construct and compute mathematical expressions that use input values extracted from tiddler fields or slices.
!!!!!Usage
<<<
The syntax for use in tiddlers:
{{{
<<wikify format value value value value ...>>
<<wikiCalc format value value value value ...>>
}}}
The syntax for use in templates:
{{{
<span macro='wikify format value value value value ...'></span>
<span macro='wikiCalc format value value value value ...'></span>
}}}
where:
* ''format'' specifies the format of the wiki-syntax content (or javascript expression, if using {{{<<wikiCalc>>}}}) that will be rendered
* ''value'' parameters (space-separated), specified using any of:
** ''"tiddlername::slicename"'' - a tiddler slice reference
** ''"fieldname@tiddlername"'' - a tiddler custom field reference
** ''"""{{config.options.txtUserName}}"""'' - evaluated javascript parameter
** ''"none of the above"'' - literal text
When the ''format'' parameter contains //substitution markers// (using "%0" through "%9" character sequences), each value parameter is retrieved and embedded into the formatted content, replacing its corresponding marker.  If the ''format'' parameter does //not// contain any substitution markers, then all parameters are simply joined together for output.  Once the values have been formatted (and, if {{{<<wikiCalc>>}}} is used, evaluated as a javascript expression), the resulting content is then passed to the core wikify() parser to render and display it.

Notes:
* If a parameter is not recognized as fitting any of the above syntax, or if the slice/field referred to cannot be located, the reference will be inserted as literal text into the output
* When working with custom tiddler fields or tiddler slices, you can enter a special psuedo-tiddler name, ''@here'' (e.g., "fieldname@here") or ''here::'' (e.g., "here::slicename") to access custom fields and slices associated with the //current// tiddler.  This //relative// reference syntax can be particularly helpful when placed directly into a ViewTemplate and/or EditTemplate definition, where it can be applied automatically to each tiddler that is displayed.   Note: if you omit the ''@here'' portion of a field reference (e.g., just using "fieldname"), it is assumed to be a reference to a field in the current tiddler (i.e., it is treated as if you specified ''fieldname@here'').
<<<
!!!!!Examples
<<<
{{{
<<wikify [[This tiddler is: %0 using %1 bytes (last author: %2)]] title {{tiddler.text.length}} modifier>>
<<wikify [[The source URL for this plugin is: %0]] 'here::Source'>>
<<wikify [[The tiddler has been changed %0 times]] changecount@here>>
<<wikify [[The Primary Mid color is: @@background:%0;%0@@]] 'ColorPalette::PrimaryMid'>>
<<wikify [[This current user is: %0]] {{config.options.txtUserName}}>>
}}}
<<wikify [[This tiddler is: %0 using %1 bytes (last author: %2)]] title {{tiddler.text.length}} modifier>>
<<wikify [[The source URL for this plugin is: %0]] 'here::Source'>>
<<wikify [[The tiddler has been changed %0 times]] changecount@here>>
<<wikify [[The Primary Mid color is: @@background:%0;%0@@]] 'ColorPalette::PrimaryMid'>>
<<wikify [[This current user is: %0]] {{config.options.txtUserName}}>>
<<<
!!!!!Revisions
<<<
2008.03.08 [1.1.1] size reduction: documentation moved to [[WikifyPluginInfo]]
2008.03.07 [1.1.0] added {{{<<wikicalc>>}}} variant for evaluating assembled output as javascript before rendering the result
2007.11.11 [1.0.1] in handler(), fixed problem where a trailing space was created when no substitution markers were present in the format param.
2007.06.22 [1.0.0] initial release
<<<