<!--{{{-->
<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 0 1em 1em; left:-1px; top:-1px;}
.headerForeground {position:absolute; padding:4.5em 0 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:0 0.2em; padding:0.2em 0.3em; display:block;}
#sidebarOptions input {margin:0.4em 0.5em;}
#sidebarOptions .sliderPanel {margin-left:1em; padding:0.5em; font-size:.85em;}
#sidebarOptions .sliderPanel a {font-weight:bold; display:inline; padding:0;}
#sidebarOptions .sliderPanel input {margin:0 0 0.3em 0;}
#sidebarTabs .tabContents {width:15em; overflow:hidden;}
 
.wizard {padding:0.1em 1em 0 2em;}
.wizard h1 {font-size:2em; font-weight:bold; background:none; padding:0; margin:0.4em 0 0.2em;}
.wizard h2 {font-size:1.2em; font-weight:bold; background:none; padding:0; margin:0.4em 0 0.2em;}
.wizardStep {padding:1em 1em 1em 1em;}
.wizard .button {margin:0.5em 0 0; font-size:1.2em;}
.wizardFooter {padding:0.8em 0.4em 0.8em 0;}
.wizardFooter .status {padding:0 0.4em; margin-left:1em;}
.wizard .button {padding:0.1em 0.2em;}
 
#messageArea {position:fixed; top:2em; right:0; margin:0.5em; padding:0.5em; z-index:2000; _position:absolute;}
.messageToolbar {display:block; text-align:right; padding:0.2em;}
#messageArea a {text-decoration:underline;}
 
.tiddlerPopupButton {padding:0.2em;}
.popupTiddler {position: absolute; z-index:300; padding:1em; margin:0;}
 
.popup {position:absolute; z-index:300; font-size:.9em; padding:0; list-style:none; margin:0;}
.popup .popupMessage {padding:0.4em;}
.popup hr {display:block; height:1px; width:auto; padding:0; margin:0.2em 0;}
.popup li.disabled {padding:0.4em;}
.popup li a {display:block; padding:0.4em; font-weight:normal; cursor:pointer;}
.listBreak {font-size:1px; line-height:1px;}
.listBreak div {margin:2px 0;}
 
.tabset {padding:1em 0 0 0.5em;}
.tab {margin:0 0 0 0.25em; padding:2px;}
.tabContents {padding:0.5em;}
.tabContents ul, .tabContents ol {margin:0; padding:0;}
.txtMainTab .tabContents li {list-style:none;}
.tabContents li.listLink { margin-left:.75em;}
 
#contentWrapper {display:block;}
#splashScreen {display:none;}
 
#displayArea {margin:1em 17em 0 14em;}
 
.toolbar {text-align:right; font-size:.9em;}
 
.tiddler {padding:1em 1em 0;}
 
.missing .viewer,.missing .title {font-style:italic;}
 
.title {font-size:1.6em; font-weight:bold;}
 
.missing .subtitle {display:none;}
.subtitle {font-size:1.1em;}
 
.tiddler .button {padding:0.2em 0.4em;}
 
.tagging {margin:0.5em 0.5em 0.5em 0; float:left; display:none;}
.isTag .tagging {display:block;}
.tagged {margin:0.5em; float:right;}
.tagging, .tagged {font-size:0.9em; padding:0.25em;}
.tagging ul, .tagged ul {list-style:none; margin:0.25em; padding:0;}
.tagClear {clear:both;}
 
.footer {font-size:.9em;}
.footer li {display:inline;}
 
.annotation {padding:0.5em; margin:0.5em;}
 
* html .viewer pre {width:99%; padding:0 0 1em 0;}
.viewer {line-height:1.4em; padding-top:0.5em;}
.viewer .button {margin:0 0.25em; padding:0 0.25em;}
.viewer blockquote {line-height:1.5em; padding-left:0.8em;margin-left:2.5em;}
.viewer ul, .viewer ol {margin-left:0.5em; padding-left:1.5em;}
 
.viewer table, table.twtable {border-collapse:collapse; margin:0.8em 1.0em;}
.viewer th, .viewer td, .viewer tr,.viewer caption,.twtable th, .twtable td, .twtable tr,.twtable caption {padding:3px;}
table.listView {font-size:0.85em; margin:0.8em 1.0em;}
table.listView th, table.listView td, table.listView tr {padding: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 0; font-size:.9em;}
.editorFooter .button {padding-top:0px; padding-bottom:0px;}
 
.fieldsetFix {border:0; padding:0; margin: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;}
#backstageToolbar {position:relative;}
#backstageArea a {font-weight:bold; margin-left:0.5em; padding:0.3em 0.5em;}
#backstageButton {display:none; position:absolute; z-index:175; top:0; right:0;}
#backstageButton a {padding:0.1em 0.4em; margin:0.1em;}
#backstage {position:relative; width:100%; z-index:50;}
#backstagePanel {display:none; z-index:100; position:absolute; width:90%; margin-left:3em; padding:1em;}
.backstagePanelFooter {padding-top:0.2em; float:right;}
.backstagePanelFooter a {padding:0.2em 0.4em;}
#backstageCloak {display:none; z-index:20; position:absolute; width:100%; height:100px;}
 
.whenBackstage {display:none;}
.backstageVisible .whenBackstage {display:block;}
/*}}}*/
/***
StyleSheet for use when a translation requires any css style changes.
This StyleSheet can be used directly by languages such as Chinese, Japanese and Korean which need larger font sizes.
***/
/*{{{*/
body {font-size:0.8em;}
#sidebarOptions {font-size:1.05em;}
#sidebarOptions a {font-style:normal;}
#sidebarOptions .sliderPanel {font-size:0.95em;}
.subtitle {font-size:0.8em;}
.viewer table.listView {font-size:0.95em;}
/*}}}*/
/*{{{*/
@media print {
#mainMenu, #sidebar, #messageArea, .toolbar, #backstageButton, #backstageArea {display: none !important;}
#displayArea {margin: 1em 1em 0em;}
noscript {display:none;} /* Fixes a feature in Firefox 1.5.0.2 where print preview displays the noscript content */
}
/*}}}*/
<!--{{{-->
<div class='header' macro='gradient vert [[ColorPalette::PrimaryLight]] [[ColorPalette::PrimaryMid]]'>
<div class='headerShadow'>
<span class='siteTitle' refresh='content' tiddler='SiteTitle'></span>&nbsp;
<span class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'></span>
</div>
<div class='headerForeground'>
<span class='siteTitle' refresh='content' tiddler='SiteTitle'></span>&nbsp;
<span class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'></span>
</div>
</div>
<div id='mainMenu' refresh='content' tiddler='MainMenu'></div>
<div id='sidebar'>
<div id='sidebarOptions' refresh='content' tiddler='SideBarOptions'></div>
<div id='sidebarTabs' refresh='content' force='true' tiddler='SideBarTabs'></div>
</div>
<div id='displayArea'>
<div id='messageArea'></div>
<div id='tiddlerDisplay'></div>
</div>
<!--}}}-->
<!--{{{-->
<div class='toolbar' macro='toolbar [[ToolbarCommands::ViewToolbar]]'></div>
<div class='title' macro='view title'></div>
<div class='subtitle'><span macro='view modifier link'></span>, <span macro='view modified date'></span> (<span macro='message views.wikified.createdPrompt'></span> <span macro='view created date'></span>)</div>
<div class='tagging' macro='tagging'></div>
<div class='tagged' macro='tags'></div>
<div class='viewer' macro='view text wikified'></div>
<div class='tagClear'></div>
<!--}}}-->
<!--{{{-->
<div class='toolbar' macro='toolbar [[ToolbarCommands::EditToolbar]]'></div>
<div class='title' macro='view title'></div>
<div class='editor' macro='edit title'></div>
<div macro='annotations'></div>
<div class='editor' macro='edit text'></div>
<div class='editor' macro='edit tags'></div><div class='editorFooter'><span macro='message views.editor.tagPrompt'></span><span macro='tagChooser excludeLists'></span></div>
<!--}}}-->
To get started with this blank [[TiddlyWiki]], you'll need to modify the following tiddlers:
* [[SiteTitle]] & [[SiteSubtitle]]: The title and subtitle of the site, as shown above (after saving, they will also appear in the browser title bar)
* [[MainMenu]]: The menu (usually on the left)
* [[DefaultTiddlers]]: Contains the names of the tiddlers that you want to appear when the TiddlyWiki is opened
You'll also need to enter your username for signing your edits: <<option txtUserName>>
These [[InterfaceOptions]] for customising [[TiddlyWiki]] are saved in your browser
 
Your username for signing your edits. Write it as a [[WikiWord]] (eg [[JoeBloggs]])
 
<<option txtUserName>>
<<option chkSaveBackups>> [[SaveBackups]]
<<option chkAutoSave>> [[AutoSave]]
<<option chkRegExpSearch>> [[RegExpSearch]]
<<option chkCaseSensitiveSearch>> [[CaseSensitiveSearch]]
<<option chkAnimate>> [[EnableAnimations]]
 
----
Also see [[AdvancedOptions]]
<<importTiddlers>>
[[TwitterBackupWizard]]
[[ThemeSwitcher]]
GettingStarted
LifeStream
— because they're your tweets!
Twitter Archiver
 
<!--<<view title>>-->,"<!--<<view text>>-->",<!--<<view modified date>>-->
TweetID,Tweet,Date
<!--<<templateTiddlers CsvItemTemplate filter:"[tag[tweets]]">>-->
//{{{
 
// CustomTracker as a namespace for tracking related functions
var CustomTracker = {
	// store a reference to the original displayTiddler function
	displayTiddler: story.displayTiddler,
	// initialise the Google tracker - specify your account number here!
	pageTracker: _gat._getTracker("UA-8645534-1")
};
 
CustomTracker.track = function(path) {
	if (document.location.protocol == "http:" || document.location.protocol == "https:") {
		this.pageTracker._trackPageview(path);
	}
};
 
CustomTracker.trackAndDisplayTiddler = function(srcElement, t) {
	// cope whether a tiddler or a string is passed
	var title = t.title || t;
	// log with the tracker
	CustomTracker.track('/' + title);
	// call the original displayTiddler function
	CustomTracker.displayTiddler.apply(this,arguments);
};
 
// replace the default displayTiddler function with a tracking version
story.displayTiddler = CustomTracker.trackAndDisplayTiddler;
 
// Call once for the initial page load
CustomTracker.track();
//}}}
Under the hood, TiddlyTweets is a plugin-extended ~TiddlyWiki (hence the name). ~TiddlyWiki is an open source project that Osmosoft has a lot of involvement with. Everything about TiddlyTweets is controlled by plugins written in JavaScript, a breakdown of which is below. If you want to get into exploring the guts, hit the "switch theme" button in the top-right to change into the ~TiddlyWiki theme, which makes it easier to navigate between tiddlers (did I mention those? A tiddler is a bit of content, or a plugin).
 
|Plugin |What's it for? |
|TwitterAdaptor |Handles communication with Twitter's API and converts returned tweets into tiddlers |
|TwitterWizardPlugin |Provides the user interface and uses the TwitterAdaptor |
|TemplatePlugin |Provides the mechanism for turning tiddlers into other data formats using templates |
|TemplatingMacrosPlugin |Adds some macros you can use inside templates to get at tiddler data |
|TemplateFormatterPlugin |Parses templates and calls macros inside them |
|TiddlyTemplatingMacro |Uses the above three plugins to generate the output XML and either save it to a file (if offline) or pop up a window with it in |
|ToggleThemePlugin |Adds the "switch theme" button |
 
|Tiddler |What's it for? |
|[[How to hack this]] |What you're reading. |
|RssTemplate |Template for creating an RSS feed from tiddlers |
|RssItemTemplate |Sub-template for each item in the RSS feed |
|RssItemCategoryTemplate |Sub-template for the tags on an RSS item |
|ThemeSwitcher |Contains a call to the toggleTheme macro to generate the "switch theme" button |
|TiddlyTweets |Information about TiddlyTweets |
|TiddlyTweetsTheme |The stylesheet, page template and tiddler view template for the default web app look |
|TiddlyWikiTheme |The stylesheet, page template and tiddler view template for the standard ~TiddlyWiki theme (plus the "switch theme" button) |
|TwitterBackupWizard |Contains a call to the TwitterBackupWizard macro to generate the Tweet Archiver interface |
twitter: [[@jayfresh|http://twitter.com/jayfresh]
blog: http://jaybyjayfresh.com
<<lifeStream tweets>>
/*
 * Javascript Humane Dates
 * Copyright (c) 2008 Dean Landolt (deanlandolt.com)
 * Re-write by Zach Leatherman (zachleat.com)
 * 
 * Adopted from the John Resig's pretty.js
 * at http://ejohn.org/blog/javascript-pretty-date
 * and henrah's proposed modification 
 * at http://ejohn.org/blog/javascript-pretty-date/#comment-297458
 * 
 * Licensed under the MIT license.
 */
 
function humane_date(date_str){
	var time_formats = [
		[60, 'Just Now'],
		[90, '1 Minute'], // 60*1.5
		[3600, 'Minutes', 60], // 60*60, 60
		[5400, '1 Hour'], // 60*60*1.5
		[86400, 'Hours', 3600], // 60*60*24, 60*60
		[129600, '1 Day'], // 60*60*24*1.5
		[604800, 'Days', 86400], // 60*60*24*7, 60*60*24
		[907200, '1 Week'], // 60*60*24*7*1.5
		[2628000, 'Weeks', 604800], // 60*60*24*(365/12), 60*60*24*7
		[3942000, '1 Month'], // 60*60*24*(365/12)*1.5
		[31536000, 'Months', 2628000], // 60*60*24*365, 60*60*24*(365/12)
		[47304000, '1 Year'], // 60*60*24*365*1.5
		[3153600000, 'Years', 31536000], // 60*60*24*365*100, 60*60*24*365
		[4730400000, '1 Century'], // 60*60*24*365*100*1.5
	];
 
	var time = ('' + date_str).replace(/-/g,"/").replace(/[TZ]/g," "),
		dt = new Date,
		seconds = ((dt - new Date(time) + (dt.getTimezoneOffset() * 60000)) / 1000),
		token = ' Ago',
		i = 0,
		format;
 
	if (seconds < 0) {
		seconds = Math.abs(seconds);
		token = '';
	}
 
	while (format = time_formats[i++]) {
		if (seconds < format[0]) {
			if (format.length == 2) {
				return format[1] + (i > 1 ? token : ''); // Conditional so we don't return Just Now Ago
			} else {
				return Math.round(seconds / format[2]) + ' ' + format[1] + (i > 1 ? token : '');
			}
		}
	}
 
	// overflow for centuries
	if(seconds > 4730400000)
		return Math.round(seconds / 4730400000) + ' Centuries' + token;
 
	return date_str;
};
 
if(typeof jQuery != 'undefined') {
	jQuery.fn.humane_dates = function(){
		return this.each(function(){
			var date = humane_date(this.title);
			if(date && jQuery(this).text() != date) // don't modify the dom if we don't have to
				jQuery(this).text(date);
		});
	};
}
 
 
config.macros.lifeStream = {};
config.macros.lifeStream.handler = function(place,macroName,params)
{
	config.macros.lifeStream.display(place, params);
};
 
config.macros.lifeStream.display = function (place, params)
{
	var tag = params[0];
	if(!tag) {
		throw "Provide a tag as a parameter to include tiddlers with that tag";
	}
	removeChildren(place);
	setStylesheet(".tiddler .button, .tiddler .button:hover {background-repeat:no-repeat;  margin:1px; float:none}"+
	".tiddler .button:hover,.tiddler .button	 {background-repeat:no-repeat; float:none;  }"+
	".textSpace {padding-top:1px}"+
	".tiddler .button, .tiddler .button:hover {padding:5px; margin:5px}"+
	".noFloat {float:none; background-color:red;}"+
	".stream { display: block; padding:1px; margin:1px ; max-width:500px;  min-height:20px; }"+
	".imgClass {float:left; display:block;padding-right:10px}");
	var tiddlers = store.reverseLookup("tags","excludeLists",false,"modified");
	var last = params[1] ? tiddlers.length-Math.min(tiddlers.length,parseInt(params[1])) : 0;
	var div = createTiddlyElement(place, "div");
	var lastDay ="";
	var today = new Date;
	var yesterday = new Date();
	yesterday.setDate(yesterday.getDate()-1);
	for(var t=tiddlers.length-1; t>=last; t--) {
		if(tiddlers[t].isTagged("tweets")) {
			if(typeof(tiddlers[t]['modified'])!='undefined'){
				var theDay = tiddlers[t]['modified'].convertToLocalYYYYMMDDHHMM().substr(0,8);
				if(theDay != lastDay) {
					if(tiddlers[t]['modified'].formatString("DD/MM/YYYY")==today.formatString("DD/MM/YYYY"))
						createTiddlyElement(place, "h3", null, null,  "Today");
					else if(tiddlers[t]['modified'].formatString("DD/MM/YYYY")==yesterday.formatString("DD/MM/YYYY"))
						createTiddlyElement(place, "h3", null, null,  "Yesterday");
					else
						createTiddlyElement(place, "h3", null, null, tiddlers[t]['modified'].formatString("DD/MM/YYYY"));
					lastDay = theDay;
				}		
			}
			var img = createTiddlyElement(null, "img", null, "imgClass");
			//img.src = tiddlers[t].fields['user_img'];
			img.src= "http://www.bioneural.net/wp-content/themes/k2bn/styles/bioneural/twitter.png";
			img.width = "16";
			img.height = "16";
			var slider = config.macros.slider.createSlider(place, "", "");
			addClass(slider,"slider");
			var sliderButton = findRelated(slider,"button","className","previousSibling");
			sliderButton.appendChild(img);
		
			var div = createTiddlyElement(sliderButton, "div", null, "textSpace");
			div.innerHTML =  tiddlers[t].text;
			addClass(sliderButton,"stream twitterStream");
			createTiddlyElement(sliderButton, "div", null, "noFloat");
			// this should choose some relevant fields - these are undefined for the tweets
			wikify(tiddlers[t].fields['url']+"\n\r"+tiddlers[t].fields.prettyDate,slider);
		}
	}
};
<?xml version="1.0"?>
<rss version="2.0">
<channel>
<title><!--<<tiddler SiteTitle>>--></title>
<link><!--<<tiddler SiteURL>>--></link>
<description><!--<<tiddler SiteSubtitle>>--></description>
<language>en-us</language>
<copyright>Copyright <!--<<today "ddd, DD MMM YYYY 0hh:0hh:0ss TZD">>--> <!--<<message config.options.txtUserName>>--></copyright>
<pubDate><!--<<today "ddd, DD MMM YYYY 0hh:0hh:0ss TZD">>--></pubDate>
<lastBuildDate><!--<<today "ddd, DD MMM YYYY 0hh:0hh:0ss TZD">>--></lastBuildDate>
<docs>http://blogs.law.harvard.edu/tech/rss</docs>
<generator>TiddlyWiki <!--<<message version.major>>-->.<!--<<message version.minor>>-->.<!--<<message version.revision>>--></generator>
<!--<<templateTiddlers RssItemTemplate filter:"[tag[tweets]]">>-->
</channel>
</rss>
<<toggleTheme TiddlyWikiTheme TiddlyTweetsTheme>>
|''Name:''|TiddlyTweetsTheme|
|''Description:''|Simple theme for TiddlyTweets|
|''Author:''|Jonathan Lister (jnthnlstr (at) googlemail (dot) com)|
|''~CodeRepository:''|http://svn.tiddlywiki.org/Trunk/contributors/JonathanLister/verticals/FNDTiddlyTweets/content/TiddlyTweetsTheme.tiddler |
|''Version:''|0.5|
|''Date:''|Mar 4, 2009|
|''Comments:''|Please make comments at http://groups.google.co.uk/group/TiddlyWikiDev |
|''License:''|[[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]] |
|''~CoreVersion:''|2.4.0|
 
|''~StyleSheet:''|##StyleSheet|
|''~PageTemplate:''|##PageTemplate|
|''~ViewTemplate:''|##ViewTemplate|
 
 
!StyleSheet
/*{{{*/
div.header {
	margin:0em 17em 0 14em;
}
 
div.headerShadow { 
	color: #DF4141;
}
 
#displayArea,
div.header {
	margin-left: 17em;
}
 
div.logo {
	padding: 12px;
	padding-left: 15px;
	float: left;
	position: absolute;
	top: 20px;
	left: 800px;
	z-index: 2;
}
 
div.header,
div.headerShadow {
	background-color: #DF4141;
        -moz-border-radius-bottomleft: 5px;
        -moz-border-radius-bottomright: 5px;
        -webkit-border-bottom-left-radius: 5px;
        -webkit-border-bottom-right-radius: 5px;
}
 
.headerForeground {
	padding-top: 2em;
}
 
.siteTitle {
	padding-left: 1em;
	line-height: 1.6em;
}
 
.siteSubtitle {
	padding-left: 2em;
	font-style: italic;
}
 
 
div.viewer {
	font-size: 1.2em;
	line-height: 1.6em;
}
 
#tiddlerThemeSwitcher {
	position:absolute;
	top:0px;
	right:0px;
}
 
#backstageButton {
	display:none;
}
 
.wizard {
	background-color:#eeeeee;
        border:2px solid #888;
        -moz-border-radius:5px;
        -webkit-border-radius:5px;
	padding: 2em;
}
 
.wizard > h1 {
	display: none;
}
 
.wizardBody h2 {
	line-height: 2em;
}
.wizardBody h2:after {
	content: ":";
}
 
.wizardFooter {
	background-color:#eeeeee;
        border:none;
}
 
.wizardFooter .button,
.button {
	background-color: #DF4141;
	color: #fff;
	padding: 5px;
        -moz-border-radius:5px;
        -webkit-border-radius:5px;
	border:none;
        border-bottom: 1px solid #000;
        border-right: 1px solid #000;
}
 
#tiddlerTwitterBackupWizard {
	padding: 0em;
}
 
#tiddlerThemeSwitcher div.viewer .button {
	font-size: 1.2em;
	line-height: 1.6em;
	padding: 5px;
	border:none;
        border-bottom: 1px solid #000;
        border-right: 1px solid #000;
}
 
#tiddlerThemeSwitcher div.viewer .button:hover,
div.wizardFooter .button:hover {
	background-color: #3875D7;
	color: #fff;
	border:none;
        border-bottom: 1px solid #000;
        border-right: 1px solid #000;
}
 
.wizardStep {
	border-color:#4D294D;
	padding: 1em;
	margin-bottom: 1em;
}
 
.progress {
	background-color: #8A2BE2;
	display: block;
	height: 2em;
	margin-bottom: -2em;
	width: 0%;
}
 
/* GrowlStyle Message Area */
#messageArea {
        border:none;
        background: transparent;
}
 
#messageArea .messageBox {
        border:2px solid #888;
        color: #000;
	background-color:#eeeeee;
        width:20em;
        padding:10px;
        margin-top:5px;
        margin-bottom:5px;
        -moz-border-radius:5px;
        -webkit-border-radius:5px;
        filter:alpha(opacity=80);
}
 
#messageArea .messageText {
        display:block;
        width:15em;
        margin:0;
        padding:0;
}
 
#messageArea .messageClear {
        display:block;
        float:right;
        width:1em;
}
 
#messageArea .messageClear a {
        text-decoration:none;
        background-color: transparent;
        color:[[ColorPalette::Foreground]];
}
 
 
/*}}}*/
 
!ViewTemplate
<!--{{{--->
<div class='viewer' macro='view text wikified'></div>
<div class='tagClear'></div>
<!--}}}-->
 
!PageTemplate
<!--{{{-->
<div class='logo'><img src="TwitterArchiverLogo.png"/></div>
<div class='header'>
<div class='headerShadow'>
<span class='siteTitle'></span>&nbsp;
<span class='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='displayArea'>
<div id='messageArea'></div>
<div id='tiddlerDisplay'></div>
</div>
<div id='footer' refresh='content' tiddler='SiteFooter'></div>
<!--}}}-->
You might be wondering what this is all about.
 
TiddlyTweets is the work of [[Fred|http://osmosoft.com/#%5B%5BFrederik%20Dohr%5D%5D]] and [[Jonathan|http://osmosoft.com/#%5B%5BJon%20Lister%5D%5D]] from [[Osmosoft|http://osmosoft.com]]. It serves as an example of a client-side mashup, creating a useful application in a web-friendly way, using only HTML, CSS and ~JavaScript.
 
If you're interested, you might like to know how this application is put together. It's really a [[TiddlyWiki|http://www.tiddlywiki.com]] loaded up with plugins. Read on for [[how to hack this|How to hack this]].
 
|''Name:''|DefaultTheme|
|''Description:''|Empty theme which resets to the defaults, leaving the ThemeSwitcher tiddler styled|
 
|''StyleSheet:''|##StyleSheet|
 
!StyleSheet
#tiddlerThemeSwitcher {
	position:absolute;
	top:0.6em;
	right:0;
}
 
#tiddlerThemeSwitcher div {
	display:none;
}
 
#tiddlerThemeSwitcher div.viewer {
	display:block;
}
 
#tiddlerThemeSwitcher div.viewer .button {
	background-color:#ffffff;
	border:#ffffff
}
 
#tiddlerThemeSwitcher div.viewer .button:hover {
	background-color:orange;
}
<<search>>
<<TwitterBackupWizard>>
[[What's this?|TiddlyTweets]]
|''Type''|twitter|
|''URL''|http://www.twitter.com|
/***
|''Name''|HTTPThrottlingPlugin|
|''Description''|limit the amount of simultaneous XMLHttpRequests|
|''Author''|FND|
|''Version''|0.1.1|
|''Status''|@@beta@@|
|''Source''|http://devpad.tiddlyspot.com/#HTTPThrottlingPlugin|
|''CodeRepository''|http://svn.tiddlywiki.org/Trunk/contributors/FND/|
|''License''|[[Creative Commons Attribution-ShareAlike 3.0 License|http://creativecommons.org/licenses/by-sa/3.0/]]|
|''CoreVersion''|2.4.1|
!Revision History
!!v0.1 (2008-11-05)
* initial release
!To Do
* use queuing instead of polling
!Code
***/
//{{{
if(!version.extensions.HTTPThrottlingPlugin) { //# ensure that the plugin is only installed once
version.extensions.HTTPThrottlingPlugin = { installed: true };
 
if(!config.extensions) { config.extensions = {}; }
 
config.extensions.HTTPThrottlingPlugin = {
	XHRCount: 0,
	throttleAmount: 2, // browsers' max. number of concurrent HTTP connections
	throttleDelay: 1000,
 
	init: function() {
		// hijack httpReq to throttle simultaneous XHRs
		var httpReq_orig = httpReq;
		httpReq = function(type, url, callback, params, headers, data, contentType, username, password, allowCache) {
			var context = config.extensions.HTTPThrottlingPlugin;
			if(context.XHRCount >= context.throttleAmount) {
				var defer = function() {
					return httpReq(type, url, callback, params, headers, data, contentType, username, password, allowCache);
				};
				setTimeout(defer, context.throttleDelay);
			} else {
				context.XHRCount++;
				var callbackWrapper = function(status, params, responseText, url, x) {
					context.XHRCount--;
					return callback(status, params, responseText, url, x);
				};
				var args = [type, url, callbackWrapper, params, headers, data, contentType, username, password, allowCache];
				return httpReq_orig.apply(this, args);
			}
		};
	}
};
 
config.extensions.HTTPThrottlingPlugin.init();
 
} //# end of "install only once"
//}}}
/***
|''Name''|TwitterAdaptor|
|''Description''|adaptor for retrieving data from Twitter|
|''Author''|FND|
|''Contributors''|[[Simon McManus|http://simonmcmanus.com]], MartinBudden|
|''Version''|0.3.6|
|''Status''|@@beta@@|
|''Source''|http://devpad.tiddlyspot.com/#TwitterAdaptor|
|''CodeRepository''|http://svn.tiddlywiki.org/Trunk/contributors/FND/|
|''License''|[[Creative Commons Attribution-ShareAlike 3.0 License|http://creativecommons.org/licenses/by-sa/3.0/]]|
|''CoreVersion''|2.5.0|
!Revision History
!!v0.2 (2008-10-23)
* initial release
!!v0.3 (2008-11-03)
* major refactoring
!To Do
* parsing of replies, DMs etc.
* document custom/optional context attributes (userID, userName, page, suppressUsers)
!Code
***/
//{{{
if(!version.extensions.TiddlyWebAdaptorPlugin) { //# ensure that the plugin is only installed once
version.extensions.TiddlyWebAdaptorPlugin = { installed: true };
 
config.adaptors.twitter = function() {};
 
(function(adaptor) { //# set up alias
 
adaptor.prototype = new AdaptorBase();
adaptor.serverType = "twitter";
adaptor.serverLabel = "Twitter";
adaptor.mimeType = "application/json";
adaptor.tweetTags = ["tweets"];
adaptor.userTags = ["users"];
 
adaptor.errorFunc = function(XMLHttpRequest, textStatus, errorThrown) {
	var message = this.errorMessage;
	displayMessage("There has been a wee problem..."+message+". Status: "+textStatus);
};
 
adaptor.prototype.getWorkspaceList = function(context, userParams, callback) {
	context = this.setContext(context, userParams, callback);
	context.workspaces = [
		{ title: "public" },
		{ title: "with_friends" }, // TODO: rename?
		{ title: "replies" },
		{ title: "direct_messages_in" },
		{ title: "direct_messages_out" },
		{ title: "friends" },
		{ title: "followers" },
		{ title: "users" },
		{ title: context.userName } // user timeline
	];
	if(context.callback) {
		context.status = true;
		window.setTimeout(function() { callback(context, context.userParams); }, 0);
	}
	return true;
};
 
adaptor.prototype.getTiddlerList = function(context, userParams, callback) {
	context = this.setContext(context, userParams, callback);
	var page = context.page || 0;
	var count = context.count || 20;
	switch(context.workspace) {
		case "public":
			var uriTemplate = "%0/statuses/public_timeline.json";
			var uri = uriTemplate.format([context.host]);
			break;
		case "with_friends":
			uriTemplate = "%0/statuses/friends_timeline.json?page=%1";
			uri = uriTemplate.format([context.host, page]);
			break;
		case "replies": // TODO: require special parsing
			uriTemplate = "%0/statuses/replies.json?page=%1";
			uri = uriTemplate.format([context.host, page]);
			break;
		case "direct_messages_in":
			uriTemplate = "%0/direct_messages.json?page=%1";
			uri = uriTemplate.format([context.host, page]);
			break;
		case "direct_messages_out":
			uriTemplate = "%0/direct_messages/sent.json?page=%1";
			uri = uriTemplate.format([context.host, page]);
			break;
		case "friends":
			if(context.userID) {
				uriTemplate = "%0/statuses/friends/%1.json?page=%2";
				uri = uriTemplate.format([context.host, context.userID, page]);
			} else {
				uriTemplate = "%0/statuses/friends.json?page=%2";
				uri = uriTemplate.format([context.host, page]);
			}
			break;
		case "followers":
			uriTemplate = "%0/statuses/followers.json?page=%1";
			uri = uriTemplate.format([context.host, page]);
			break;
		case "users":
			uriTemplate = "%0/users/show/%1.format";
			uri = uriTemplate.format([context.host, context.userID]);
			break;
		case "user_timeline":
		default: // user timeline
			if (context.userID) {
				uriTemplate = "%0/statuses/user_timeline/%1.json?page=%2&count=%3";
				uri = uriTemplate.format([context.host, context.userID, page, count]);
			} else {
				uriTemplate = "%0/statuses/user_timline.json?page=%1&count=%2";
				uri = uriTemplate.format([context.host, page, count]);
			}
			break;
	}
	/*var req = httpReq("GET", uri, adaptor.getTiddlerListCallback,
		context, null, null, { accept: adaptor.mimeType });*/
	jQuery.getJSONP = function(s) {
		console.log('getJSONP has been called in the Twitter adaptor');
	    s.dataType = 'jsonp';
	    jQuery.ajax(s);
	
	    var t = 0, cb = s.url.match(/callback=(\w+)/)[1], cbFn = window
	[cb];
	    var $script = jQuery('head script[src*='+cb+']');
	    if (!$script.length)
	        return; // same domain request
	
	    $script[0].onerror = function(e) {
	    	var text = $script;
	        //$script.remove();
	        jQuery.handleError(s, {}, "error", e);
	        clearTimeout(t);
	    };
	
	    if (!s.timeout)
	        return;
	
	    window[cb] = function(json) {
	        clearTimeout(t);
	        cbFn(json);
	        cbFn = null;
	    };
	
	    t = setTimeout(function() {
	        $script.remove();
	        jQuery.handleError(s, {}, "timeout");
	        if (cbFn)
	            window[cb] = function(){};
	    }, s.timeout);
	};
	var opt = {
		url: uri,
		dataType: 'jsonp',
		success: adaptor.getTiddlerListCallback,
		error: adaptor.errorFunc,
		context: context
	};
	jQuery.getJSONP(opt);
	/*
	var req = jQuery.ajax({
		url: uri,
		dataType: 'jsonp',
		success: adaptor.getTiddlerListCallback,
		error: adaptor.errorFunc,
		errorMessage: "Problem getting data from Twitter",
		context: context
	});
	return typeof req == "string" ? req : true;
	*/
};
 
adaptor.getTiddlerListCallback = function(data, textStatus) {
	var context = this.context;
	var tweets = data;
	context.tiddlers = [];
	var users = {};
	for(var i = 0; i < tweets.length; i++) {
		var tiddler = adaptor.parseTweet(tweets[i]);
		context.tiddlers.push(tiddler);
		if(!context.suppressUsers) { // retain user info
			var user = tweets[i].user;
			user.updated = adaptor.convertTimestamp(tweets[i].created_at);
			if(!(users[user.id] && user.updated > users[user.id].modified)) {
				users[user.id] = adaptor.parseUser(user);
				users[user.id].fields = {
					"server.type": adaptor.serverType,
					"server.host": AdaptorBase.minHostName(context.host),
					"server.workspace": "users"
				};
			}
		}
	}
	context.tweets = context.tiddlers.length;
	for(user in users) { // XXX: should be for each, but JSLint doesn't recognize that
		context.tiddlers.push(users[user]);
	}
	if(context.callback) {
		context.callback(context, context.userParams);
	}
};
 
adaptor.prototype.getTiddler = function(title, context, userParams, callback) {
	context = this.setContext(context, userParams, callback);
	context.title = title;
	var fields = {
		"server.type": adaptor.serverType,
		"server.host": AdaptorBase.minHostName(context.host),
		"server.workspace": context.workspace
	};
	// reuse previously-requested tiddlers
	if(context.tiddler) {
		context.tiddler.fields = merge(context.tiddler.fields, fields, true);
	}
	// do not re-request non-truncated tweets
	if(context.tiddler && (context.tiddler.fields.truncated === false || context.tiddler.fields["server.workspace"] == "users")) {
		context.status = true;
		var subcontext = merge({}, context);
		window.setTimeout(function() { callback(subcontext, context.userParams); }, 0);
		return true;
	}
	// request individual tweet
	if(!context.tiddler || context.tiddler.fields.truncated === undefined) { // truncated flag as indicator of actual tweet
		context.tiddler = new Tiddler(title);
		context.tiddler.modifier = context.workspace;
		context.tiddler.fields = fields;
	}
	var uriTemplate = "%0/statuses/show/%1.json";
	var uri = uriTemplate.format([context.host, title]);
	/*var req = httpReq("GET", uri, adaptor.getTiddlerCallback,
		context, null, null, { accept: adaptor.mimeType });*/
	var req = jQuery.ajax({
		url: uri,
		dataType: 'jsonp',
		success: adaptor.getTiddlerCallback,
		error: adaptor.errorFunc,
		errorMessage: "Problem getting data from Twitter",
		context: context
	});
	return typeof req == "string" ? req : true;
};
 
adaptor.getTiddlerCallback = function(data, textStatus) {
	var context = this.context;
	var tweet = data;
	var tiddler = adaptor.parseTweet(tweet);
	tiddler.fields = merge(context.tiddler.fields, tiddler.fields, true);
	context.tiddler = tiddler;
	if(context.callback) {
		if(context.tiddler.fields.truncated) {
			var subContext = merge({},context);
			subContext.tiddler = context.tiddler;
			if(window.location.protocol!=='file') {
				// do pass on truncated tweet to callback even though we can't request full tweet
				context.callback(context, context.userParams);
			} else {
				context.callback(context, context.userParams);
				context.adaptor.getFullTweet(subContext, context.userParams, context.callback);
			}
		} else {
			context.callback(context, context.userParams);
		}
	}
};
 
// re-request truncated tweet - need to be offline for this
adaptor.prototype.getFullTweet = function(context, userParams, callback) {
	context = this.setContext(context, userParams, callback);
	var uriTemplate = "%0/%1/status/%2";
	var uri = uriTemplate.format([context.host, context.userID, context.tiddler.title]);
	var req = httpReq("GET", uri, adaptor.getFullTweetCallback, context);
	return typeof req == "string" ? req : true;
};
 
adaptor.getFullTweetCallback = function(status, context, responseText, uri, xhr) {
	context.status = status;
	context.statusText = xhr.statusText;
	context.httpStatus = xhr.status;
	if(status) {
		context.tiddler.text = adaptor.scrapeTweet(responseText);
	}
	if(context.callback) {
		context.callback(context, context.userParams);
	}
};
 
// convert tweet to tiddler object
adaptor.parseTweet = function(tweet) {
	var tiddler = new Tiddler(tweet.id.toString());
	tiddler.created = adaptor.convertTimestamp(tweet.created_at);
	tiddler.modified = tiddler.created;
	tiddler.modifier = tweet.user.id.toString();
	tiddler.tags = adaptor.tweetTags;
	tiddler.fields = {
		source: tweet.source, // TODO: split into appName and appURI
		truncated: tweet.truncated,
		favorited: tweet.favorited,
		context: tweet.in_reply_to_status_id,
		user: tweet.user.id,
		username: tweet.user.name, // XXX: obsolete due to separate user info?
		usernick: tweet.user.screen_name // TODO: rename --  XXX: obsolete due to separate user info?
	};
	tiddler.text = adaptor.decodeHTMLEntities(tweet.text);
	return tiddler;
};
 
// convert user to tiddler object
adaptor.parseUser = function(user) {
	var tiddler = new Tiddler(user.id.toString());
	tiddler.created = user.updated; // XXX: not quite correct (updated vs. created)
	tiddler.modified = tiddler.created;
	tiddler.modifier = user.id.toString();
	tiddler.tags = adaptor.userTags;
	var slice = "|''%0''|%1|\n";
	tiddler.text = slice.format(["ID", user.id]) +
		slice.format(["ScreenName", user.screen_name]) +
		slice.format(["FullName", user.name]) +
		slice.format(["URL", user.url]) +
		slice.format(["Icon", user.profile_image_url]) +
		slice.format(["Bio", user.description]) +
		slice.format(["Location", user.location]) +
		slice.format(["Followers", user.followers_count]) +
		slice.format(["Protected", user.protected]);
	return tiddler;
};
 
// retrieve untruncated tweet (cf. http://code.google.com/p/twitter-api/issues/detail?id=133)
adaptor.scrapeTweet = function(html) {
	// load HTML page
	var ifrm = document.createElement("iframe");
	ifrm.style.display = "none";
	document.body.appendChild(ifrm);
	var doc = ifrm.document;
	if(ifrm.contentDocument) { // NS6
		doc = ifrm.contentDocument;
	} else if(ifrm.contentWindow) { // IE
		doc = ifrm.contentWindow.document;
	}
	doc.open();
	doc.writeln(html);
	doc.close();
	// retrieve status message
	var container = doc.getElementById("permalink");
	var spans = container.getElementsByTagName("span");
	for(i = 0; i < spans.length; i++) {
		if(spans[i].className == "entry-content") {
			var tweet = spans[i];
			var text = tweet.text || tweet.textContent; // strip descendants' markup -- XXX: cross-browser compatible?
			break;
		}
	}
	removeNode(ifrm);
	return adaptor.decodeHTMLEntities(text.trim());
};
 
// convert timestamp ("mmm 0DD 0hh:0mm:0ss +0000 YYYY") to Date instance
adaptor.convertTimestamp = function(str) {
	var c = str.match(/(\w+) (\d+) (\d+):(\d+):(\d+) \+\d+ (\d+)/);
	return new Date(c[6], adaptor.convertShortMonth(c[1]),
		c[2], c[3], c[4], c[5]);
};
 
// convert short-month string (mmm) to month number (zero-based)
adaptor.convertShortMonth = function(text) {
	for(var i = 0; i < config.messages.dates.shortMonths.length; i++) { // XXX: inefficient!?
		if(text == config.messages.dates.shortMonths[i]) {
			return i;
		}
	}
};
 
// convert HTML entities to the respective characters
adaptor.decodeHTMLEntities = function(str) {
	var el = document.createElement("textarea");
	el.innerHTML = str;
	return el.value;
};
 
})(config.adaptors.twitter); //# end of alias
 
} //# end of "install only once"
//}}}
/***
|''Name''|TwitterWizardPlugin|
|''Description''|interface for retrieving tweets and user data from Twitter|
|''Author''|FND, JonathanLister|
|''Version''|0.2.0|
|''Status''|@@experimental@@|
|''Requires''|TwitterAdaptorPlugin|
|''Source''|http://devpad.tiddlyspot.com/#TwitterArchivePlugin|
|''CodeRepository''|http://svn.tiddlywiki.org/Trunk/contributors/FND/|
|''License''|[[Creative Commons Attribution-ShareAlike 3.0 License|http://creativecommons.org/licenses/by-sa/3.0/]]|
|''CoreVersion''|2.5.0|
!Usage
{{{
<<TiddlyTweets [workspace] [pages]>>
}}}
{{{
<<TwitterWizard>>
}}}
!Revision History
!!v0.2 (2009-03-04)
* jsonp
* made it work
!!v0.1 (2008-11-14)
* initial release
!To Do
* documentation
* abort conditions: empty response or tweet already archived
* report when retrieval has been completed
* disable wiki markup for tweets
!Code
***/
//{{{
if(!version.extensions.TwitterWizardPlugin) { //# ensure that the plugin is only installed once
version.extensions.TwitterWizardPlugin = { installed: true };
 
if(!config.adaptors.twitter) {
	throw "Missing dependency: TwitterAdaptor";
}
 
config.macros.TiddlyTweets = {
	btnLabel: "TiddlyTweets",
	btnTooltip: "retrieve tweets",
	usernamePrompt: "enter Twitter username",
 
	host: "http://www.twitter.com",
	requestDelay: 1000, // delay between page requests
	adaptor: new config.adaptors.twitter(),
 
	handler: function(place, macroName, params, wikifier, paramString, tiddler) {
		this.pageCount = 0; // XXX: means there can only be a single instance!!
		createTiddlyButton(place, this.btnLabel, this.btnTooltip,
			function() { config.macros.TiddlyTweets.dispatcher(params); });
	},
 
	dispatcher: function(params) { // TODO: rename
		var self = config.macros.TiddlyTweets;
		var maxPages = params[1] || 1;
		self.maxPages = maxPages;
		var count = params[2];
		if(self.pageCount <= maxPages) {
			var username = params[0] || prompt(self.usernamePrompt);
			setTimeout(function() { self.dispatcher(params); },
				self.requestDelay);
			self.launcher(username, self.pageCount, count);
			self.pageCount++;
		} else {
			self.pageCount = 1;
		}
	},
 
	launcher: function(username, page, count) { // TODO: rename
		var self = config.macros.TiddlyTweets;
		var context = {
			host: self.host,
			workspace: "user_timeline",
			userID: username,
			page: page,
			count: count
		};
		self.adaptor.getTiddlerList(context, null, self.processor);
		/*
		var status = self.adaptor.getTiddlerList(context, null, self.processor);
		if(status !== true) {
			displayMessage("error retrieving page " + context.page); // TODO: i18n
		}
		*/
	},
 
	processor: function(context, userParams) { // TODO: rename
		var self = config.macros.TiddlyTweets;
		self.doneRequestCount++;
		self.totalReturnedTiddlers += context.tweets;
		if(self.doneRequestCount === self.maxPages) {
			displayMessage('all the page requests have returned and been processed!');
			if(self.totalReturnedTiddlers!==self.tweetCount) {
				var difference = self.tweetCount - self.totalReturnedTiddlers;
				displayMessage('total tweets doesn\'t match predicted number, there are '+difference+' missing tweets');
			} else {
				displayMessage('all expected tweets returned');
			}
		}
		for(var i = 0; i < context.tweets; i++) {
			context.tiddler = context.tiddlers[i];
			self.adaptor.getTiddler(context.tiddler.title, context, null, self.saver);
		}
	},
 
	saver: function(context, userParams) { // TODO: rename
		var self = config.macros.TiddlyTweets;
		var tiddler = context.tiddler;
		store.saveTiddler(tiddler.title, tiddler.title, tiddler.text,
			tiddler.modifier, tiddler.modified, tiddler.tags,
			tiddler.fields, false, tiddler.created);
		self.savedTweets++;
		self.progressBar.style.width = (self.savedTweets / self.tweetCount)*100 +'%';
		console.log(self.progressBar.style.width);
		if(self.savedTweets === self.tweetCount) {
			displayMessage('saved all tweets! finished!');
		}
	},
 
	// this function could probably move out to the TwitterBackWizard macro
	// then TiddlyTweets macro should have some instantiation with params like pageCount and launchCount
	handleWizard: function(w) {
		var self = config.macros.TiddlyTweets;
		self.pageCount = 1;
		self.doneRequestCount = 0;
		self.totalReturnedTiddlers = 0;
		self.savedTweets = 0;
		self.tweetCount = w.tweetCount;
		var params = [
			w.username,
			w.maxPages,
			200
		];
		w.addStep("Downloading","<span class='progress'></span>");
		var stepElem = w.bodyElem.getElementsByTagName('div')[1];
		stepElem.style.padding = 0;
		stepElem.style.paddingBottom = "2em";
		w.setButtons([{
			caption: "Search these tweets",
			tooltip: "Search these tweets",
			onClick: function() {
				story.displayTiddler("bottom","TweetTrawler");
				return false;
			}
		},
		{
			caption: "Save To CSV",
			tooltip: "Save to CSV",
			onClick: function() {
				TiddlyTemplating.templateAndPublish(w.username+'.csv','CsvTemplate');
				return false;
			}
		},
		{
			caption: "Do it again!",
			tooltip: "Start again",
			onClick: function() {
				var w = new Wizard(this);
				var place = w.clear();
				config.macros.TwitterBackupWizard.restart(w);
				return false;
			}
		}]);
		self.progressBar = w.bodyElem.getElementsByTagName('span')[0];
		self.dispatcher(params);
	}
};
 
jQuery.getJSONP = function(s) {
	console.log('getJSONP has been called in the Twitter Archiver wizard');
    s.dataType = 'jsonp';
    jQuery.ajax(s);
 
    var t = 0, cb = s.url.match(/callback=(\w+)/)[1], cbFn = window
[cb];
    var $script = jQuery('head script[src*='+cb+']');
    if (!$script.length)
        return; // same domain request
 
    $script[0].onerror = function(e) {
    	var text = $script;
        //$script.remove();
        jQuery.handleError(s, {}, "error", e);
        clearTimeout(t);
    };
 
    if (!s.timeout)
        return;
 
    window[cb] = function(json) {
        clearTimeout(t);
        cbFn(json);
        cbFn = null;
    };
 
    t = setTimeout(function() {
        $script.remove();
        jQuery.handleError(s, {}, "timeout");
        if (cbFn)
            window[cb] = function(){};
    }, s.timeout);
};
 
// like the more ambitious TwitterWizard below, but only for your tweets
// includes a step to check how many tweets you have and work out maxPages from that
config.macros.TwitterBackupWizard = {
	handler: function(place, macroName, params, wikifier, paramString, tiddler, errorMsg) {
		var w = new Wizard();
		w.createWizard(place, "Twitter Backup Wizard");
		this.restart(w);
	},
	
	restart: function(w) {
		var self = config.macros.TwitterBackupWizard;
		var onClick = function() {
			w.username = w.getValue('username').value;
			self.step2(w);
			return false;
		};
		w.addStep("Type in your Twitter username please", "<input name='username'>");
		w.formElem.onsubmit = onClick;
		w.setButtons([{
			caption: "Let's go",
			tooltip: "First thing, click to count your tweets",
			onClick: onClick
		}]);
	},
 
	handleProfilePageToCountUpdates: function(person, textStatus) {
		var tweetCount = person.statuses_count;
		var w = this.wizard;
		config.macros.TwitterBackupWizard.step3(w, tweetCount);
	},
 
	step2: function(w) {
		w.addStep("Hello " + w.username + ", counting your tweets", "<span>hold your horses!</span>");
		w.setButtons([]);
		var self = config.macros.TwitterBackupWizard;
		var host = "http://www.twitter.com";
		var url = host + "/users/show/" + w.username + ".json";
		var context = {
			wizard: w
		};
		//var req = httpReq("GET", url, self.handleProfilePageToCountUpdates, context);
		try {
		var opt = {
			url: url,
			//url: 'http://jquery.com/Test.php',
			dataType: 'jsonp',
			success: self.handleProfilePageToCountUpdates,
			error: self.errorFunc,
			wizard: w
		};
		jQuery.getJSONP(opt);
		} catch(e) {
			console.log(e,e.message);
		}
	},
 
	step3: function(w, tweetCount) {
		var step3html = "";
		if(tweetCount > 3200) {
			step3html += "we need the Power of Greyskull to get back further than that! Let's do what we can...<p /><img src='http://www.dvdplaza.fi/reviews/images/heman46_000.jpg' title='image from http://www.dvdplaza.fi/' />";
			w.addStep("oh noes "+w.username+"!, you've got "+tweetCount+" tweets and I can only get the first 3200 tweets", step3html);
			tweetCount = 3200;
		} else {
			step3html = "This might take a moment...";
			w.addStep(w.username+", you've got " + tweetCount + " tweets!", step3html);
		}
		w.tweetCount = tweetCount;
		w.maxPages = Math.ceil(parseInt(tweetCount, 10) / 200);
		w.setButtons([{
			caption: "Download tweets",
			tooltip: "Download " + tweetCount + " tweets",
			onClick: function() { config.macros.TiddlyTweets.handleWizard(w); }
		},
		{
			caption: "Go back",
			tooltip: "Oops! Wrong username, take me back",
			onClick: function() {
				var w = new Wizard(this);
				var place = w.clear();
				config.macros.TwitterBackupWizard.restart(w);
				return false;
			}
		}]);
	},
	
	errorFunc: function(XMLHttpRequest, textStatus, errorThrown) {
		var w = this.wizard;
		var addResetButton = function(wizard) {
			wizard.setButtons([{
				caption: "Start again!",
				tooltip: "Start again!",
				onClick: function() {
					var w = new Wizard(wizard.formElem);
					var place = w.clear();
					config.macros.TwitterBackupWizard.restart(w);
					return false;
				}
			}]);
		};
		if(!self.apiLimitChecked) {
			w.addStep("Ah. There has been a wee problem... maybe we're hammering Twitter too much", "checking your API rate limit...");
			var twitterAPICheckerCallback = function(limitObj) {
				self.apiLimitChecked = false; // ensure future errors trigger limit check again
				var limit = limitObj.hourly_limit;
				var remaining = limitObj.remaining_hits;
				var w = this.wizard;
				var errorHTML = "";
				if(remaining > 0) {
					errorHTML = "you have "+remaining+" calls left from an hourly limit of "+limit+"<p/>best check the twitter account exists: <a href='http://twitter.com/"+w.username+"' target='_blank'>"+w.username+"</a>";
				} else {
					var resetTime = limitObj.reset_time_in_seconds*1000 - new Date().getTime();
					resetTime = new Date().getTime() + resetTime;
					resetTime = new Date(resetTime);
					errorHTML = "you've run out of calls to the API; wait a while and try again<p/>your limit will reset in less than "+resetTime.getMinutes()+" minutes";
				}
				w.addStep("Checked your rate limit",errorHTML);
				addResetButton(w);
			};
			var opt = {
				url: "http://twitter.com/account/rate_limit_status.json",
				dataType: 'jsonp',
				success: twitterAPICheckerCallback,
				error: arguments.callee,
				wizard: w
			};
			self.apiLimitChecked = true;
			jQuery.getJSONP(opt);
		} else {
			self.apiLimitChecked = false; // ensure future errors trigger limit check again
						w.addStep("Error checking rate limit","maybe Twitter is down?<br/><a href='http://istwitterdown.com' target='_blank'>istwitterdown.com</a>");
			addResetButton(w);
		}
	}
};
 
/*** past here, code is not used in Twitter Archiver ***/
 
// Twitter archiving wizard -- XXX: experimental, incomplete -- TODO: i18n
config.macros.TwitterWizard = {
	handler: function(place, macroName, params, wikifier, paramString, tiddler, errorMsg) {
		var w = new Wizard();
		w.createWizard(place, "Twitter Wizard");
		w.addStep("Twitter username", "<input name='username'>");
		w.setButtons([{
			caption: "Import",
			tooltip: "click to import",
			onClick: function() { config.macros.twitter.step1(w); }
		}]);
	},
 
	step1: function(w) {
		var step1Html = "<input name='my_tweets' type='checkbox' /><label>My Tweets</label><br />" +
			"<input name='contacts' type='checkbox' /><label>My Contacts</label><br />" +
			"<input name='contacts_tweets' type='checkbox' /><label>My Contacts Tweets</label><br />";
		w.addStep("account :" + w.formElem.twitter_id.value, step1Html);
		w.setButtons([{
			caption: "Import 2",
			tooltip: "click to import",
			onClick: function() { config.macros.twitter.step2(w); }
		}]);
	},
 
	step2: function(w) {
		w.addStep("enter password for " + w.formElem.twitter_id.value,
			"<input name='twitter_password' type='password'/>");
		w.setButtons([{
			caption: "Import",
			tooltip: "click to import",
			onClick: function() { config.macros.TwitterWizard.step3(w); }
		}]);
	},
 
	step3: function(w) {
		var html = w.formElem.twitter_id.value + "<br />" +
			w.formElem.my_tweets + "<br />" +
			w.formElem.twitter_password.value + "<br />";
		w.addStep("All Done", html);
	}
};
 
} //# end of "install only once"
//}}}
/***
|''Name:''|TemplatePlugin |
|''Description:''|Collection of functions to support rendering of tiddlers through HTML templates |
|''Author:''|JonathanLister |
|''CodeRepository:''|http://svn.tiddlywiki.org/Trunk/contributors/JonathanLister/plugins/TemplatePlugin.js |
|''Version:''|0.0.5 |
|''Date:''|3/3/08 |
|''Comments:''|Please make comments at http://groups.google.co.uk/group/TiddlyWikiDev |
|''License:''|[[BSD License|http://www.opensource.org/licenses/bsd-license.php]] |
|''~CoreVersion:''|2.3|
 
The templateTiddlers macro finds a set of tiddlers and renders them once each through a template. The template can contain additional
calls to the macro to allow for e.g. looping inside a template (think RSS items). It needs to be able to support recursion, so that sub-templates make sense.
 
Usage:
{{{
<<templateTiddlers template:RssTemplate filter:"[tag[!excludeLists]]" [wikitext:true]>>
<<templateTiddlers RssTemplate filter:"[tag[!excludeLists]]">> // template qualification is optional
}}}
 
Parameters can be:
template - the name of the template
filter - a tiddler filter
wikitext - if true, renders the target tiddler's text as wikitext instead of using the special template formatter
raw - if true, adds the HTML to place without encoding it as text
 
If a parameter does not have a qualifier, it is assumed to be the template name
 
|''Name:''|templateTagsMacro |
|''Description:''|Renders a tiddler's tags through a template |
 
Usage:
{{{
<<templateTags template:RssItemCategoryTemplate>>
<<templateTiddlers RssTemplate>> // template qualification is optional
}}}
 
Parameters can be:
template - the name of the template
 
The templateTags macro renders a tiddler's tags through a template in an analagous way to how templateTiddlers renders a set of tiddlers. Future development might offer support for other data items other than tags, but this is what is needed for RSS, the use-case driving the development.
 
|''Name:''|PermalinkMacro |
|''Description:''|Creates a permalink to the tiddler |
 
Usage:
{{{
<<permalink>>
}}}
***/
 
//{{{
if(!version.extensions.templatePlugin) {
version.extensions.templatePlugin = {installed:true};
 
expandTemplate = function(template,tiddlers,wikitext)
{
	var defaultTemplate = "<<view text>>";
	var t = template;
	template = template ? store.getTiddlerText(template,template) : defaultTemplate;
	if(!tiddlers) {
		// no tiddlers provided, so create a temporary tiddler
		tiddlers = [];
		tiddlers.push(new Tiddler("temp"));
	}
	var output = "";
	// decide whether to parse as wikitext or simple template
	var format = wikitext ? null : 'template';
	for(var i=0; i<tiddlers.length; i++) {
		output += wikifyStatic(template,null,tiddlers[i],format).htmlDecode();
	}
	return output;
};
 
config.macros.templateTiddlers = {};
config.macros.templateTiddlers.handler = function(place,macroName,params,wikifier,paramString,tiddler)
{
	p = paramString.parseParams("anon",null,true,false,false);
	var template = getParam(p,"template",null);
	if(!template)
		template = getParam(p,"anon",null);
	var filter = getParam(p,"filter",null);
	var wikitext = getParam(p,"wikitext",null);
	var raw = getParam(p,"raw",false);
	var tiddlers = [];
	if(filter) {
		tiddlers = store.filterTiddlers(filter);
	} else {
		// no filter provided, so inherit or create temp tiddler
		tiddlers.push(tiddler ? tiddler : new Tiddler("temp"));
	}
	var output = expandTemplate(template,tiddlers,wikitext);
	/* I'm not sure this 'raw' thing is actually useful... if you don't do the htmlEncode before adding the output to the innerHTML, nested template content could be broken by the htmlDecode in expandTemplate. I think I've used the 'raw' control before to style a tiddler, but maybe this can still be done without using this method. It's probably safe if used right at the top-level of templating... */
	place.innerHTML += raw ? output : output.htmlEncode();
	if(raw) {
		/* Gotta refresh the tiddlerlinks! The wikifyStatic just plops a line of HTML in - the onclick is attached to different element */
	}
};
 
config.macros.templateTags = {};
config.macros.templateTags.handler = function(place,macroName,params,wikifier,paramString,tiddler)
{
	p = paramString.parseParams("anon",null,true,false,false);
	var template = getParam(p,"template",null);
	var tiddlers = [];
	if(!template)
		template = getParam(p,"anon",null);
	for(var i=0;i<tiddler.tags.length;i++) {
		var t = new Tiddler(tiddler.title);
		t.tags = [tiddler.tags[i]];
		tiddlers.push(t);
	}
	var output = expandTemplate(template,tiddlers);
	place.innerHTML += output;
};
 
} //# end of 'install only once'
//}}}
/***
|''Name:''|TemplatingMacrosPlugin |
|''Description:''|Some macros used in TiddlyTemplating templates |
|''Author:''|JonathanLister |
|''CodeRepository:''|http://svn.tiddlywiki.org/Trunk/contributors/JonathanLister/plugins/TemplatingMacrosPlugin.js |
|''Version:''|0.0.1 |
|''Date:''|25/3/08 |
|''Comments:''|Please make comments at http://groups.google.co.uk/group/TiddlyWikiDev |
|''License:''|[[BSD License|http://www.opensource.org/licenses/bsd-license.php]] |
|''~CoreVersion:''|2.3|
 
!permalink macro
 
Creates a link to a view of the TiddlyWiki with only the enclosing tiddler opened
 
Usage:
{{{
<<permalink>>
}}}
 
!view macro - slice view
 
Allows access to a slice contained within a tiddler
 
Usage:
{{{
<<view text slice MySlice>>
 
will extract this slice:
 
|mySlice | slice content |
}}}
 
!view macro - section view
 
Provides access to a section contained within a tiddler
 
Usage:
{{{
<<view text section mySection>>
 
will extract this section:
 
!mySection
blah blah
!end of mySection
 
}}}
 
***/
 
//{{{
if(!version.extensions.templatingMacrosPlugin) {
version.extensions.templatingMacrosPlugin = {installed:true};
 
config.macros.permalink = {};
config.macros.permalink.handler = function(place,macroName,params,wikifier,paramString,tiddler)
{
	var t = encodeURIComponent(String.encodeTiddlyLink(tiddler.title));
	createTiddlyText(place,window.location+"#"+t);
};
 
config.macros.view.views.slice = function(value,place,params,wikifier,paramString,tiddler) {
	var slice = "";
	if(params && params[2]) {
		slice = store.getTiddlerSlice(tiddler.title,params[2]);
		if(slice) {
			createTiddlyText(place,slice);
		}
	}
};
 
config.macros.view.views.section = function(value,place,params,wikifier,paramString,tiddler) {
	var section = "";
	if(params && params[2]) {
		section = store.getTiddlerText(tiddler.title+"##"+params[2]);
		if(section) {
			createTiddlyText(place,section);
		}
	}
};
 
} //# end of 'install only once'
//}}}
/***
 
|''Name:''|TiddlyTemplatingMacro |
|''Description:''|Renders a template and saves the output to a local file |
|''Author:''|JonathanLister|
|''CodeRepository:''|http://svn.tiddlywiki.org/Trunk/contributors/JonathanLister/plugins/TiddlyTemplatingMacro.js |
|''Version:''|3 |
|''Date:''|25/3/08 |
|''Comments:''|Please make comments at http://groups.google.co.uk/group/TiddlyWikiDev |
|''License:''|[[BSD License|http://www.opensource.org/licenses/bsd-license.php]] |
|''~CoreVersion:''|2.3 |
 
Usage:
{{{
<<TiddlyTemplating template|template:tiddlerName [filter:filterString] [wikitext:true] [filename:filename]>>
}}}
 
Description:
Provides a button labelled "Publish" that triggers the templating and saving processes
 
***/
 
//{{{
if(!version.extensions.TiddlyTemplating) {
version.extensions.TiddlyTemplating = {installed:true};
 
var TiddlyTemplating = {
	defaultFileName:"output.txt"
};
 
config.macros.TiddlyTemplating = {};
 
config.macros.TiddlyTemplating.handler = function(place,macroName,params,wikifier,paramString,tiddler)
{
	var button = createTiddlyButton(place,"Publish","Publish",config.macros.TiddlyTemplating.onclick);
	button.params = params;
	button.paramString = paramString;
};
 
config.macros.TiddlyTemplating.onclick = function(e)
{
	console.log(TiddlyTemplating);
	var p = this.paramString.parseParams("anon",null,true,false,false);
	var filename = TiddlyTemplating.getFileName(p);
	var template = TiddlyTemplating.getTemplate(p);
	var tiddlers = TiddlyTemplating.getTiddlers(p);
	var wikitext = getParam(p,"wikitext",null);
	displayMessage("generating...");
	TiddlyTemplating.templateAndPublish(filename,template,tiddlers,wikitext);
};
 
TiddlyTemplating.getFileName = function(p)
{
	console.log(p);
	var filename = getParam(p,"fileName");
	if(!filename) {
		filename = this.defaultFileName;
	}
	return filename;
};
 
TiddlyTemplating.getTemplate = function(p)
{
	var template = getParam(p,"template",null);
	if(!template) {
		template = getParam(p,"anon",null);
	}
	return template;
};
 
TiddlyTemplating.getTiddlers = function(p)
{
	var filter = getParam(p,"filter",null);
	var tiddlers = [];
	if(filter) {
		tiddlers = store.filterTiddlers(filter);
	} else {
		// no filter provided, so inherit or create temp tiddler
		tiddlers.push(tiddler ? tiddler : new Tiddler("temp"));
	}
	return tiddlers;
};
 
TiddlyTemplating.templateAndPublish = function(filename,template,tiddlers,isWikitext)
{
	var content = expandTemplate(template,tiddlers,isWikitext);
	if(window.location.protocol === 'file:') {
		this.saveToFile(filename,content);
	} else {
		this.saveToWindow(filename,content);
	}
};
 
TiddlyTemplating.saveToFile = function(filename,content)
{
	config.messages.fileSaved = "file successfully saved";
	config.messages.fileFailed = "file save failed";
	var localPath = getLocalPath(document.location.toString());
	var savePath;
	if((p = localPath.lastIndexOf("/")) != -1) {
		savePath = localPath.substr(0,p) + "/" + filename;
	} else {
		if((p = localPath.lastIndexOf("\\")) != -1) {
			savePath = localPath.substr(0,p) + "\\" + filename;
		} else {
			savePath = localPath + "." + filename;
		}
	}
	displayMessage("saving...");
	var fileSave = saveFile(savePath,convertUnicodeToUTF8(content));
	if(fileSave) {
		displayMessage("saved... click here to load","file://"+savePath);
	} else {
		alert(config.messages.fileFailed,"file://"+savePath);
	}
};
 
TiddlyTemplating.saveToWindow = function(name,content)
{
	var newwindow = window.open(null,name);
	var doc = newwindow.document;
	if(doc.contentDocument) { // NS6
		doc = newwindow.contentDocument;
	} else if(newwindow.contentWindow) { // IE
		doc = newwindow.contentWindow.document;
	}
	doc.open();
	doc.write("<html><head></head><body><textarea id='source' rows='20' cols='80'>(source code goes here)</textarea></body></html>");
	doc.close();
	var theTextBox = doc.getElementById("source");
	theTextBox.value = content;
	theTextBox.focus();
	theTextBox.select();
};
 
} //# end of 'install only once'
//}}}
/***
|''Name:''|ToggleThemePlugin|
|''Description:''|Switches between two themes|
|''Author:''|Jonathan Lister (jnthnlstr (at) googlemail (dot) com)|
|''~CodeRepository:''|http://svn.tiddlywiki.org/Trunk/contributors/JonathanLister/verticals/FNDTiddlyTweets/plugins/ToggleThemePlugin.js |
|''Version:''|0.1|
|''Date:''|Mar 4, 2009|
|''Comments:''|Please make comments at http://groups.google.co.uk/group/TiddlyWikiDev |
|''License:''|[[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]] |
|''~CoreVersion:''|2.4|
 
!!Description
This plugin defines a theme selector button that allows you to select a theme from a list of tiddlers tagged with "systemTheme".
 
!!Usage
Include
{{{<<selectTheme>>}}}
in any tiddler to create a select theme button.
 
***/
 
//{{{
if(!version.extensions.ToggleThemePlugin) {
version.extensions.ToggleThemePlugin = {installed:true};
 
config.macros.toggleTheme = {
 
	label: "switch theme",
	prompt: "Switch the theme from %0 to %1",
 
	getNewTheme: function(theme1,theme2) {
		var currentTheme = config.options.txtTheme;
		var newTheme = currentTheme === theme1 ? theme2 : theme1;
		return newTheme;
	},
	
	handler: function(place,macroName,params,wikfier,paramString,tiddler) {
		var theme1 = params[0];
		var theme2 = params[1];
		if(!(theme1 && theme2)) {
			throw "Error in toggleTheme: please provide two themes as parameters";
		}
		var newTheme  = this.getNewTheme(theme1,theme2);
		var plugin = this;
		var onClick = function() {
			var newTheme = plugin.getNewTheme(theme1,theme2);
			// switchTheme triggers this handler before changing config.options.txtTheme
			config.options.txtTheme = newTheme;
			story.switchTheme(newTheme);
		};
		var btn = createTiddlyButton(place,this.label,this.prompt.format([config.options.txtTheme,newTheme]),onClick);
	}
};
 
} //# end of 'install only once'
//}}}
<item>
	<title><!--<<view title>>--></title>
	<description><![CDATA[<!--<<view text>>-->]]></description>
	<!--<<templateTags RssItemCategoryTemplate>>-->
	<link><!--<<permalink>>--></link>
	<pubDate><!--<<view modified date>>--></pubDate>
</item>
<category><!--<<view tags>>--></category>
/***
|''Name:''|TemplateFormatterPlugin|
|''Author:''|Martin Budden ( mjbudden [at] gmail [dot] com)|
|''Description:''|Plug to demonstrate template formatter|
|''CodeRepository:''|http://svn.tiddlywiki.org/Trunk/contributors/MartinBudden/experimental/TemplateFormatterPlugin.js |
|''Version:''|0.0.3|
|''Date:''|Mar 19, 2008|
|''Comments:''|Please make comments at http://groups.google.co.uk/group/TiddlyWikiDev |
|''License:''|[[Creative Commons Attribution-ShareAlike 3.0 License|http://creativecommons.org/licenses/by-sa/3.0/]] |
|''~CoreVersion:''|2.3.0|
 
!!Description
Provides a formatter that can be used to expand templates
 
!!Usage
Then include this plugin and tag it systemConfig in the normal way. Templates can include:
{{{
<!--<<macroname macroparameters>>--> : macro that is expanded into the template
<!--comment--> : comment that is included in the output
<!--@@comment@@-->> : comment that is not included in the output (can be used to document the template itself)
}}}
 
***/
 
//{{{
if(!version.extensions.TemplateFormatterPlugin) {
version.extensions.TemplateFormatterPlugin = {installed:true};
 
config.templateFormatters = [
{
	name: 'templateElement',
	match: '<!--(?:<<|@@)',
	lookaheadRegExp: /<!--<<([^>\s]+)(?:\s*)((?:[^>]|(?:>(?!>)))*)>>-->|<!--@@([^@]*)@@-->/mg,
	handler: function(w)
	{
		this.lookaheadRegExp.lastIndex = w.matchStart;
		var lookaheadMatch = this.lookaheadRegExp.exec(w.source);
		if(lookaheadMatch && lookaheadMatch.index == w.matchStart) {
			w.nextMatch = this.lookaheadRegExp.lastIndex;
			if(lookaheadMatch[1]) {
				invokeMacro(w.output,lookaheadMatch[1],lookaheadMatch[2],w,w.tiddler);
			}
		}
	}
}
];
 
config.parsers.templateFormatter = new Formatter(config.templateFormatters);
config.parsers.templateFormatter.format = 'template';
config.parsers.templateFormatter.formatTag = 'TemplateFormat';
} //# end of 'install only once'
//}}}
/***
|''Name:''|YourSearchPlugin|
|''Version:''|2.1.0 (2006-10-12)|
|''Source:''|http://tiddlywiki.abego-software.de/#YourSearchPlugin ([[del.icio.us|http://del.icio.us/post?url=http://tiddlywiki.abego-software.de/index.html%23YourSearchPlugin]])|
|''Author:''|UdoBorkowski (ub [at] abego-software [dot] de)|
|''Licence:''|[[BSD open source license (abego Software)|http://www.abego-software.de/legal/apl-v10.html]]|
|''Copyright:''|&copy; 2005-2006 [[abego Software|http://www.abego-software.de]]|
|''~CoreVersion:''|2.1.0|
|''Browser:''|Firefox 1.0.4+; Firefox 1.5; ~InternetExplorer 6.0|
!About YourSearch
YourSearch gives you a bunch of new features to simplify and speed up your daily searches in TiddlyWiki. It seamlessly integrates into the standard TiddlyWiki search: just start typing into the 'search' field and explore!
 
For more information see [[Help|YourSearch Help]].
!Compatibility
This plugin requires TiddlyWiki 2.1. 
Check the [[archive|http://tiddlywiki.abego-software.de/archive]] for ~YourSearchPlugins supporting older versions of TiddlyWiki.
!Source Code
***/
/***
This plugin's source code is compressed (and hidden). Use this [[link|http://tiddlywiki.abego-software.de/archive/YourSearchPlugin/Plugin-YourSearch-src.2.1.0.js]] to get the readable source code.
***/
///%
if(!version.extensions.YourSearchPlugin){version.extensions.YourSearchPlugin={major:2,minor:1,revision:0,source:"http://tiddlywiki.abego-software.de/#YourSearchPlugin",licence:"[[BSD open source license (abego Software)|http://www.abego-software.de/legal/apl-v10.html]]",copyright:"Copyright (c) abego Software GmbH, 2005-2006 (www.abego-software.de)"};if(!window.abego){window.abego={};}if(!Array.forEach){Array.forEach=function(_1,_2,_3){for(var i=0,len=_1.length;i<len;i++){_2.call(_3,_1[i],i,_1);}};Array.prototype.forEach=function(_5,_6){for(var i=0,len=this.length;i<len;i++){_5.call(_6,this[i],i,this);}};}abego.toInt=function(s,_9){if(!s){return _9;}var n=parseInt(s);return (n==NaN)?_9:n;};abego.createEllipsis=function(_b){var e=createTiddlyElement(_b,"span");e.innerHTML="&hellip;";};abego.shallowCopy=function(_d){if(!_d){return _d;}var _e={};for(var n in _d){_e[n]=_d[n];}return _e;};abego.copyOptions=function(_10){return !_10?{}:abego.shallowCopy(_10);};abego.countStrings=function(_11,s){if(!s){return 0;}var len=s.length;var n=0;var _15=0;while(1){var i=_11.indexOf(s,_15);if(i<0){return n;}n++;_15=i+len;}return n;};abego.getBracedText=function(_17,_18,_19){if(!_18){_18=0;}var re=/\{([^\}]*)\}/gm;re.lastIndex=_18;var m=re.exec(_17);if(m){var s=m[1];var _1d=abego.countStrings(s,"{");if(!_1d){if(_19){_19.lastIndex=re.lastIndex;}return s;}var len=_17.length;for(var i=re.lastIndex;i<len&&_1d;i++){var c=_17.charAt(i);if(c=="{"){_1d++;}else{if(c=="}"){_1d--;}}}if(!_1d){if(_19){_19.lastIndex=i-1;}return _17.substring(m.index+1,i-1);}}};abego.select=function(_21,_22,_23,_24){if(!_24){_24=[];}_21.forEach(function(t){if(_22.call(_23,t)){_24.push(t);}});return _24;};abego.TiddlerFilterTerm=function(_26,_27){if(!_27){_27={};}var _28=_26;if(!_27.textIsRegExp){_28=_26.escapeRegExp();if(_27.fullWordMatch){_28="\\b"+_28+"\\b";}}var _29=new RegExp(_28,"m"+(_27.caseSensitive?"":"i"));this.tester=new abego.MultiFieldRegExpTester(_29,_27.fields,_27.withExtendedFields);};abego.TiddlerFilterTerm.prototype.test=function(_2a){return this.tester.test(_2a);};abego.parseNewTiddlerCommandLine=function(s){var m=/(.*?)\.(?:\s+|$)([^#]*)(#.*)?/.exec(s);if(!m){m=/([^#]*)()(#.*)?/.exec(s);}if(m){var r;if(m[3]){var s2=m[3].replace(/#/g,"");r=s2.parseParams("tag");}else{r=[[]];}var _2f=m[2]?m[2].trim():"";r.push({name:"text",value:_2f});r[0].text=[_2f];return {title:m[1].trim(),params:r};}else{return {title:s.trim(),params:[[]]};}};abego.parseTiddlerFilterTerm=function(_30,_31,_32){var re=/\s*(?:(?:\{([^\}]*)\})|(?:(=)|([#%!])|(?:(\w+)\s*\:(?!\/\/))|(?:(?:("(?:(?:\\")|[^"])+")|(?:\/((?:(?:\\\/)|[^\/])+)\/)|(\w+\:\/\/[^\s]+)|([^\s\)\-\"]+)))))/mg;var _34={"!":"title","%":"text","#":"tags"};var _35={};var _36;re.lastIndex=_31;while(1){var i=re.lastIndex;var m=re.exec(_30);if(!m||m.index!=i){throw "Word or String literal expected";}if(m[1]){var _39={};var _3a=abego.getBracedText(_30,0,_39);if(!_3a){throw "Invalid {...} syntax";}var f=Function("tiddler","return ("+_3a+");");return {func:f,lastIndex:_39.lastIndex,markRE:null};}if(m[2]){_36=true;}else{if(m[3]){_35[_34[m[3]]]=1;}else{if(m[4]){_35[m[4]]=1;}else{var _3c=m[6];var _3d=m[5]?window.eval(m[5]):m[6]?m[6]:m[7]?m[7]:m[8];var _32=abego.copyOptions(_32);_32.fullWordMatch=_36;_32.textIsRegExp=_3c;var _3e=[];for(var n in _35){_3e.push(n);}if(_3e.length==0){_32.fields=_32.defaultFields;}else{_32.fields=_3e;_32.withExtendedFields=false;}var _40=new abego.TiddlerFilterTerm(_3d,_32);var _41=_3c?_3d:_3d.escapeRegExp();if(_41&&_36){_41="\\b"+_41+"\\b";}return {func:function(_42){return _40.test(_42);},lastIndex:re.lastIndex,markRE:_41?"(?:"+_41+")":null};}}}}};abego.BoolExp=function(s,_44,_45){this.s=s;var _46=_45&&_45.defaultOperationIs_OR;var _47=/\s*(?:(\-|not)|(\())/gi;var _48=/\s*\)/g;var _49=/\s*(?:(and|\&\&)|(or|\|\|))/gi;var _4a=/\s*[^\)\s]/g;var _4b=/\s*(\-|not)?(\s*\()?/gi;var _4c=function(_4d){_4b.lastIndex=_4d;var m=_4b.exec(s);var _4f;var _50;if(m&&m.index==_4d){_4d=_4b.lastIndex;_4f=m[1];if(m[2]){var e=parseBoolExpression(_4d);_48.lastIndex=e.lastIndex;if(!_48.exec(s)){throw "Missing ')'";}_50={func:e.func,lastIndex:_48.lastIndex};}}if(!_50){_50=_44(s,_4d,_45);}if(_4f){_50.func=(function(f){return function(_53){return !f(_53);};})(_50.func);_50.markRE=null;}return _50;};var _54=function(_55){var _56=_4c(_55);while(1){var l=_56.lastIndex;_49.lastIndex=l;var m=_49.exec(s);var _59;var _5a;if(m&&m.index==l){_59=!m[1];_5a=_4c(_49.lastIndex);}else{try{_5a=_4c(l);}catch(e){return _56;}_59=_46;}_56.func=(function(_5b,_5c,_5d){return _5d?function(_5e){return _5b(_5e)||_5c(_5e);}:function(_5f){return _5b(_5f)&&_5c(_5f);};})(_56.func,_5a.func,_59);_56.lastIndex=_5a.lastIndex;if(!_56.markRE){_56.markRE=_5a.markRE;}else{if(_5a.markRE){_56.markRE=_56.markRE+"|"+_5a.markRE;}}}};var _60=_54(0);this.evalFunc=_60.func;if(_60.markRE){this.markRegExp=new RegExp(_60.markRE,_45.caseSensitive?"mg":"img");}};abego.BoolExp.prototype.exec=function(){return this.evalFunc.apply(this,arguments);};abego.BoolExp.prototype.getMarkRegExp=function(){return this.markRegExp;};abego.BoolExp.prototype.toString=function(){return this.s;};abego.MultiFieldRegExpTester=function(re,_62,_63){this.re=re;this.fields=_62?_62:["title","text","tags"];this.withExtendedFields=_63;};abego.MultiFieldRegExpTester.prototype.test=function(_64){var re=this.re;for(var i=0;i<this.fields.length;i++){var s=store.getValue(_64,this.fields[i]);if(typeof s=="string"&&re.test(s)){return this.fields[i];}}if(this.withExtendedFields){return store.forEachField(_64,function(_68,_69,_6a){return typeof _6a=="string"&&re.test(_6a)?_69:null;},true);}return null;};abego.TiddlerQuery=function(_6b,_6c,_6d,_6e,_6f){if(_6d){this.regExp=new RegExp(_6b,_6c?"mg":"img");this.tester=new abego.MultiFieldRegExpTester(this.regExp,_6e,_6f);}else{this.expr=new abego.BoolExp(_6b,abego.parseTiddlerFilterTerm,{defaultFields:_6e,caseSensitive:_6c,withExtendedFields:_6f});}this.getQueryText=function(){return _6b;};this.getUseRegExp=function(){return _6d;};this.getCaseSensitive=function(){return _6c;};this.getDefaultFields=function(){return _6e;};this.getWithExtendedFields=function(){return _6f;};};abego.TiddlerQuery.prototype.test=function(_70){if(!_70){return false;}if(this.regExp){return this.tester.test(_70);}return this.expr.exec(_70);};abego.TiddlerQuery.prototype.filter=function(_71){return abego.select(_71,this.test,this);};abego.TiddlerQuery.prototype.getMarkRegExp=function(){if(this.regExp){return "".search(this.regExp)>=0?null:this.regExp;}return this.expr.getMarkRegExp();};abego.TiddlerQuery.prototype.toString=function(){return (this.regExp?this.regExp:this.expr).toString();};abego.PageWiseRenderer=function(){this.firstIndexOnPage=0;};merge(abego.PageWiseRenderer.prototype,{setItems:function(_72){this.items=_72;this.setFirstIndexOnPage(0);},getMaxPagesInNavigation:function(){return 10;},getItemsCount:function(_73){return this.items?this.items.length:0;},getCurrentPageIndex:function(){return Math.floor(this.firstIndexOnPage/this.getItemsPerPage());},getLastPageIndex:function(){return Math.floor((this.getItemsCount()-1)/this.getItemsPerPage());},setFirstIndexOnPage:function(_74){this.firstIndexOnPage=Math.min(Math.max(0,_74),this.getItemsCount()-1);},getFirstIndexOnPage:function(){this.firstIndexOnPage=Math.floor(this.firstIndexOnPage/this.getItemsPerPage())*this.getItemsPerPage();return this.firstIndexOnPage;},getLastIndexOnPage:function(){return Math.min(this.getFirstIndexOnPage()+this.getItemsPerPage()-1,this.getItemsCount()-1);},onPageChanged:function(_75,_76){},renderPage:function(_77){if(_77.beginRendering){_77.beginRendering(this);}try{if(this.getItemsCount()){var _78=this.getLastIndexOnPage();var _79=-1;for(var i=this.getFirstIndexOnPage();i<=_78;i++){_79++;_77.render(this,this.items[i],i,_79);}}}finally{if(_77.endRendering){_77.endRendering(this);}}},addPageNavigation:function(_7b){if(!this.getItemsCount()){return;}var _7c=this;var _7d=function(e){if(!e){var e=window.event;}var _7f=abego.toInt(this.getAttribute("page"),0);var _80=_7c.getCurrentPageIndex();if(_7f==_80){return;}var _81=_7f*_7c.getItemsPerPage();_7c.setFirstIndexOnPage(_81);_7c.onPageChanged(_7f,_80);};var _82;var _83=this.getCurrentPageIndex();var _84=this.getLastPageIndex();if(_83>0){_82=createTiddlyButton(_7b,"Previous","Go to previous page (Shortcut: Alt-'<')",_7d,"prev");_82.setAttribute("page",(_83-1).toString());_82.setAttribute("accessKey","<");}for(var i=-this.getMaxPagesInNavigation();i<this.getMaxPagesInNavigation();i++){var _86=_83+i;if(_86<0){continue;}if(_86>_84){break;}var _87=(i+_83+1).toString();var _88=_86==_83?"currentPage":"otherPage";_82=createTiddlyButton(_7b,_87,"Go to page %0".format([_87]),_7d,_88);_82.setAttribute("page",(_86).toString());}if(_83<_84){_82=createTiddlyButton(_7b,"Next","Go to next page (Shortcut: Alt-'>')",_7d,"next");_82.setAttribute("page",(_83+1).toString());_82.setAttribute("accessKey",">");}}});abego.LimitedTextRenderer=function(){var _89=40;var _8a=4;var _8b=function(_8c,_8d,_8e){var n=_8c.length;if(n==0){_8c.push({start:_8d,end:_8e});return;}var i=0;for(;i<n;i++){var _91=_8c[i];if(_91.start<=_8e&&_8d<=_91.end){var r;var _93=i+1;for(;_93<n;_93++){r=_8c[_93];if(r.start>_8e||_8d>_91.end){break;}}var _94=_8d;var _95=_8e;for(var j=i;j<_93;j++){r=_8c[j];_94=Math.min(_94,r.start);_95=Math.max(_95,r.end);}_8c.splice(i,_93-i,{start:_94,end:_95});return;}if(_91.start>_8e){break;}}_8c.splice(i,0,{start:_8d,end:_8e});};var _97=function(_98){var _99=0;for(var i=0;i<_98.length;i++){var _9b=_98[i];_99+=_9b.end-_9b.start;}return _99;};var _9c=function(c){return (c>="a"&&c<="z")||(c>="A"&&c<="Z")||c=="_";};var _9e=function(s,_a0){if(!_9c(s[_a0])){return null;}for(var i=_a0-1;i>=0&&_9c(s[i]);i--){}var _a2=i+1;var n=s.length;for(i=_a0+1;i<n&&_9c(s[i]);i++){}return {start:_a2,end:i};};var _a4=function(s,_a6,_a7){var _a8;if(_a7){_a8=_9e(s,_a6);}else{if(_a6<=0){return _a6;}_a8=_9e(s,_a6-1);}if(!_a8){return _a6;}if(_a7){if(_a8.start>=_a6-_8a){return _a8.start;}if(_a8.end<=_a6+_8a){return _a8.end;}}else{if(_a8.end<=_a6+_8a){return _a8.end;}if(_a8.start>=_a6-_8a){return _a8.start;}}return _a6;};var _a9=function(s,_ab){var _ac=[];if(_ab){var _ad=0;var n=s.length;var _af=0;do{_ab.lastIndex=_ad;var _b0=_ab.exec(s);if(_b0){if(_ad<_b0.index){var t=s.substring(_ad,_b0.index);_ac.push({text:t});}_ac.push({text:_b0[0],isMatch:true});_ad=_b0.index+_b0[0].length;}else{_ac.push({text:s.substr(_ad)});break;}}while(true);}else{_ac.push({text:s});}return _ac;};var _b2=function(_b3){var _b4=0;for(var i=0;i<_b3.length;i++){if(_b3[i].isMatch){_b4++;}}return _b4;};var _b6=function(s,_b8,_b9,_ba,_bb){var _bc=Math.max(Math.floor(_bb/(_ba+1)),_89);var _bd=Math.max(_bc-(_b9-_b8),0);var _be=Math.min(Math.floor(_b9+_bd/3),s.length);var _bf=Math.max(_be-_bc,0);_bf=_a4(s,_bf,true);_be=_a4(s,_be,false);return {start:_bf,end:_be};};var _c0=function(_c1,s,_c3){var _c4=[];var _c5=_b2(_c1);var pos=0;for(var i=0;i<_c1.length;i++){var t=_c1[i];var _c9=t.text;if(t.isMatch){var _ca=_b6(s,pos,pos+_c9.length,_c5,_c3);_8b(_c4,_ca.start,_ca.end);}pos+=_c9.length;}return _c4;};var _cb=function(s,_cd,_ce){var _cf=_ce-_97(_cd);while(_cf>0){if(_cd.length==0){_8b(_cd,0,_a4(s,_ce,false));return;}else{var _d0=_cd[0];var _d1;var _d2;if(_d0.start==0){_d1=_d0.end;if(_cd.length>1){_d2=_cd[1].start;}else{_8b(_cd,_d1,_a4(s,_d1+_cf,false));return;}}else{_d1=0;_d2=_d0.start;}var _d3=Math.min(_d2,_d1+_cf);_8b(_cd,_d1,_d3);_cf-=(_d3-_d1);}}};var _d4=function(_d5,s,_d7,_d8,_d9){if(_d8.length==0){return;}var _da=function(_db,s,_dd,_de,_df){var t;var _e1;var pos=0;var i=0;var _e4=0;for(;i<_dd.length;i++){t=_dd[i];_e1=t.text;if(_de<pos+_e1.length){_e4=_de-pos;break;}pos+=_e1.length;}var _e5=_df-_de;for(;i<_dd.length&&_e5>0;i++){t=_dd[i];_e1=t.text.substr(_e4);_e4=0;if(_e1.length>_e5){_e1=_e1.substr(0,_e5);}if(t.isMatch){createTiddlyElement(_db,"span",null,"marked",_e1);}else{createTiddlyText(_db,_e1);}_e5-=_e1.length;}if(_df<s.length){abego.createEllipsis(_db);}};if(_d8[0].start>0){abego.createEllipsis(_d5);}var _e6=_d9;for(var i=0;i<_d8.length&&_e6>0;i++){var _e8=_d8[i];var len=Math.min(_e8.end-_e8.start,_e6);_da(_d5,s,_d7,_e8.start,_e8.start+len);_e6-=len;}};this.render=function(_ea,s,_ec,_ed){if(s.length<_ec){_ec=s.length;}var _ee=_a9(s,_ed);var _ef=_c0(_ee,s,_ec);_cb(s,_ef,_ec);_d4(_ea,s,_ee,_ef,_ec);};};(function(){function alertAndThrow(msg){alert(msg);throw msg;}if(version.major<2||(version.major==2&&version.minor<1)){alertAndThrow("YourSearchPlugin requires TiddlyWiki 2.1 or newer.\n\nCheck the archive for YourSearch plugins\nsupporting older versions of TiddlyWiki.\n\nArchive: http://tiddlywiki.abego-software.de/archive");}abego.YourSearch={};var _f1;var _f2;var _f3=function(_f4){_f1=_f4;};var _f5=function(){return _f1?_f1:[];};var _f6=function(){return _f1?_f1.length:0;};var _f7=4;var _f8=10;var _f9=2;var _fa=function(s,re){var m=s.match(re);return m?m.length:0;};var _fe=function(_ff,_100){var _101=_100.getMarkRegExp();if(!_101){return 1;}var _102=_ff.title.match(_101);var _103=_102?_102.length:0;var _104=_fa(_ff.getTags(),_101);var _105=_102?_102.join("").length:0;var _106=_ff.title.length>0?_105/_ff.title.length:0;var rank=_103*_f7+_104*_f9+_106*_f8+1;return rank;};var _108=function(_109,_10a,_10b,_10c,_10d,_10e){_f2=null;var _10f=_109.reverseLookup("tags",_10e,false);try{var _110=[];if(config.options.chkSearchInTitle){_110.push("title");}if(config.options.chkSearchInText){_110.push("text");}if(config.options.chkSearchInTags){_110.push("tags");}_f2=new abego.TiddlerQuery(_10a,_10b,_10c,_110,config.options.chkSearchExtendedFields);}catch(e){return [];}var _111=_f2.filter(_10f);var _112=abego.YourSearch.getRankFunction();for(var i=0;i<_111.length;i++){var _114=_111[i];var rank=_112(_114,_f2);_114.searchRank=rank;}if(!_10d){_10d="title";}var _116=function(a,b){var _119=a.searchRank-b.searchRank;if(_119==0){if(a[_10d]==b[_10d]){return (0);}else{return (a[_10d]<b[_10d])?-1:+1;}}else{return (_119>0)?-1:+1;}};_111.sort(_116);return _111;};var _11a=80;var _11b=50;var _11c=250;var _11d=50;var _11e=25;var _11f=10;var _120="yourSearchResult";var _121="yourSearchResultItems";var _122;var _123;var _124;var _125;var _126;var _127=function(){if(version.extensions.YourSearchPlugin.styleSheetInited){return;}version.extensions.YourSearchPlugin.styleSheetInited=true;setStylesheet(store.getTiddlerText("YourSearchStyleSheet"),"yourSearch");};var _128=function(){return _123!=null&&_123.parentNode==document.body;};var _129=function(){if(_128()){document.body.removeChild(_123);}};var _12a=function(e){_129();var _12c=this.getAttribute("tiddlyLink");if(_12c){var _12d=this.getAttribute("withHilite");var _12e=highlightHack;if(_12d&&_12d=="true"&&_f2){highlightHack=_f2.getMarkRegExp();}story.displayTiddler(this,_12c);highlightHack=_12e;}return (false);};var _12f=function(){if(!_124){return;}var root=_124;var _131=findPosX(root);var _132=findPosY(root);var _133=root.offsetHeight;var _134=_131;var _135=_132+_133;var _136=findWindowWidth();if(_136<_123.offsetWidth){_123.style.width=(_136-100)+"px";_136=findWindowWidth();}var _137=_123.offsetWidth;if(_134+_137>_136){_134=_136-_137-30;}if(_134<0){_134=0;}_123.style.left=_134+"px";_123.style.top=_135+"px";_123.style.display="block";};var _138=function(){if(_123){window.scrollTo(0,ensureVisible(_123));}if(_124){window.scrollTo(0,ensureVisible(_124));}};var _139=function(){_12f();_138();};var _13a;var _13b;var _13c=new abego.PageWiseRenderer();var _13d=function(_13e){this.itemHtml=store.getTiddlerText("YourSearchItemTemplate");if(!this.itemHtml){alertAndThrow("YourSearchItemTemplate not found");}this.place=document.getElementById(_121);if(!this.place){this.place=createTiddlyElement(_13e,"div",_121);}};merge(_13d.prototype,{render:function(_13f,_140,_141,_142){_13a=_142;_13b=_140;var item=createTiddlyElement(this.place,"div",null,"yourSearchItem");item.innerHTML=this.itemHtml;applyHtmlMacros(item,null);refreshElements(item,null);},endRendering:function(_144){_13b=null;}});var _145=function(){if(!_123||!_124){return;}var html=store.getTiddlerText("YourSearchResultTemplate");if(!html){html="<b>Tiddler YourSearchResultTemplate not found</b>";}_123.innerHTML=html;applyHtmlMacros(_123,null);refreshElements(_123,null);var _147=new _13d(_123);_13c.renderPage(_147);_139();};_13c.getItemsPerPage=function(){var n=(config.options.chkPreviewText)?abego.toInt(config.options.txtItemsPerPageWithPreview,_11f):abego.toInt(config.options.txtItemsPerPage,_11e);return (n>0)?n:1;};_13c.onPageChanged=function(){_145();};var _149=function(){if(!_123){_123=createTiddlyElement(document.body,"div",_120,"yourSearchResult");}else{if(_123.parentNode!=document.body){document.body.appendChild(_123);}}_145();};var _14a=function(){if(_124==null||!config.options.chkUseYourSearch){return;}if((_124.value==_122)&&_122&&!_128()){if(_123&&(_123.parentNode!=document.body)){document.body.appendChild(_123);_139();}else{_149();}}};var _14b=function(){_129();_123=null;_122=null;};var _14c=function(self,e){while(e!=null){if(self==e){return true;}e=e.parentNode;}return false;};var _14f=function(e){if(e.target==_124){return;}if(e.target==_125){return;}if(_123&&_14c(_123,e.target)){return;}_129();};var _151=function(e){if(e.keyCode==27){_129();}};addEvent(document,"click",_14f);addEvent(document,"keyup",_151);var _153=function(text,_155,_156){_122=text;_f3(_108(store,text,_155,_156,"title","excludeSearch"));highlightHack=_f2?_f2.getMarkRegExp():null;_13c.setItems(_f5());_149();highlightHack=null;};var _157=function(_158,_159,_15a,_15b,_15c,_15d){_127();_122="";var _15e=null;var _15f=function(txt){if(config.options.chkUseYourSearch){_153(txt.value,config.options.chkCaseSensitiveSearch,config.options.chkRegExpSearch);}else{story.search(txt.value,config.options.chkCaseSensitiveSearch,config.options.chkRegExpSearch);}_122=txt.value;};var _161=function(e){_15f(_124);return false;};var _163=function(e){if(!e){var e=window.event;}_124=this;switch(e.keyCode){case 13:if(e.ctrlKey&&_126&&_128()){_126.onclick.apply(_126,[e]);}else{_15f(this);}break;case 27:if(_128()){_129();}else{this.value="";clearMessage();}break;}if(String.fromCharCode(e.keyCode)==this.accessKey||e.altKey){_14a();}if(this.value.length<3&&_15e){clearTimeout(_15e);}if(this.value.length>2){if(this.value!=_122){if(!config.options.chkUseYourSearch||config.options.chkSearchAsYouType){if(_15e){clearTimeout(_15e);}var txt=this;_15e=setTimeout(function(){_15f(txt);},500);}}else{if(_15e){clearTimeout(_15e);}}}if(this.value.length==0){_129();}};var _166=function(e){this.select();clearMessage();_14a();};var args=_15c.parseParams("list",null,true);var _169=getFlag(args,"buttonAtRight");var _16a=getParam(args,"sizeTextbox",this.sizeTextbox);var btn;if(!_169){btn=createTiddlyButton(_158,this.label,this.prompt,_161);}var txt=createTiddlyElement(_158,"input",null,null,null);if(_15a[0]){txt.value=_15a[0];}txt.onkeyup=_163;txt.onfocus=_166;txt.setAttribute("size",_16a);txt.setAttribute("accessKey",this.accessKey);txt.setAttribute("autocomplete","off");if(config.browser.isSafari){txt.setAttribute("type","search");txt.setAttribute("results","5");}else{txt.setAttribute("type","text");}if(_169){btn=createTiddlyButton(_158,this.label,this.prompt,_161);}_124=txt;_125=btn;};var _16d=function(){_129();var _16e=_f5();var n=_16e.length;if(n){var _170=[];for(var i=0;i<n;i++){_170.push(_16e[i].title);}story.displayTiddlers(null,_170);}};var _172=function(_173,_174,_175,_176){invokeMacro(_173,"option",_174,_175,_176);var elem=_173.lastChild;var _178=elem.onclick;elem.onclick=function(e){var _17a=_178.apply(this,arguments);_145();return _17a;};return elem;};var _17b=function(s){var _17d=["''","{{{","}}}","//","<<<","/***","***/"];var _17e="";for(var i=0;i<_17d.length;i++){if(i!=0){_17e+="|";}_17e+="("+_17d[i].escapeRegExp()+")";}return s.replace(new RegExp(_17e,"mg"),"").trim();};var _180=function(){var i=_13a;return (i>=0&&i<=9)?(i<9?(i+1):0):-1;};var _182=new abego.LimitedTextRenderer();var _183=function(_184,s,_186){_182.render(_184,s,_186,_f2.getMarkRegExp());};var _187=TiddlyWiki.prototype.saveTiddler;TiddlyWiki.prototype.saveTiddler=function(_188,_189,_18a,_18b,_18c,tags,_18e){_187.apply(this,arguments);_14b();};var _18f=TiddlyWiki.prototype.removeTiddler;TiddlyWiki.prototype.removeTiddler=function(_190){_18f.apply(this,arguments);_14b();};config.macros.yourSearch={label:"yourSearch",prompt:"Gives access to the current/last YourSearch result",handler:function(_191,_192,_193,_194,_195,_196){if(_193.length==0){return;}var name=_193[0];var func=config.macros.yourSearch.funcs[name];if(func){func(_191,_192,_193,_194,_195,_196);}},tests:{"true":function(){return true;},"false":function(){return false;},"found":function(){return _f6()>0;},"previewText":function(){return config.options.chkPreviewText;}},funcs:{itemRange:function(_199){if(_f6()){var _19a=_13c.getLastIndexOnPage();var s="%0 - %1".format([_13c.getFirstIndexOnPage()+1,_19a+1]);createTiddlyText(_199,s);}},count:function(_19c){createTiddlyText(_19c,_f6().toString());},query:function(_19d){if(_f2){createTiddlyText(_19d,_f2.toString());}},version:function(_19e){var t="YourSearch %0.%1.%2".format([version.extensions.YourSearchPlugin.major,version.extensions.YourSearchPlugin.minor,version.extensions.YourSearchPlugin.revision]);var e=createTiddlyElement(_19e,"a");e.setAttribute("href","http://tiddlywiki.abego-software.de/#YourSearchPlugin");e.innerHTML="<font color=\"black\" face=\"Arial, Helvetica, sans-serif\">"+t+"<font>";},copyright:function(_1a1){var e=createTiddlyElement(_1a1,"a");e.setAttribute("href","http://www.abego-software.de");e.innerHTML="<font color=\"black\" face=\"Arial, Helvetica, sans-serif\">&copy; 2005-2006 <b><font color=\"red\">abego</font></b> Software<font>";},newTiddlerButton:function(_1a3){if(_f2){var r=abego.parseNewTiddlerCommandLine(_f2.getQueryText());var btn=config.macros.newTiddler.createNewTiddlerButton(_1a3,r.title,r.params,"new tiddler","Create a new tiddler based on search text. (Shortcut: Ctrl-Enter; Separators: '.', '#')",null,"text");var _1a6=btn.onclick;btn.onclick=function(){_129();_1a6.apply(this,arguments);};_126=btn;}},linkButton:function(_1a7,_1a8,_1a9,_1aa,_1ab,_1ac){if(_1a9<2){return;}var _1ad=_1a9[1];var text=_1a9<3?_1ad:_1a9[2];var _1af=_1a9<4?text:_1a9[3];var _1b0=_1a9<5?null:_1a9[4];var btn=createTiddlyButton(_1a7,text,_1af,_12a,null,null,_1b0);btn.setAttribute("tiddlyLink",_1ad);},closeButton:function(_1b2,_1b3,_1b4,_1b5,_1b6,_1b7){var _1b8=createTiddlyButton(_1b2,"close","Close the Search Results (Shortcut: ESC)",_129);},openAllButton:function(_1b9,_1ba,_1bb,_1bc,_1bd,_1be){var n=_f6();if(n==0){return;}var _1c0=n==1?"open tiddler":"open all %0 tiddlers".format([n]);var _1c1=createTiddlyButton(_1b9,_1c0,"Open all found tiddlers (Shortcut: Alt-O)",_16d);_1c1.setAttribute("accessKey","O");},naviBar:function(_1c2,_1c3,_1c4,_1c5,_1c6,_1c7){_13c.addPageNavigation(_1c2);},"if":function(_1c8,_1c9,_1ca,_1cb,_1cc,_1cd){if(_1ca.length<2){return;}var _1ce=_1ca[1];var _1cf=(_1ce=="not");if(_1cf){if(_1ca.length<3){return;}_1ce=_1ca[2];}var test=config.macros.yourSearch.tests[_1ce];var _1d1=false;try{if(test){_1d1=test(_1c8,_1c9,_1ca,_1cb,_1cc,_1cd)!=_1cf;}else{_1d1=(!eval(_1ce))==_1cf;}}catch(ex){}if(!_1d1){_1c8.style.display="none";}},chkPreviewText:function(_1d2,_1d3,_1d4,_1d5,_1d6,_1d7){var _1d8=_1d4.slice(1).join(" ");var elem=_172(_1d2,"chkPreviewText",_1d5,_1d7);elem.setAttribute("accessKey","P");elem.title="Show text preview of found tiddlers (Shortcut: Alt-P)";return elem;}}};config.macros.foundTiddler={label:"foundTiddler",prompt:"Provides information on the tiddler currently processed on the YourSearch result page",handler:function(_1da,_1db,_1dc,_1dd,_1de,_1df){var name=_1dc[0];var func=config.macros.foundTiddler.funcs[name];if(func){func(_1da,_1db,_1dc,_1dd,_1de,_1df);}},funcs:{title:function(_1e2,_1e3,_1e4,_1e5,_1e6,_1e7){if(!_13b){return;}var _1e8=_180();var _1e9=_1e8>=0?"Open tiddler (Shortcut: Alt-%0)".format([_1e8.toString()]):"Open tiddler";var btn=createTiddlyButton(_1e2,null,_1e9,_12a,null);btn.setAttribute("tiddlyLink",_13b.title);btn.setAttribute("withHilite","true");_183(btn,_13b.title,_11a);if(_1e8>=0){btn.setAttribute("accessKey",_1e8.toString());}},tags:function(_1eb,_1ec,_1ed,_1ee,_1ef,_1f0){if(!_13b){return;}_183(_1eb,_13b.getTags(),_11b);},text:function(_1f1,_1f2,_1f3,_1f4,_1f5,_1f6){if(!_13b){return;}_183(_1f1,_17b(_13b.text),_11c);},field:function(_1f7,_1f8,_1f9,_1fa,_1fb,_1fc){if(!_13b){return;}var name=_1f9[1];var len=_1f9.length>2?abego.toInt(_1f9[2],_11d):_11d;var v=store.getValue(_13b,name);if(v){_183(_1f7,_17b(v),len);}},number:function(_200,_201,_202,_203,_204,_205){var _206=_180();if(_206>=0){var text="%0)".format([_206.toString()]);createTiddlyElement(_200,"span",null,"shortcutNumber",text);}}}};var opts={chkUseYourSearch:true,chkPreviewText:true,chkSearchAsYouType:true,chkSearchInTitle:true,chkSearchInText:true,chkSearchInTags:true,chkSearchExtendedFields:true,txtItemsPerPage:_11e,txtItemsPerPageWithPreview:_11f};for(var n in opts){if(config.options[n]==undefined){config.options[n]=opts[n];}}config.shadowTiddlers.AdvancedOptions+="\n<<option chkUseYourSearch>> Use 'Your Search' //([[more options|YourSearch Options]]) ([[help|YourSearch Help]])// ";config.shadowTiddlers["YourSearch Help"]="!Field Search\nWith the Field Search you can restrict your search to certain fields of a tiddler, e.g"+" only search the tags or only the titles. The general form is //fieldname//'':''//textToSearch// (e."+"g. {{{title:intro}}}). In addition one-character shortcuts are also supported for the standard field"+"s {{{title}}}, {{{text}}} and {{{tags}}}:\n|!What you want|!What you type|!Example|\n|Search ''titles "+"only''|start word with ''!''|{{{!jonny}}} (shortcut for {{{title:jonny}}})|\n|Search ''contents/text "+"only''|start word with ''%''|{{{%football}}} (shortcut for {{{text:football}}})|\n|Search ''tags only"+"''|start word with ''#''|{{{#Plugin}}} (shortcut for {{{tags:Plugin}}})|\n\nUsing this feature you may"+" also search the extended fields (\"Metadata\") introduced with TiddlyWiki 2.1, e.g. use {{{priority:1"+"}}} to find all tiddlers with the priority field set to \"1\".\n\nYou may search a word in more than one"+" field. E.g. {{{!#Plugin}}} (or {{{title:tags:Plugin}}} in the \"long form\") finds tiddlers containin"+"g \"Plugin\" either in the title or in the tags (but does not look for \"Plugin\" in the text). \n\n!Boole"+"an Search\nThe Boolean Search is useful when searching for multiple words.\n|!What you want|!What you "+"type|!Example|\n|''All words'' must exist|List of words|{{{jonny jeremy}}} (or {{{jonny and jeremy}}}"+")|\n|''At least one word'' must exist|Separate words by ''or''|{{{jonny or jeremy}}}|\n|A word ''must "+"not exist''|Start word with ''-''|{{{-jonny}}} (or {{{not jonny}}})|\n\n''Note:'' When you specify two"+" words, separated with a space, YourSearch finds all tiddlers that contain both words, but not neces"+"sarily next to each other. If you want to find a sequence of word, e.g. '{{{John Brown}}}', you need"+" to put the words into quotes. I.e. you type: {{{\"john brown\"}}}.\n\nUsing parenthesis you may change "+"the default \"left to right\" evaluation of the boolean search. E.g. {{{not (jonny or jeremy)}}} finds"+" all tiddlers that contain neither \"jonny\" nor \"jeremy. In contrast to this {{{not jonny or jeremy}}"+"} (i.e. without parenthesis) finds all tiddlers that either don't contain \"jonny\" or that contain \"j"+"eremy\".\n\n!'Exact Word' Search\nBy default a search result all matches that 'contain' the searched tex"+"t. E.g. if you search for {{{Task}}} you will get all tiddlers containing 'Task', but also '~Complet"+"edTask', '~TaskForce' etc.\n\nIf you only want to get the tiddlers that contain 'exactly the word' you"+" need to prefix it with a '='. E.g. typing '=Task' will find the tiddlers that contain the word 'Tas"+"k', ignoring words that just contain 'Task' as a substring.\n\n!~CaseSensitiveSearch and ~RegExpSearch"+"\nThe standard search options ~CaseSensitiveSearch and ~RegExpSearch are fully supported by YourSearc"+"h. However when ''~RegExpSearch'' is on Filtered and Boolean Search are disabled.\n\nIn addition you m"+"ay do a \"regular expression\" search even with the ''~RegExpSearch'' set to false by directly enterin"+"g the regular expression into the search field, framed with {{{/.../}}}. \n\nExample: {{{/m[ae][iy]er/"+"}}} will find all tiddlers that contain either \"maier\", \"mayer\", \"meier\" or \"meyer\".\n\n!~JavaScript E"+"xpression Filtering\nIf you are familiar with JavaScript programming and know some TiddlyWiki interna"+"ls you may also use JavaScript expression for the search. Just enter a JavaScript boolean expression"+" into the search field, framed with {{{ { ... } }}}. In the code refer to the variable tiddler and e"+"valuate to {{{true}}} when the given tiddler should be included in the result. \n\nExample: {{{ { tidd"+"ler.modified > new Date(\"Jul 4, 2005\")} }}} returns all tiddler modified after July 4th, 2005.\n\n!Com"+"bined Search\nYou are free to combine the various search options. \n\n''Examples''\n|!What you type|!Res"+"ult|\n|{{{!jonny !jeremy -%football}}}|all tiddlers with both {{{jonny}}} and {{{jeremy}}} in its tit"+"les, but no {{{football}}} in content.|\n|{{{#=Task}}}|All tiddlers tagged with 'Task' (the exact wor"+"d). Tags named '~CompletedTask', '~TaskForce' etc. are not considered.|\n\n!Access Keys\nYou are encour"+"aged to use the access keys (also called \"shortcut\" keys) for the most frequently used operations. F"+"or quick reference these shortcuts are also mentioned in the tooltip for the various buttons etc.\n\n|"+"!Key|!Operation|\n|{{{Alt-F}}}|''The most important keystroke'': It moves the cursor to the search in"+"put field so you can directly start typing your query. Pressing {{{Alt-F}}} will also display the pr"+"evious search result. This way you can quickly display multiple tiddlers using \"Press {{{Alt-F}}}. S"+"elect tiddler.\" sequences.|\n|{{{ESC}}}|Closes the [[YourSearch Result]]. When the [[YourSearch Resul"+"t]] is already closed and the cursor is in the search input field the field's content is cleared so "+"you start a new query.|\n|{{{Alt-1}}}, {{{Alt-2}}},... |Pressing these keys opens the first, second e"+"tc. tiddler from the result list.|\n|{{{Alt-O}}}|Opens all found tiddlers.|\n|{{{Alt-P}}}|Toggles the "+"'Preview Text' mode.|\n|{{{Alt-'<'}}}, {{{Alt-'>'}}}|Displays the previous or next page in the [[Your"+"Search Result]].|\n|{{{Return}}}|When you have turned off the 'as you type' search mode pressing the "+"{{{Return}}} key actually starts the search (as does pressing the 'search' button).|\n\n//If some of t"+"hese shortcuts don't work for you check your browser if you have other extensions installed that alr"+"eady \"use\" these shortcuts.//";config.shadowTiddlers["YourSearch Options"]="|>|!YourSearch Options|\n|>|<<option chkUseYourSearch>> Use 'Your Search'|\n|!|<<option chkPreviewText"+">> Show Text Preview|\n|!|<<option chkSearchAsYouType>> 'Search As You Type' Mode (No RETURN required"+" to start search)|\n|!|Default Search Filter:<<option chkSearchInTitle>>Title ('!')     <<option chk"+"SearchInText>>Text ('%')     <<option chkSearchInTags>>Tags ('#')    <<option chkSearchExtendedFiel"+"ds>>Extended Fields<html><br><font size=\"-2\">The fields of a tiddlers that are searched when you don"+"'t explicitly specify a filter in the search text <br>(Explictly specify fields using one or more '!"+"', '%', '#' or 'fieldname:' prefix before the word/text to find).</font></html>|\n|!|Number of items "+"on search result page: <<option txtItemsPerPage>>|\n|!|Number of items on search result page with pre"+"view text: <<option txtItemsPerPageWithPreview>>|\n";config.shadowTiddlers["YourSearchStyleSheet"]="/***\n!~YourSearchResult Stylesheet\n***/\n/*{{{*/\n.yourSearchResult {\n\tposition: absolute;\n\twidth: 800"+"px;\n\n\tpadding: 0.2em;\n\tlist-style: none;\n\tmargin: 0;\n\n\tbackground: #ffd;\n\tborder: 1px solid DarkGra"+"y;\n}\n\n/*}}}*/\n/***\n!!Summary Section\n***/\n/*{{{*/\n.yourSearchResult .summary {\n\tborder-bottom-width:"+" thin;\n\tborder-bottom-style: solid;\n\tborder-bottom-color: #999999;\n\tpadding-bottom: 4px;\n}\n\n.yourSea"+"rchRange, .yourSearchCount, .yourSearchQuery   {\n\tfont-weight: bold;\n}\n\n.yourSearchResult .summary ."+"button {\n\tfont-size: 10px;\n\n\tpadding-left: 0.3em;\n\tpadding-right: 0.3em;\n}\n\n.yourSearchResult .summa"+"ry .chkBoxLabel {\n\tfont-size: 10px;\n\n\tpadding-right: 0.3em;\n}\n\n/*}}}*/\n/***\n!!Items Area\n***/\n/*{{{*"+"/\n.yourSearchResult .marked {\n\tbackground: none;\n\tfont-weight: bold;\n}\n\n.yourSearchItem {\n\tmargin-to"+"p: 2px;\n}\n\n.yourSearchNumber {\n\tcolor: #808080;\n}\n\n\n.yourSearchTags {\n\tcolor: #008000;\n}\n\n.yourSearc"+"hText {\n\tcolor: #808080;\n\tmargin-bottom: 6px;\n}\n\n/*}}}*/\n/***\n!!Footer\n***/\n/*{{{*/\n.yourSearchFoote"+"r {\n\tmargin-top: 8px;\n\tborder-top-width: thin;\n\tborder-top-style: solid;\n\tborder-top-color: #999999;"+"\n}\n\n.yourSearchFooter a:hover{\n\tbackground: none;\n\tcolor: none;\n}\n/*}}}*/\n/***\n!!Navigation Bar\n***/"+"\n/*{{{*/\n.yourSearchNaviBar a {\n\tfont-size: 16px;\n\tmargin-left: 4px;\n\tmargin-right: 4px;\n\tcolor: bla"+"ck;\n\ttext-decoration: underline;\n}\n\n.yourSearchNaviBar a:hover {\n\tbackground-color: none;\n}\n\n.yourSe"+"archNaviBar .prev {\n\tfont-weight: bold;\n\tcolor: blue;\n}\n\n.yourSearchNaviBar .currentPage {\n\tcolor: #"+"FF0000;\n\tfont-weight: bold;\n\ttext-decoration: none;\n}\n\n.yourSearchNaviBar .next {\n\tfont-weight: bold"+";\n\tcolor: blue;\n}\n/*}}}*/\n";config.shadowTiddlers["YourSearchResultTemplate"]="<!--\n{{{\n-->\n<span macro=\"yourSearch if found\">\n<!-- The Summary Header ============================"+"================ -->\n<table class=\"summary\" border=\"0\" width=\"100%\" cellspacing=\"0\" cellpadding=\"0\">"+"<tbody>\n  <tr>\n\t<td align=\"left\">\n\t\tYourSearch Result <span class=\"yourSearchRange\" macro=\"yourSearc"+"h itemRange\"></span>\n\t\t&nbsp;of&nbsp;<span class=\"yourSearchCount\" macro=\"yourSearch count\"></span>\n"+"\t\tfor&nbsp;<span class=\"yourSearchQuery\" macro=\"yourSearch query\"></span>\n\t</td>\n\t<td class=\"yourSea"+"rchButtons\" align=\"right\">\n\t\t<span macro=\"yourSearch chkPreviewText\"></span><span class=\"chkBoxLabel"+"\">preview text</span>\n\t\t<span macro=\"yourSearch newTiddlerButton\"></span>\n\t\t<span macro=\"yourSearch openAllButton\"></span>\n\t\t<span macro=\"yourSearch lin"+"kButton 'YourSearch Options' options 'Configure YourSearch'\"></span>\n\t\t<span macro=\"yourSearch linkB"+"utton 'YourSearch Help' help 'Get help how to use YourSearch'\"></span>\n\t\t<span macro=\"yourSearch clo"+"seButton\"></span>\n\t</td>\n  </tr>\n</tbody></table>\n\n<!-- The List of Found Tiddlers ================="+"=========================== -->\n<div id=\"yourSearchResultItems\" itemsPerPage=\"25\" itemsPerPageWithPr"+"eview=\"10\"></div>\n\n<!-- The Footer (with the Navigation) ==========================================="+"= -->\n<table class=\"yourSearchFooter\" border=\"0\" width=\"100%\" cellspacing=\"0\" cellpadding=\"0\"><tbody"+">\n  <tr>\n\t<td align=\"left\">\n\t\tResult page: <span class=\"yourSearchNaviBar\" macro=\"yourSearch naviBar"+"\"></span>\n\t</td>\n\t<td align=\"right\"><span macro=\"yourSearch version\"></span>, <span macro=\"yourSearc"+"h copyright\"></span>\n\t</td>\n  </tr>\n</tbody></table>\n<!-- end of the 'tiddlers found' case ========="+"================================== -->\n</span>\n\n\n<!-- The \"No tiddlers found\" case ================="+"========================== -->\n<span macro=\"yourSearch if not found\">\n<table class=\"summary\" border="+"\"0\" width=\"100%\" cellspacing=\"0\" cellpadding=\"0\"><tbody>\n  <tr>\n\t<td align=\"left\">\n\t\tYourSearch Resu"+"lt: No tiddlers found for <span class=\"yourSearchQuery\" macro=\"yourSearch query\"></span>.\n\t</td>\n\t<t"+"d class=\"yourSearchButtons\" align=\"right\">\n\t\t<span macro=\"yourSearch newTiddlerButton\"></span>\n\t\t<span macro=\"yourSearch linkButton 'YourSearch Options'"+" options 'Configure YourSearch'\"></span>\n\t\t<span macro=\"yourSearch linkButton 'YourSearch Help' help"+" 'Get help how to use YourSearch'\"></span>\n\t\t<span macro=\"yourSearch closeButton\"></span>\n\t</td>\n  <"+"/tr>\n</tbody></table>\n</span>\n\n\n<!--\n}}}\n-->\n";config.shadowTiddlers["YourSearchItemTemplate"]="<!--\n{{{\n-->\n<span class='yourSearchNumber' macro='foundTiddler number'></span>\n<span class='yourSea"+"rchTitle' macro='foundTiddler title'/></span>&nbsp;-&nbsp;\n<span class='yourSearchTags' macro='found"+"Tiddler field tags 50'/></span>\n<span macro=\"yourSearch if previewText\"><div class='yourSearchText' macro='fo"+"undTiddler field text 250'/></div></span>\n<!--\n}}}\n-->";config.shadowTiddlers["YourSearch"]="<<tiddler [[YourSearch Help]]>>";config.shadowTiddlers["YourSearch Result"]="The popup-like window displaying the result of a YourSearch query.";config.macros.search.handler=_157;var _20a=function(){if(config.macros.search.handler!=_157){alert("Message from YourSearchPlugin:\n\n\nAnother plugin has disabled the 'Your Search' features.\n\n\nYou may "+"disable the other plugin or change the load order of \nthe plugins (by changing the names of the tidd"+"lers)\nto enable the 'Your Search' features.");}};setTimeout(_20a,5000);abego.YourSearch.getStandardRankFunction=function(){return _fe;};abego.YourSearch.getRankFunction=function(){return abego.YourSearch.getStandardRankFunction();};abego.YourSearch.getCurrentTiddler=function(){return _13b;};abego.YourSearch.closeResult=function(){_129();};})();}
//%/
/***
|''Name:''|WikifiedMessagesPlugin|
|''Description:''|Wikify displayMessage text  |
|''Author:''|PaulDowney (psd (at) osmosoft (dot) com) |
|''Source:''|http://whatfettle.com/2008/07/WikifiedMessagesPlugin/ |
|''CodeRepository:''|http://svn.tiddlywiki.org/Trunk/contributors/PaulDowney/plugins/WikifiedMessagesPlugin/ |
|''Version:''|0.4|
|''License:''|[[BSD License|http://www.opensource.org/licenses/bsd-license.php]] |
|''Comments:''|Please make comments at http://groups.google.co.uk/group/TiddlyWikiDev |
|''~CoreVersion:''|2.4|
!!Documentation
A plugin to replace the core displayMessage function with a version which wikifies the message text.
The construction of the [close] single message and [close all] buttons has been seperated to be overrideable and the created message div is returned by displayMessage, for extensibility by other plugins.
!!Code
***/
//{{{
if(!version.extensions.WikifiedMessagesPlugin) {
version.extensions.WikifiedMessagesPlugin = {installed:true};
 
	if(!config.extensions){
		config.extensions = {};
	}
 
	config.extensions.WikifiedMessages = {
 
		createClearAllButton: function(msgArea)
		{
			return (msgArea.hasChildNodes())? null :
				createTiddlyButton(createTiddlyElement(msgArea,"div",null,"messageToolbar"),
					config.messages.messageClose.text,
					config.messages.messageClose.tooltip,
					clearMessage);
		},
		createClearMessageButton: function(e)
		{
			return null;
		},
		getMessageDiv: function()
		{
			var msgArea = document.getElementById("messageArea");
			var me = config.extensions.WikifiedMessages;
			if(!msgArea){
				return null;
			}
			msgArea.style.display = "block";
			me.createClearAllButton(msgArea);
			e = createTiddlyElement(msgArea,"div",null,"messageBox");
			me.createClearMessageButton(e);
			return e;
		},
		displayMessage: function(text,linkText)
		{
			var e = getMessageDiv();
			if(!e) {
				alert(wikifyPlain(text));
				return null;
			}
			if(linkText) {
				text = "[["+text+"|"+linkText+"]]";
			}
			t = createTiddlyElement(e,"span",null,"messageText");
			t.innerHTML = wikifyStatic(text);
			return e;
		}
	};
 
	displayMessage = config.extensions.WikifiedMessages.displayMessage;
	getMessageDiv = config.extensions.WikifiedMessages.getMessageDiv;
 
        // macro, useful for testing
        config.macros.DisplayMessage = {
                handler: function(place,macroName,params,wikifier,paramString,tiddler){
                        displayMessage(paramString);
                }
        };
}
//}}}
/***
|''Name:''|FadingMessagesPlugin|
|''Description:''|Automatically clear a displayed message after an interval |
|''Author:''|PaulDowney (psd (at) osmosoft (dot) com) |
|''Source:''|http://whatfettle.com/2008/07/FadingMessagesPlugin/ |
|''CodeRepository:''|http://svn.tiddlywiki.org/Trunk/contributors/PaulDowney/plugins/FadingMessagesPlugin/ |
|''Version:''|0.2|
|''License:''|[[BSD License|http://www.opensource.org/licenses/bsd-license.php]] |
|''Comments:''|Please make comments at http://groups.google.co.uk/group/TiddlyWikiDev |
|''~CoreVersion:''|2.4|
|''Overrides:''|displayMessage|
|''Requires:''|WikifiedMessagesPlugin|
!!Documentation
Displayed messages automatically fade away after a short interval. 
!!Options
|<<option txtFadingMessagesTimeout>>|<<message config.optionsDesc.txtFadingMessagesTimeout>>|
|<<option chkAnimate>>|<<message config.optionsDesc.chkAnimate>>|
!!Code
***/
//{{{
if(!version.extensions.FadingMessagesPlugin) {
version.extensions.FadingMessagesPlugin = {installed:true};
 
	config.options.txtFadingMessagesTimeout = 5;
	config.optionsDesc.txtFadingMessagesTimeout = "seconds before a displayed message clears itself";
 
	config.animDurationFade = 900;
 
	config.extensions.FadingMessages = {
		Fader: function(e,done)
		{
			e.style.overflow = 'hidden';
			e.style.display = 'block';
			var p = [];
			p.push({style: 'display', atEnd: 'none'});
			p.push({style: 'opacity', start: 1, end: 0, template: '%0'});
			p.push({style: 'filter', start: 100, end: 0, template: 'alpha(opacity:%0)'});
			return new Morpher(e,config.animDurationFade,p,done);
		},  
		clearMessageBox: function(e)
		{
			try { removeNode(e); } catch(ex) {}
			var msgArea = document.getElementById("messageArea");
			var n = msgArea.getElementsByTagName('div');
			if(!(n&&n.length)){
				msgArea.style.display = "none";
			}
		},
		fadeMessageBox: function(e)
		{
			var me = config.extensions.FadingMessages;
			if(config.options.chkAnimate && anim){
				anim.startAnimating(new me.Fader(e,me.clearMessageBox));
			}else{
				me.clearMessageBox(e);
			}
		},
		createClearAllButton: function(e)
		{
			return null;
		},
		createClearMessageButton: function(e)
		{
			var me = config.extensions.FadingMessages;
			return createTiddlyButton(createTiddlyElement(e,"span",null,"messageClear"),
				"×","",
				function(){me.clearMessageBox(e);});
		},
		_displayMessage: displayMessage,
		displayMessage: function(text,linkText)
		{
			var me = config.extensions.FadingMessages;
			var e = me._displayMessage(text,linkText);
			if(e){
				window.setTimeout(function(){me.fadeMessageBox(e);},config.options.txtFadingMessagesTimeout*1000);
			}
			return e;
		}
	};
 
	displayMessage = config.extensions.FadingMessages.displayMessage;
	config.extensions.WikifiedMessages.createClearMessageButton = config.extensions.FadingMessages.createClearMessageButton;
	config.extensions.WikifiedMessages.createClearAllButton = config.extensions.FadingMessages.createClearAllButton;
}
//}}}