Rayspot01 is loading ...

Requires Javascript.
Rayspot01 - a place to aggregate Big Issues material
<!--{{{-->
<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]];}

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

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

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

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

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

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

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

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

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

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

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

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

hr {height:1px;}

a {text-decoration:none;}

dt {font-weight:bold;}

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

.txtOptionInput {width:11em;}

#contentWrapper .chkOptionInput {border:0;}

.externalLink {text-decoration:underline;}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

.whenBackstage {display:none;}
.backstageVisible .whenBackstage {display:block;}
/*}}}*/
/***
StyleSheet for use when a translation requires any css style changes.
This StyleSheet can be used directly by languages such as Chinese, Japanese and Korean which need larger font sizes.
***/
/*{{{*/
body {font-size:0.8em;}
#sidebarOptions {font-size:1.05em;}
#sidebarOptions a {font-style:normal;}
#sidebarOptions .sliderPanel {font-size:0.95em;}
.subtitle {font-size:0.8em;}
.viewer table.listView {font-size:0.95em;}
/*}}}*/
/*{{{*/
@media print {
#mainMenu, #sidebar, #messageArea, .toolbar, #backstageButton, #backstageArea {display: none !important;}
#displayArea {margin: 1em 1em 0em;}
noscript {display:none;} /* Fixes a feature in Firefox 1.5.0.2 where print preview displays the noscript content */
}
/*}}}*/
<!--{{{-->
<div class='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>>
Test if update works from tablet using Firefox. 
!Big Data

Everyone is talking about it.

Its the latest Consultant's Gold Mine, in which false promises are made about how intelligent mining of the vast stores of data will unlock the essential advantage.

It figures in the latest disturbing chapters of The Adventures of The Whistleblowers who are crying out about the manner in which Governments are controlling their Peoples.

Big data is so big it is beginning to emerge as the biggest consumer of Energy.
!Suppressing Harassers

During rush hours where passenger have to squeeze one another like tuna cans to stay on board, now need not worry about being victims of harassment because safety officials have made their presence to protect passengers.

BANGKOK: -- ‘Victims’ of sexual harassment are not just female passengers but also female conductors (fare collectors boxes) that have been confronted with several deviant acts.

Bangkok Mass Transit Authority, together with the related project is creating a campaign to “Eliminate and provide sexual harassment free zone”

Time has arrived for passengers and fare collectors to receive serious protection against sexual harassment.

The 3 major sexual harassment cases are:

1. Sexual harassment among employees
2. Sexual harassment between employees and passengers.
3. Sexual harassment among passengers

Usually fare collectors are women and they unknowingly become victims of sexual harassment i.e verbally or by caressing and touching her clothing, hair, or body. These women are afraid to file complains because they are unsure of their safety and are reluctant about the consequences.

@@Usually female passengers are college students on female that dresses inappropriately and therefore gets picked at or teased with lines like “do you want go with me, pretty girl, are you here alone!”@@

The transportation department has set guidelines in promoting safety areas. These measures are set to protect passengers by providing a channel to receive complains deviant behavior.

At the moment there are 120 employees working as safety officer, these officers have been hired from fare collector’s position. The safety officials will be in the local buses as an eye for providing a safety environment. If a passenger has a complaint they could report if to safety officials at that very instant. From then on the safety officer will try and resolve the problem. The passenger report inappropriate behavior such as staring, pushing on even verbal communication.

Full story: http://www.pattayada...sing-harassers/

-- Pattaya Daily News 2013-08-24

!!!Comments: <<comment>>
<<notes heading:'Rays Notes'>>
This is a Tiddlywiki, hosted by Tiddlyspot.

Ray is using it as an experimental site, to learn a little about Tiddlywiki.

He is also using it as a repository for material relating to the phenomenon of @@Big Data@@.
Click <<slideShow button:'About Ray' style:'MyStyleSheet' repeat>> to start slideshow, then use Ctrl+ or Ctrl- to fit comfortably on your screen. You can discover simple controls near the bottom of the screen with your mouse.

-s-
!Ray has a lot of viewable content published on the web
[img[http://www.allraysworld.com/uploads/1/2/5/2/12527257/9609838.jpg?1362389794]]

# Extensive [[Homepage|http://allraysworld.com]]
# Numerous photoblogs:
** [[Daily photoblog of Thailand-sourced images|http://mainlythai.shutterchance.com]].
** [[Bi-daily photoblog of Bangkok-sourced images|http://bangkokwild.aminus3.com]].
** [[Images from all over|http://mainlythai.shutterchance.com]], posted frequently, but irregularly.

-s-

!A number of Ray's e-Books can be viewed on the web:
# [[Rays World|https://picasaweb.google.com/112193852814997284666/CoffeetableBook7RaySWorld2013]]
[img[http://www.allraysworld.com/uploads/1/2/5/2/12527257/423520943.jpg]]

-s-

!Writing

** There are several [[e-Books of short stories|http://www.allraysworld.com]] 
[img[http://www.allraysworld.com/uploads/1/2/5/2/12527257/4055762_orig.jpg]] 



-s-

!Ray welcomes interaction:
# eMail at raycastorey@gmail.com
# or, [[leave comments|http://www.allraysworld.com/dont-be-shy.html]] which I shall respond to.

-s-

! Please enjoy your visit.
!!This is a repository for miscellaneous articles.

This site also uses the following Tiddlywiki plugins, from 3rd part developers:
|!Plugin|!Description|!Usage|
|[[Tiddlyspot|http://tiddlyspot.com]]|Components that assist in upload/sync of off-line & on-line copies| |
|[[Splashscreen|http://www.tiddlytools.com]]|Provides something to look at while the site is loading in browser| |
|[[Slideshow|http://www.math.ist.utl.pt/~psoares/addons.html#Plugins]]|Enables full-screen display of simple slideshows|e.g. [[Introducing Ray Storey]]...hit F11 on the keyboard to see everything.|
|[[CommentPlugin|http://www.tiddlytools.com]]|To allow for feedback through a device at the bottom of a page|{{{!!!Comments: <<comment>>}}}|
|[[TiddlerNotesPlugin|http://tw.lewcid.org/#%5B%5BExtensions%20Overview%5D%5D]]|Allows notes to be appended to tiddlers|{{{<<notes heading:'Rays Notes'>>}}}|

It makes use of the following:
* {{{<<formTiddler NewArticleTemplate>>}}} to create a //new article// from a button in the right sidebar
* Tagging to list articles with something in common...major tags are:
|!Tag|!Example|!Meaning|
|9999|2008|Year article published|
|Abbbbb|NYTimes|Journal in which article was published|
|aaaaaaa|cycling|Subject...there can be several|
!Here are some Internet-sourced articles relating to BigData

|!Article|!Source|!Date|!Synopsis|
|http://www.theguardian.com/technology/2013/aug/23/nasdaq-crash-data|The Guardian|20130823|We cannot control Big Data|
|http://www.theguardian.com/technology/2013/aug/23/tech-giants-data|The Guardian|20130823|Big Data Farms|
|http://www.theguardian.com/business/2013/aug/23/spending-on-data-centres-reaches-150-billion-dollars|The Guardian|20130823|Google's Big Data Farms|
/***
|Name:|CloseOnCancelPlugin|
|Description:|Closes the tiddler if you click new tiddler then cancel. Default behaviour is to leave it open|
|Version:|3.0.1a|
|Date:|27-Jun-2011|
|Source:|http://mptw.tiddlyspot.com/#CloseOnCancelPlugin|
|Author:|Simon Baird <simon.baird@gmail.com>|
|License:|http://mptw.tiddlyspot.com/#TheBSDLicense|
***/
//{{{
merge(config.commands.cancelTiddler,{

  handler_mptw_orig_closeUnsaved: config.commands.cancelTiddler.handler,

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

});

//}}}
Name: MptwRed
Background: #fff
Foreground: #000
PrimaryPale: #eaa
PrimaryLight: #c55
PrimaryMid: #711
PrimaryDark: #500
SecondaryPale: #ffc
SecondaryLight: #fe8
SecondaryMid: #db4
SecondaryDark: #841
TertiaryPale: #eee
TertiaryLight: #ccc
TertiaryMid: #999
TertiaryDark: #666
Error: #f88

/***
|Name|CommentPlugin|
|Source|http://www.TiddlyTools.com/#CommentPlugin|
|Documentation|http://www.TiddlyTools.com/#CommentPluginInfo|
|Version|2.9.0|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|plugin|
|Requires||
|Overrides||
|Description|automatically insert formatted comments into tiddler content|
!!!!!Documentation
>see [[CommentPluginInfo]]
!!!!!Configuration
>see [[CommentPluginInfo]]
!!!!!Revisions
<<<
2008.05.17 [2.9.0] optional 'overwrite' param replaces existing comment when stored as separate tiddler
| please see [[CommentPluginInfo]] for previous revision details |
2006.04.20 [1.0.0] initial release
<<<
!!!!!Code
***/
//{{{
version.extensions.CommentPlugin= {major: 2, minor: 9, revision: 0, date: new Date(2008,5,17)};

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

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

Note: as of revision 2.0.0, dependencies on [[NestedSlidersPlugin]], [[MoveablePanelPlugin]], [[InlineJavascriptPlugin]] and [[ExpandSlidersScript]] have been eliminated.  As a result, the comment form and generated comment output are no longer automatically contained within sliders and the "view all/close all" command is not automatically included.  To recreate the previous output format and comment interface, use the following syntax in the tiddler in which you want to place your comments:
{{{
+++^40em^[add a note]...
<<moveablePanel>>add a note
----
<<comment here "" "+++!!!!![%when% (%who%): %subject%]>...\n%message%\n===\n">>===
 | <<tiddler ExpandSlidersScript with: here "view all" "close all">>
}}}
<<<
!!!!!Revisions
<<<
2008.05.17 [2.9.0] added support for optional 'overwrite' macro param to replace existing comment (for use when comment is stored as separate tiddler)
2008.04.21 [2.8.0] replaced use of %n markers with special 'named' markers: %tiddler%, %UTC%, %random%, %who%, %when%, %subject% and %message% to avoid conflict with TW core processing of tiddler content.  Also, added support for 'reverse' macro param.
2008.04.17 [2.7.0] added support for constructing target by inserting UTC timestamp, random number, username and/or subject text into target tiddler title
2008.04.15 [2.6.0] added support for custom format and dateformat parameters to override global default formats
2008.04.15 [2.5.1] make sure tiddlers are displayed before attempting to refresh them
2008.04.15 [2.5.0] refresh tiddler containing comment macro after adding new comment to target tiddler (if different)
2008.04.14 [2.4.0] added optional tag list parameter for tagging the target tiddler when comments are written
2008.04.14 [2.3.0] if %2 (subject) or %3 (message) are omitted from format string, suppress display and validation of corresponding form elements.
2008.04.13 [2.2.0] added optional ~TiddlerName param to specify target tiddler for writing comments
2008.04.10 [2.1.0] converted from inline script to plugin
2008.04.05 [2.0.0] removed dependencies on NestedSlidersPlugin, MoveablePanelPlugin, ExpandSlidersScript
2007.10.24 [1.2.0] added config.options.txtCommentDateFormat
2007.07.05 [1.1.0] added 'view all/close all' toolbar item plus code cleanup
2007.06.28 [1.0.2] added tiddler.fields to saveTiddler() call (preserves custom fields)
2007.05.26 [1.0.1] added support for optional 'reverse' keyword.
2006.04.20 [1.0.0] initial release
<<<
config.macros.comment.reverse=false;
config.macros.comment.fmt="__''%subject%''__\n^^posted by %who% on %when%^^\n<<<\n%message%\n<<<\n";
config.macros.comment.datefmt="DDD, MMM DDth, YYYY at hh12:0mm:0ss am";
/***
|''Name:''|DataTiddlerPlugin|
|''Version:''|1.0.6 (2006-08-26)|
|''Source:''|http://tiddlywiki.abego-software.de/#DataTiddlerPlugin|
|''Author:''|UdoBorkowski (ub [at] abego-software [dot] de)|
|''Licence:''|[[BSD open source license]]|
|''TiddlyWiki:''|1.2.38+, 2.0|
|''Browser:''|Firefox 1.0.4+; InternetExplorer 6.0|
!Description
Enhance your tiddlers with structured data (such as strings, booleans, numbers, or even arrays and compound objects) that can be easily accessed and modified through named fields (in JavaScript code).

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

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




''Access and Modify Tiddler Data''

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

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

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


''Data Representation in a Tiddler''

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

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

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

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

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


''Saving Changes''

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


''Notifications''

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

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


''The showData Macro''

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

''Syntax:'' 
|>|{{{<<}}}''showData '' [''JSON''] [//tiddlerName//] {{{>>}}}|
|''JSON''|By default the data is rendered as a table with a "Name" and "Value" column. When defining ''JSON'' the data is rendered in JSON format|
|//tiddlerName//|Defines the tiddler holding the data to be displayed. When no tiddler is given the tiddler containing the showData macro is used. When the tiddler name contains spaces you must quote the name (or use the {{{[[...]]}}} syntax.)|
|>|~~Syntax formatting: Keywords in ''bold'', optional parts in [...]. 'or' means that exactly one of the two alternatives must exist.~~|


!Revision history
* v1.0.6 (2006-08-26) 
** Removed misleading comment
* v1.0.5 (2006-02-27) (Internal Release Only)
** Internal
*** Make "JSLint" conform
* v1.0.4 (2006-02-05)
** Bugfix: showData fails in TiddlyWiki 2.0
* v1.0.3 (2006-01-06)
** Support TiddlyWiki 2.0
* v1.0.2 (2005-12-22)
** Enhancements:
*** Handle texts "<data>" or "</data>" more robust when used in a tiddler text or as a field value.
*** Improved (JSON) error messages.
** Bugs fixed: 
*** References are not updated when using the DataTiddler.
*** Changes to compound objects are not always saved.
*** "~</data>" is not rendered correctly (expected "</data>")
* v1.0.1 (2005-12-13)
** Features: 
*** The showData macro supports an optional "tiddlername" argument to specify the tiddler containing the data to be displayed
** Bugs fixed: 
*** A script immediately following a data section is deleted when the data is changed. (Thanks to GeoffS for reporting.)
* v1.0.0 (2005-12-12)
** initial version

!Code
***/
//{{{
//============================================================================
//============================================================================
//                           DataTiddlerPlugin
//============================================================================
//============================================================================

// Ensure that the DataTiddler Plugin is only installed once.
//
if (!version.extensions.DataTiddlerPlugin) {



version.extensions.DataTiddlerPlugin = {
    major: 1, minor: 0, revision: 6,
    date: new Date(2006, 7, 26), 
    type: 'plugin',
    source: "http://tiddlywiki.abego-software.de/#DataTiddlerPlugin"
};

// For backward compatibility with v1.2.x
//
if (!window.story) window.story=window; 
if (!TiddlyWiki.prototype.getTiddler) {
	TiddlyWiki.prototype.getTiddler = function(title) { 
		var t = this.tiddlers[title]; 
		return (t !== undefined && t instanceof Tiddler) ? t : null; 
	};
}

//============================================================================
// DataTiddler Class
//============================================================================

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

function DataTiddler() {
}

DataTiddler = {
    // Function to stringify a JavaScript value, producing the text for the data section content.
    // (Must match the implementation of DataTiddler.parse.)
    //
    stringify : null,
    

    // Function to parse the text for the data section content, producing a JavaScript value.
    // (Must match the implementation of DataTiddler.stringify.)
    //
    parse : null
};

// Ensure access for IE
window.DataTiddler = DataTiddler;

// ---------------------------------------------------------------------------
// Data Accessor and Mutator
// ---------------------------------------------------------------------------


// Returns the value of the given data field of the tiddler.
// When no such field is defined or its value is undefined
// the defaultValue is returned.
// 
// @param tiddler either a tiddler name or a tiddler
//
DataTiddler.getData = function(tiddler, field, defaultValue) {
    var t = (typeof tiddler == "string") ? store.getTiddler(tiddler) : tiddler;
    if (!(t instanceof Tiddler)) {
        throw "Tiddler expected. Got "+tiddler;
    }

    return DataTiddler.getTiddlerDataValue(t, field, defaultValue);
};


// Sets the value of the given data field of the tiddler to
// the value. When the value is equal to the defaultValue
// no value is set (and the field is removed)
//
// Changing data of a tiddler will not trigger notifications.
// 
// @param tiddler either a tiddler name or a tiddler
//
DataTiddler.setData = function(tiddler, field, value, defaultValue) {
    var t = (typeof tiddler == "string") ? store.getTiddler(tiddler) : tiddler;
    if (!(t instanceof Tiddler)) {
        throw "Tiddler expected. Got "+tiddler+ "("+t+")";
    }

    DataTiddler.setTiddlerDataValue(t, field, value, defaultValue);
};


// Returns the data object of the tiddler, with a property for every field.
//
// The properties of the returned data object may only be read and
// not be modified. To modify the data use DataTiddler.setData(...) 
// or the corresponding Tiddler method.
//
// If no data section is defined a new (empty) object is returned.
//
// @param tiddler either a tiddler name or a Tiddler
//
DataTiddler.getDataObject = function(tiddler) {
    var t = (typeof tiddler == "string") ? store.getTiddler(tiddler) : tiddler;
    if (!(t instanceof Tiddler)) {
        throw "Tiddler expected. Got "+tiddler;
    }

    return DataTiddler.getTiddlerDataObject(t);
};

// Returns the text of the content of the data section of the tiddler.
//
// When no data section is defined for the tiddler null is returned 
//
// @param tiddler either a tiddler name or a Tiddler
// @return [may be null]
//
DataTiddler.getDataText = function(tiddler) {
    var t = (typeof tiddler == "string") ? store.getTiddler(tiddler) : tiddler;
    if (!(t instanceof Tiddler)) {
        throw "Tiddler expected. Got "+tiddler;
    }

    return DataTiddler.readDataSectionText(t);
};


// ---------------------------------------------------------------------------
// Internal helper methods (must not be used by code from outside this plugin)
// ---------------------------------------------------------------------------

// Internal.
//
// The original JSONError is not very user friendly, 
// especially it does not define a toString() method
// Therefore we extend it here.
//
DataTiddler.extendJSONError = function(ex) {
	if (ex.name == 'JSONError') {
        ex.toString = function() {
			return ex.name + ": "+ex.message+" ("+ex.text+")";
		};
	}
	return ex;
};

// Internal.
//
// @param t a Tiddler
//
DataTiddler.getTiddlerDataObject = function(t) {
    if (t.dataObject === undefined) {
        var data = DataTiddler.readData(t);
        t.dataObject = (data) ? data : {};
    }
    
    return t.dataObject;
};


// Internal.
//
// @param tiddler a Tiddler
//
DataTiddler.getTiddlerDataValue = function(tiddler, field, defaultValue) {
    var value = DataTiddler.getTiddlerDataObject(tiddler)[field];
    return (value === undefined) ? defaultValue : value;
};


// Internal.
//
// @param tiddler a Tiddler
//
DataTiddler.setTiddlerDataValue = function(tiddler, field, value, defaultValue) {
    var data = DataTiddler.getTiddlerDataObject(tiddler);
    var oldValue = data[field];
	
    if (value == defaultValue) {
        if (oldValue !== undefined) {
            delete data[field];
            DataTiddler.save(tiddler);
        }
        return;
    }
    data[field] = value;
    DataTiddler.save(tiddler);
};

// Internal.
//
// Reads the data section from the tiddler's content and returns its text
// (as a String).
//
// Returns null when no data is defined.
//
// @param tiddler a Tiddler
// @return [may be null]
//
DataTiddler.readDataSectionText = function(tiddler) {
    var matches = DataTiddler.getDataTiddlerMatches(tiddler);
    if (matches === null || !matches[2]) {
        return null;
    }
    return matches[2];
};

// Internal.
//
// Reads the data section from the tiddler's content and returns it
// (as an internalized object).
//
// Returns null when no data is defined.
//
// @param tiddler a Tiddler
// @return [may be null]
//
DataTiddler.readData = function(tiddler) {
    var text = DataTiddler.readDataSectionText(tiddler);
	try {
	    return text ? DataTiddler.parse(text) : null;
	} catch(ex) {
		throw DataTiddler.extendJSONError(ex);
	}
};

// Internal.
// 
// Returns the serialized text of the data of the given tiddler, as it
// should be stored in the data section.
//
// @param tiddler a Tiddler
//
DataTiddler.getDataTextOfTiddler = function(tiddler) {
    var data = DataTiddler.getTiddlerDataObject(tiddler);
    return DataTiddler.stringify(data);
};


// Internal.
// 
DataTiddler.indexOfNonEscapedText = function(s, subString, startIndex) {
	var index = s.indexOf(subString, startIndex);
	while ((index > 0) && (s[index-1] == '~')) { 
		index = s.indexOf(subString, index+1);
	}
	return index;
};

// Internal.
//
DataTiddler.getDataSectionInfo = function(text) {
	// Special care must be taken to handle "<data>" and "</data>" texts inside
	// a data section. 
	// Also take care not to use an escaped <data> (i.e. "~<data>") as the start 
	// of a data section. (Same for </data>)

    // NOTE: we are explicitly searching for a data section that contains a JSON
    // string, i.e. framed with braces. This way we are little bit more robust in
    // case the tiddler contains unescaped texts "<data>" or "</data>". This must
    // be changed when using a different stringifier.

	var startTagText = "<data>{";
	var endTagText = "}</data>";

	var startPos = 0;

	// Find the first not escaped "<data>".
	var startDataTagIndex = DataTiddler.indexOfNonEscapedText(text, startTagText, 0);
	if (startDataTagIndex < 0) {
		return null;
	}

	// Find the *last* not escaped "</data>".
	var endDataTagIndex = text.indexOf(endTagText, startDataTagIndex);
	if (endDataTagIndex < 0) {
		return null;
	}
	var nextEndDataTagIndex;
	while ((nextEndDataTagIndex = text.indexOf(endTagText, endDataTagIndex+1)) >= 0) {
		endDataTagIndex = nextEndDataTagIndex;
	}

	return {
		prefixEnd: startDataTagIndex, 
		dataStart: startDataTagIndex+(startTagText.length)-1, 
		dataEnd: endDataTagIndex, 
		suffixStart: endDataTagIndex+(endTagText.length)
	};
};

// Internal.
// 
// Returns the "matches" of a content of a DataTiddler on the
// "data" regular expression. Return null when no data is defined
// in the tiddler content.
//
// Group 1: text before data section (prefix)
// Group 2: content of data section
// Group 3: text behind data section (suffix)
//
// @param tiddler a Tiddler
// @return [may be null] null when the tiddler contains no data section, otherwise see above.
//
DataTiddler.getDataTiddlerMatches = function(tiddler) {
	var text = tiddler.text;
	var info = DataTiddler.getDataSectionInfo(text);
	if (!info) {
		return null;
	}

	var prefix = text.substr(0,info.prefixEnd);
	var data = text.substr(info.dataStart, info.dataEnd-info.dataStart+1);
	var suffix = text.substr(info.suffixStart);
	
	return [text, prefix, data, suffix];
};


// Internal.
//
// Saves the data in a <data> block of the given tiddler (as a minor change). 
//
// The "chkAutoSave" and "chkForceMinorUpdate" options are respected. 
// I.e. the TiddlyWiki *file* is only saved when AutoSave is on.
//
// Notifications are not send. 
//
// This method should only be called when the data really has changed. 
//
// @param tiddler
//             the tiddler to be saved.
//
DataTiddler.save = function(tiddler) {

    var matches = DataTiddler.getDataTiddlerMatches(tiddler);

    var prefix;
    var suffix;
    if (matches === null) {
        prefix = tiddler.text;
        suffix = "";
    } else {
        prefix = matches[1];
        suffix = matches[3];
    }

    var dataText = DataTiddler.getDataTextOfTiddler(tiddler);
    var newText = 
            (dataText !== null) 
                ? prefix + "<data>" + dataText + "</data>" + suffix
                : prefix + suffix;
    if (newText != tiddler.text) {
        // make the change in the tiddlers text
        
        // ... see DataTiddler.MyTiddlerChangedFunction
        tiddler.isDataTiddlerChange = true;
        
        // ... do the action change
        tiddler.set(
                tiddler.title,
                newText,
                config.options.txtUserName, 
                config.options.chkForceMinorUpdate? undefined : new Date(),
                tiddler.tags);

        // ... see DataTiddler.MyTiddlerChangedFunction
        delete tiddler.isDataTiddlerChange;

        // Mark the store as dirty.
        store.dirty = true;
 
        // AutoSave if option is selected
        if(config.options.chkAutoSave) {
           saveChanges();
        }
    }
};

// Internal.
//
DataTiddler.MyTiddlerChangedFunction = function() {
    // Remove the data object from the tiddler when the tiddler is changed
    // by code other than DataTiddler code. 
    //
    // This is necessary since the data object is just a "cached version" 
    // of the data defined in the data section of the tiddler and the 
    // "external" change may have changed the content of the data section.
    // Thus we are not sure if the data object reflects the data section 
    // contents. 
    // 
    // By deleting the data object we ensure that the data object is 
    // reconstructed the next time it is needed, with the data defined by
    // the data section in the tiddler's text.
    
    // To indicate that a change is a "DataTiddler change" a temporary
    // property "isDataTiddlerChange" is added to the tiddler.
    if (this.dataObject && !this.isDataTiddlerChange) {
        delete this.dataObject;
    }
    
    // call the original code.
	DataTiddler.originalTiddlerChangedFunction.apply(this, arguments);
};


//============================================================================
// Formatters
//============================================================================

// This formatter ensures that "~<data>" is rendered as "<data>". This is used to 
// escape the "<data>" of a data section, just in case someone really wants to use
// "<data>" as a text in a tiddler and not start a data section.
//
// Same for </data>.
//
config.formatters.push( {
    name: "data-escape",
    match: "~<\\/?data>",

    handler: function(w) {
            w.outputText(w.output,w.matchStart + 1,w.nextMatch);
    }
} );


// This formatter ensures that <data>...</data> sections are not rendered.
//
config.formatters.push( {
    name: "data",
    match: "<data>",

    handler: function(w) {
		var info = DataTiddler.getDataSectionInfo(w.source);
		if (info && info.prefixEnd == w.matchStart) {
            w.nextMatch = info.suffixStart;
		} else {
			w.outputText(w.output,w.matchStart,w.nextMatch);
		}
    }
} );


//============================================================================
// Tiddler Class Extension
//============================================================================

// "Hijack" the changed method ---------------------------------------------------

DataTiddler.originalTiddlerChangedFunction = Tiddler.prototype.changed;
Tiddler.prototype.changed = DataTiddler.MyTiddlerChangedFunction;

// Define accessor methods -------------------------------------------------------

// Returns the value of the given data field of the tiddler. When no such field 
// is defined or its value is undefined the defaultValue is returned.
//
// When field is undefined (or null) the data object is returned. (See 
// DataTiddler.getDataObject.)
//
// @param field [may be null, undefined]
// @param defaultValue [may be null, undefined]
// @return [may be null, undefined]
//
Tiddler.prototype.data = function(field, defaultValue) {
    return (field) 
         ? DataTiddler.getTiddlerDataValue(this, field, defaultValue)
         : DataTiddler.getTiddlerDataObject(this);
};

// Sets the value of the given data field of the tiddler to the value. When the 
// value is equal to the defaultValue no value is set (and the field is removed).
//
// @param value [may be null, undefined]
// @param defaultValue [may be null, undefined]
//
Tiddler.prototype.setData = function(field, value, defaultValue) {
    DataTiddler.setTiddlerDataValue(this, field, value, defaultValue);
};


//============================================================================
// showData Macro
//============================================================================

config.macros.showData = {
     // Standard Properties
     label: "showData",
     prompt: "Display the values stored in the data section of the tiddler"
};

config.macros.showData.handler = function(place,macroName,params) {
    // --- Parsing ------------------------------------------

    var i = 0; // index running over the params
    // Parse the optional "JSON"
    var showInJSONFormat = false;
    if ((i < params.length) && params[i] == "JSON") {
        i++;
        showInJSONFormat = true;
    }
    
    var tiddlerName = story.findContainingTiddler(place).id.substr(7);
    if (i < params.length) {
        tiddlerName = params[i];
        i++;
    }

    // --- Processing ------------------------------------------
    try {
        if (showInJSONFormat) {
            this.renderDataInJSONFormat(place, tiddlerName);
        } else {
            this.renderDataAsTable(place, tiddlerName);
        }
    } catch (e) {
        this.createErrorElement(place, e);
    }
};

config.macros.showData.renderDataInJSONFormat = function(place,tiddlerName) {
    var text = DataTiddler.getDataText(tiddlerName);
    if (text) {
        createTiddlyElement(place,"pre",null,null,text);
    }
};

config.macros.showData.renderDataAsTable = function(place,tiddlerName) {
    var text = "|!Name|!Value|\n";
    var data = DataTiddler.getDataObject(tiddlerName);
    if (data) {
        for (var i in data) {
            var value = data[i];
            text += "|"+i+"|"+DataTiddler.stringify(value)+"|\n";
        }
    }
    
    wikify(text, place);
};


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

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


} // of "install only once"
// Used Globals (for JSLint) ==============

// ... TiddlyWiki Core
/*global 	createTiddlyElement, saveChanges, store, story, wikify */
// ... DataTiddler
/*global 	DataTiddler */
// ... JSON
/*global 	JSON */
			

/***
!JSON Code, used to serialize the data
***/
/*
Copyright (c) 2005 JSON.org

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The Software shall be used for Good, not Evil.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/

/*
    The global object JSON contains two methods.

    JSON.stringify(value) takes a JavaScript value and produces a JSON text.
    The value must not be cyclical.

    JSON.parse(text) takes a JSON text and produces a JavaScript value. It will
    throw a 'JSONError' exception if there is an error.
*/
var JSON = {
    copyright: '(c)2005 JSON.org',
    license: 'http://www.crockford.com/JSON/license.html',
/*
    Stringify a JavaScript value, producing a JSON text.
*/
    stringify: function (v) {
        var a = [];

/*
    Emit a string.
*/
        function e(s) {
            a[a.length] = s;
        }

/*
    Convert a value.
*/
        function g(x) {
            var c, i, l, v;

            switch (typeof x) {
            case 'object':
                if (x) {
                    if (x instanceof Array) {
                        e('[');
                        l = a.length;
                        for (i = 0; i < x.length; i += 1) {
                            v = x[i];
                            if (typeof v != 'undefined' &&
                                    typeof v != 'function') {
                                if (l < a.length) {
                                    e(',');
                                }
                                g(v);
                            }
                        }
                        e(']');
                        return;
                    } else if (typeof x.toString != 'undefined') {
                        e('{');
                        l = a.length;
                        for (i in x) {
                            v = x[i];
                            if (x.hasOwnProperty(i) &&
                                    typeof v != 'undefined' &&
                                    typeof v != 'function') {
                                if (l < a.length) {
                                    e(',');
                                }
                                g(i);
                                e(':');
                                g(v);
                            }
                        }
                        return e('}');
                    }
                }
                e('null');
                return;
            case 'number':
                e(isFinite(x) ? +x : 'null');
                return;
            case 'string':
                l = x.length;
                e('"');
                for (i = 0; i < l; i += 1) {
                    c = x.charAt(i);
                    if (c >= ' ') {
                        if (c == '\\' || c == '"') {
                            e('\\');
                        }
                        e(c);
                    } else {
                        switch (c) {
                            case '\b':
                                e('\\b');
                                break;
                            case '\f':
                                e('\\f');
                                break;
                            case '\n':
                                e('\\n');
                                break;
                            case '\r':
                                e('\\r');
                                break;
                            case '\t':
                                e('\\t');
                                break;
                            default:
                                c = c.charCodeAt();
                                e('\\u00' + Math.floor(c / 16).toString(16) +
                                    (c % 16).toString(16));
                        }
                    }
                }
                e('"');
                return;
            case 'boolean':
                e(String(x));
                return;
            default:
                e('null');
                return;
            }
        }
        g(v);
        return a.join('');
    },
/*
    Parse a JSON text, producing a JavaScript value.
*/
    parse: function (text) {
        var p = /^\s*(([,:{}\[\]])|"(\\.|[^\x00-\x1f"\\])*"|-?\d+(\.\d*)?([eE][+-]?\d+)?|true|false|null)\s*/,
            token,
            operator;

        function error(m, t) {
            throw {
                name: 'JSONError',
                message: m,
                text: t || operator || token
            };
        }

        function next(b) {
            if (b && b != operator) {
                error("Expected '" + b + "'");
            }
            if (text) {
                var t = p.exec(text);
                if (t) {
                    if (t[2]) {
                        token = null;
                        operator = t[2];
                    } else {
                        operator = null;
                        try {
                            token = eval(t[1]);
                        } catch (e) {
                            error("Bad token", t[1]);
                        }
                    }
                    text = text.substring(t[0].length);
                } else {
                    error("Unrecognized token", text);
                }
            } else {
                token = operator = undefined;
            }
        }


        function val() {
            var k, o;
            switch (operator) {
            case '{':
                next('{');
                o = {};
                if (operator != '}') {
                    for (;;) {
                        if (operator || typeof token != 'string') {
                            error("Missing key");
                        }
                        k = token;
                        next();
                        next(':');
                        o[k] = val();
                        if (operator != ',') {
                            break;
                        }
                        next(',');
                    }
                }
                next('}');
                return o;
            case '[':
                next('[');
                o = [];
                if (operator != ']') {
                    for (;;) {
                        o.push(val());
                        if (operator != ',') {
                            break;
                        }
                        next(',');
                    }
                }
                next(']');
                return o;
            default:
                if (operator !== null) {
                    error("Missing value");
                }
                k = token;
                next();
                return k;
            }
        }
        next();
        return val();
    }
};

/***
!Setup the data serialization
***/

DataTiddler.format = "JSON";
DataTiddler.stringify = JSON.stringify;
DataTiddler.parse = JSON.parse;

//}}}
[[AboutRay]]
Evolution of a big data environment: How storage options are changing
Sarah Wilson 20130904

With more enterprises needing to store growing volumes of data, storage vendors and administrators alike need to determine the best practices for storage in a big data environment. With this in mind, we're hearing more and more about things such as Hadoop and the cloud. But according to Jon Toigo, chief principal partner at Toigo Partners International, those methods aren't necessarily best for a big data environment.

In this podcast, Toigo discussed the evolution of the storage market with regard to big data with associate site editor Sarah Wilson. Listen to the audio or read the transcript below to find out his thoughts on how storage, the cloud, and backup and disaster recovery might adapt for a big data environment.

''How do you think the storage market is evolving to better accommodate big data?''

Jon Toigo: Well, I think you're seeing two different trends here. One is that Hadoop is sort of joined at the hip with the concept of big data. We're talking about Hadoop-style clustering. The industry is basically dissing shared storage at this point -- SAN [storage area network] and NAS [network-attached storage] -- and preferring direct-attached storage [DAS], particularly DAS that uses flash. IBM has gone up on stage -- the director of their storage group -- and they've specifically said, 'We see flash as the future of everything.' So they're trying to push flash-based storage, direct-attached to clustered units as the modality for storing data that will be used for big data analytics. I don't know [if] that's the best approach to do this stuff, and I think we're going to find out and we're going to spend a ton of money on it. It sets the clock back to pre-1999 in terms of storage architecture and it re-introduces issues that we had two decades ago and currently have forgotten about regarding how you protect your data in a world of isolated islands of storage. You're going to have to have a whole lot of replication going on from one node to another in order to find out how much bandwidth that's going to utilize to provide protection to isolated storage components. It does, however, sell more gear, which is something the industry likes to see given the general trends toward slowing storage sales.

The other side of the house is trying to look at this from a holistic perspective. They're saying, 'We spent the last ten years deploying shared storage, deploying Fibre Channel fabrics. We had the potential to grow that technology going forward in significant directions, whether it was using InfiniBand, or SAS, or whatever the next generation of that is going to be. But why would we want to aggregate all our stuff for ten years and then segregate it again?' It doesn't make any sense. So you look at companies like DataCore Software, or to some extent IBM with SAN Volume Controller, and a few others who are trying to virtualize that storage infrastructure so they can present virtual volumes up to the servers that pretend or behave as though they're direct-attached storage for those servers. That makes a heck of a lot more sense and also gives you the ability to manage holistically all the infrastructure that's associated with storage. And I think a lot more work needs to be done in that space rather than segregating all the storage and doing a bunch of direct attachment on a bunch of servers. And I think we're eventually going to get to that latter model.

''Cloud seems to be a popular option for storage in a big data environment, too. Do you think cloud providers are adapting their services to work better with large volumes of data?''

Toigo: You know, I have a mixed mind as far as clouds go. I'm not a big advocate of cloud technology generally -- of the public variety. However, I did think that maybe one of the better models for cloud going forward -- a sustainable business model for cloud, would be cloud that is specialized in holding huge repositories of certain kinds of data. I asked experts about this. Jeff Jonas at IBM, I asked him, would it make sense for a cloud service provider to stand up big data so I don't have to buy the infrastructure myself? And I thought that might make sense for a company that doesn't want to spend big bucks on the infrastructure to support Hadoop for a business analysis project that's only going to be used once, or very infrequently, like voter registration analysis. Why would you want to stand up a multi-million dollar infrastructure to analyze one aspect of data and then go home and basically turn it off? It doesn't make any sense to me.

[Jonas] didn't think much about that idea though, and I was kind of scratching my head about that, but he explained his view. He said the amount of time it takes to position data in a cloud, and then the bandwidth that you have to pay for to get access to the data in the cloud, and then the initial security issues, resiliency issues associated with data and the cloud, and many other aspects of cloud operations are not necessarily the best places to host data for big data analytics.

Now, I think that, assuming some of these problems can be worked out, and that's a big assumption, you might find a cloud provider that says, 'We handle all the data for the national institute that has all the treatment data for oncology for cancer treatment. We've properly taken out all references to the patients themselves, and the original data is all here.' Now if Johns Hopkins wants to run a big data analysis on a new drug trial they're doing, they should be able to, as a service, plug into that data set and include it in their analytical model. And that would make sense, because then you've got multiple customers in need of that kind of data.

Would I put my own data up in a cloud? Probably not. I don't today, and I wouldn't going forward because a cloud service provider is hampered by the fact that he doesn't own the network that provides the connectivity to my shop. So how can he with a straight face promise me a service level? He doesn't control the mechanism by which I access the server. If my phone system goes up and down several times a month, it doesn't matter if I have a super stable cloud service or not, I'm not going to be able to access it. So I don't understand why I believe anything a cloud service provider tells me. I have a hard time believing my information is secure if it's in the cloud. Now that may not be a big issue if I adopt some sort of one-way hash like [IBM's Jonas has suggested] and I depersonalized all the data that's up there and I don't have anything to worry about. But for my business processes that are mission-critical and for my business transactions, my financial information, credit card information, whatever, I'm sure as heck not going to put it up there. Bottom line: I have issues with cloud and I'm not sure it's everything it's made out to be. Also, [on] the numbers on cloud -- I read an article recently that said there was a 340% increase in cloud adoption, but it was 19 people they had in the survey.

''How do backup and disaster recovery methods change in a big data environment?''

Toigo: If you follow the Hadoop model, which is basically to break up your shared storage and deploy it on individual nodes and direct-attached storage modalities, you run into a huge, huge problem with how you're going to replicate and safeguard that data. That's a major issue. We're already encountering that in shops that have adopted VMware, because VMware doesn't perform well at all with traditional shared storage modalities. What VMware is asking you to do is break up your SAN and deploy your storage in direct-attached configurations right next to each VMware server in the cluster. That creates an issue where you have to rely on back-end replication and mirroring from one box to another, and the problem with mirrors is nobody ever checks them. It's a pain to shut a mirror down, quiesce the application, flush the data out of the cache onto the disk, copy that disk over to the secondary mirror, and then shut the whole operation down and do a file-by-file compare, and then cross your fingers and restart everything and pray to God that you don't have a career-limiting event where things won't synchronize again. For that reason, nobody ever checks mirrors. And that's a key Achilles' heel of the way big data is architected over Hadoop.

Now, I will say that using big data analytics to model and monitor expansive storage infrastructure where I've got a whole lot of information in tidbits coming in from things like smart technology on disk and various element managers on the various sets of storage components that I've got out there -- being able to correlate all that and spot problems in real time or be proactive, I'd actually be able to avoid a lot of disasters. So on one hand, I like big data for what it can offer from a better disaster recovery standpoint, giving me better information and management of the infrastructure so I can avoid those kinds of risks. On the other hand, I don't like what Hadoop infrastructure means in terms of complicating my life from a standpoint of data protection.
/***
|Name:|ExtentTagButtonPlugin|
|Description:|Adds a New tiddler button in the tag drop down|
|Version:|3.2a|
|Date:|27-Jun-2011|
|Source:|http://mptw.tiddlyspot.com/#ExtendTagButtonPlugin|
|Author:|Simon Baird <simon.baird@gmail.com>|
|License|http://mptw.tiddlyspot.com/#TheBSDLicense|
***/
//{{{

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

//}}}
[img[http://www.finextra.com/finextra-images/top_pics/5323.jpg]]
''Fiserv taps big data for predictive modelling''
Fiserv has unveiled a customer behaviour predictive modelling system designed to help banks tap into big data and boost their marketing efforts. Using patented and patent-pending models, Predictive Scores promises to provide insights from multiple, complex data sets to give banks timely, actionable information that can be used for marketing and performance management.

The vendor says that its technology harnesses multi-channel transaction data - from account processing, debit and credit cards, online and mobile banking, and electronic bill pay systems - to "reveal crucial propensities or probabilities" that affect business growth. 

The data can then boost response rates and returns on investments for marketing campaigns; improve mobile banking take up; and help identify the highest-value prospective customers. 

Danny Baker, VP, financial and risk management solutions, Fiserv, says: "The unique combination of data science and big data is what sets our solution apart. It provides financial institutions with extremely valuable insights that can lower their direct marketing production costs - by almost 50 percent for some clients."
/***
|Name|FontSizePlugin|
|Created by|SaqImtiaz|
|Location|http://tw.lewcid.org/#FontSizePlugin|
|Version|1.0|
|Requires|~TW2.x|
!Description:
Resize tiddler text on the fly. The text size is remembered between sessions by use of a cookie.
You can customize the maximum and minimum allowed sizes.
(only affects tiddler content text, not any other text)

Also, you can load a TW file with a font-size specified in the url.
Eg: http://tw.lewcid.org/#font:110

!Demo:
Try using the font-size buttons in the sidebar, or in the MainMenu above.

!Installation:
Copy the contents of this tiddler to your TW, tag with systemConfig, save and reload your TW.
Then put {{{<<fontSize "font-size:">>}}} in your SideBarOptions tiddler, or anywhere else that you might like.

!Usage
{{{<<fontSize>>}}} results in <<fontSize>>
{{{<<fontSize font-size: >>}}} results in <<fontSize font-size:>>

!Customizing:
The buttons and prefix text are wrapped in a span with class fontResizer, for easy css styling.
To change the default font-size, and the maximum and minimum font-size allowed, edit the config.fontSize.settings section of the code below.

!Notes:
This plugin assumes that the initial font-size is 100% and then increases or decreases the size by 10%. This stepsize of 10% can also be customized.

!History:
*27-07-06, version 1.0 : prevented double clicks from triggering editing of containing tiddler.
*25-07-06,  version 0.9

!Code
***/

//{{{
config.fontSize={};

//configuration settings
config.fontSize.settings =
{
            defaultSize : 100,  // all sizes in %
            maxSize : 200,
            minSize : 40,
            stepSize : 10
};

//startup code
var fontSettings = config.fontSize.settings;

if (!config.options.txtFontSize)
            {config.options.txtFontSize = fontSettings.defaultSize;
            saveOptionCookie("txtFontSize");}
setStylesheet(".tiddler .viewer {font-size:"+config.options.txtFontSize+"%;}\n","fontResizerStyles");
setStylesheet("#contentWrapper .fontResizer .button {display:inline;font-size:105%; font-weight:bold; margin:0 1px; padding: 0 3px; text-align:center !important;}\n .fontResizer {margin:0 0.5em;}","fontResizerButtonStyles");

//macro
config.macros.fontSize={};
config.macros.fontSize.handler = function (place,macroName,params,wikifier,paramString,tiddler)
{

               var sp = createTiddlyElement(place,"span",null,"fontResizer");
               sp.ondblclick=this.onDblClick;
               if (params[0])
                           createTiddlyText(sp,params[0]);
               createTiddlyButton(sp,"+","increase font-size",this.incFont);
               createTiddlyButton(sp,"=","reset font-size",this.resetFont);
               createTiddlyButton(sp,"–","decrease font-size",this.decFont);
}

config.macros.fontSize.onDblClick = function (e)
{
             if (!e) var e = window.event;
             e.cancelBubble = true;
             if (e.stopPropagation) e.stopPropagation();
             return false;
}

config.macros.fontSize.setFont = function ()
{
               saveOptionCookie("txtFontSize");
               setStylesheet(".tiddler .viewer {font-size:"+config.options.txtFontSize+"%;}\n","fontResizerStyles");
}

config.macros.fontSize.incFont=function()
{
               if (config.options.txtFontSize < fontSettings.maxSize)
                  config.options.txtFontSize = (config.options.txtFontSize*1)+fontSettings.stepSize;
               config.macros.fontSize.setFont();
}

config.macros.fontSize.decFont=function()
{

               if (config.options.txtFontSize > fontSettings.minSize)
                  config.options.txtFontSize = (config.options.txtFontSize*1) - fontSettings.stepSize;
               config.macros.fontSize.setFont();
}

config.macros.fontSize.resetFont=function()
{

               config.options.txtFontSize=fontSettings.defaultSize;
               config.macros.fontSize.setFont();
}

config.paramifiers.font =
{
               onstart: function(v)
                  {
                   config.options.txtFontSize = v;
                   config.macros.fontSize.setFont();
                  }
};
//}}}
Here are some examples that show the usage of the write action in the ForEachTiddlerMacro.

//''Select and Sort Examples''//
* InClauseExamples
* WhereClauseExamples
* SortClauseExamples
* ScriptClauseExamples
//''Action Examples''//
* AddToListActionExamples
* WriteActionExamples


Of cause you may also combine the examples, e.g. taking the whereClause of one example, the sortClause of a second and the action of a third.
//~~(Part of the [[ForEachTiddlerPlugin]])~~//

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

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


''Using JavaScript''

To give you a lot of flexibility the [[ForEachTiddlerMacro]] uses JavaScript in its arguments. Even if you are not that familiar with JavaScript you may find forEachTiddler useful. Just have a look at the various ready-to-use [[ForEachTiddlerExamples]] and adapt them to your needs.

''The Elements of the Macro''

The arguments of the ForEachTiddlerMacro consist of multiple parts, each of them being optional.

<<slider chkFETInClause [[inClause]] "inClause" "inClause">>
<<slider chkFETWhereClause [[whereClause]] "whereClause" "whereClause">>
<<slider chkFETSortClause [[sortClause]] "sortClause" "sortClause">>
<<slider chkFETScriptClause [[scriptClause]] "scriptClause" "scriptClause">>
<<slider chkFETActions [[Action Specification]] "Action Specification" "Action Specification">>

''Using Macros and ">" inside the forEachTiddler Macro''

You may use other macro calls into the expression, especially in the actionParameters. To avoid that the {{{>>}}} of such a macro call is misinterpreted as the end of the {{{<<forEachTiddler...>>}}} macro you must escape the {{{>>}}} of the inner macro with {{{$))}}} E.g. if you want to use {{{<<tiddler ...>>}}} inside the {{{forEachTiddler}}} macro you have to write {{{<<tiddler ...$))}}}.

In addition it is necessary to escape single {{{>}}} with the text {{{$)}}}.

''Using {{{<<tiddler ... with: ...>>}}} to re-use ForEachTiddler definitions''

Sometimes you may want to use a certain ForEachTiddler definition in slight variations. E.g. you may want to list either the tiddlers tagged with "ToDo" and in the other case with "Done". To do so you may use "Tiddler parameters". Here an example:

Replace the variable part of the ForEachTiddler definition with $1 ($2,... $9 are supported). E.g. you may create the tiddler "ListTaggedTiddlers" like this
{{{
<<forEachTiddler 
 where 
 'tiddler.tags.contains("$1")'
>>
}}}

Now you can use the ListTaggedTiddlers for various specific tags, using the {{{<<tiddler ...>>}}} macro:
{{{
<<tiddler ListTaggedTiddlers with: "systemConfig">>
}}}
{{{
<<tiddler ListTaggedTiddlers with: "Plugin">>
}}}


See also [[ForEachTiddlerExamples]].
/***
|''Name:''|ForEachTiddlerPlugin|
|''Version:''|1.0.8 (2007-04-12)|
|''Source:''|http://tiddlywiki.abego-software.de/#ForEachTiddlerPlugin|
|''Author:''|UdoBorkowski (ub [at] abego-software [dot] de)|
|''Licence:''|[[BSD open source license (abego Software)|http://www.abego-software.de/legal/apl-v10.html]]|
|''Copyright:''|&copy; 2005-2007 [[abego Software|http://www.abego-software.de]]|
|''TiddlyWiki:''|1.2.38+, 2.0|
|''Browser:''|Firefox 1.0.4+; Firefox 1.5; InternetExplorer 6.0|
!Description

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

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

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

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

!Code
***/
//{{{

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


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

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

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

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

	return tiddlyWiki;
};


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

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

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

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

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

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

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

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


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

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


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

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

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

// Internal.
//
// Returns the given original path (that is a file path, starting with "file:")
// as a path to a local file, in the systems native file format.
//
// Location information in the originalPath (i.e. the "#" and stuff following)
// is stripped.
// 
config.macros.forEachTiddler.getLocalPath = function(originalPath) {
	// Remove any location part of the URL
	var hashPos = originalPath.indexOf("#");
	if(hashPos != -1)
		originalPath = originalPath.substr(0,hashPos);
	// Convert to a native file format assuming
	// "file:///x:/path/path/path..." - pc local file --> "x:\path\path\path..."
	// "file://///server/share/path/path/path..." - FireFox pc network file --> "\\server\share\path\path\path..."
	// "file:///path/path/path..." - mac/unix local file --> "/path/path/path..."
	// "file://server/share/path/path/path..." - pc network file --> "\\server\share\path\path\path..."
	var localPath;
	if(originalPath.charAt(9) == ":") // pc local file
		localPath = unescape(originalPath.substr(8)).replace(new RegExp("/","g"),"\\");
	else if(originalPath.indexOf("file://///") === 0) // FireFox pc network file
		localPath = "\\\\" + unescape(originalPath.substr(10)).replace(new RegExp("/","g"),"\\");
	else if(originalPath.indexOf("file:///") === 0) // mac/unix local file
		localPath = unescape(originalPath.substr(7));
	else if(originalPath.indexOf("file:/") === 0) // mac/unix local file
		localPath = unescape(originalPath.substr(5));
	else // pc network file
		localPath = "\\\\" + unescape(originalPath.substr(7)).replace(new RegExp("/","g"),"\\");	
	return localPath;
};

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

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


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



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


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

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

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

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


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


} // of "install only once"

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


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

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.

Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or other
materials provided with the distribution.

Neither the name of abego Software nor the names of its contributors may be
used to endorse or promote products derived from this software without specific
prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
***/
The [[FormTiddlerPlugin]] allows you to enter your data in a form and store the form's data in your tiddlers.

(For more information on tiddler data see the [[DataTiddlerPlugin]].)

//''Define ~FormTemplate''//

When you want to enter data in a form you first have to define a [[FormTemplate]] tiddler. A FormTemplate tiddler is a tiddler that contains named HTML INPUT elements (such as textfields, password fields, lists etc.) that define the stuff that should be edited in the form. E.g. you may have a FormTemplate that looks like this:

<html>
 <b>Name:</b><br/>
 <input name=userName type=text /><br/>
 <b>Password:</b><br/>
 <input name=pwd type=password /><br/>
</html>

The correspond HTML text looks like this
{{{
<html>
 <b>Name:</b><br/>
 <input name=userName type=text /><br/>
 <b>Password:</b><br/>
 <input name=pwd type=password /><br/>
</html>
}}}

The name of the INPUT element is also the name of the data field it is editing. E.g. a text field defined like this: 
{{{
<input name=userName type=text />
}}}
will edit the data field "userName" of the tiddler.


You are free to layout the INPUT elements as you like, but don't add a "form" element around them and don't define 'onchange' handlers, since this will be done automatically by the {{{<<formTiddler ...>>}}} macro.


//''Use ~FormTemplates (through the {{{<<formTiddler ...>>}}} macro)''//

In a second step you add the {{{<<formTiddler ...>>}}} macro to tiddlers that should be edited. In the macro you are referencing the [[FormTemplate]] that should be used to edit the tiddler's data. You may refer to the same FormTemplate tiddler in as many tiddlers as you like. Every such tiddler displays the same INPUT elements as the FormTemplate, but with the "data" of each individual tiddler.

In addition you may more than one {{{<<formTiddler...>>}}} macro call in one tiddler. Just make sure that the names of the elements in the referenced FormTemplate tiddlers do not collide. This feature may be useful if you want to construct a larger input form from a set of smaller FormTemplates.

You can easily create tiddlers with an embedded {{{<<formTiddler...>>}}} macro call using the [[<<newTiddlerWithForm...>>|NewTiddlerWithFormMacro]] macro. The macro shows a button similar to the "new tiddler" button and creates the requested tiddler, ready to enter data. For details see NewTiddlerWithFormMacro.


//''"Structured" and "Free" Data''//

Typically you will edit a tiddler that uses the {{{<<formTiddler...>>}}} macro through the form. But you are free to also edit the tiddler "as usual", through the build-in edit feature. I.e. you may mix "structured data" (as entered through the form) with "free data". I.e. on a "Contact" tiddler you may add an image to the tiddler, or add extra links to related persons. Or you add more tags. Just make sure that you don't modify the {{{<data>...</data>}}} section of the tiddler, since this contains the data maintained by the form.

Also notice that since the data entered in the forms is stored in the tiddler's text (in the {{{<data>...</data>}}} section) using the "search" feature will also find the texts you entered in the forms (even though it will not hilite the texts in the fields).


//''Applications''//

Using the [[FormTiddlerPlugin]] it is easy to manage things like:
* [[Contacts]]
* [[Bugreports]]
* ~ToDo Lists
* and many more.

Since a FormTemplate is typically used for many tiddlers of the same kind you may also consider using the ForEachTiddlerMacro to collect data across multiple tiddlers (e.g. to get a list of all contacts, a summary page for the bug reports etc.)

(See also [[FormTiddler Examples]])


//''HTML Elements''//

For those not that familiar with the HTML INPUT elements here a short overview with HTML snippets. 
|!Type|!HTML Example|!Comment|
|button|{{{<input name=btn type=button value="Just a button" />}}}|no data|
|checkbox|{{{<input name=isVIP type=checkbox />is VIP}}}||
|file|{{{<input name=attachment type=file />}}}|The "file" input element typically does not restore the path of the previously selected file. Nevertheless the path of the file is stored in the tiddler.|
|hidden|{{{<input name=hiddenValue type=hidden value="This is a hidden value" />}}}||
|password|{{{<input name=pwd type=password />}}}|The data entered in a "password" field is stored as clear text in the tiddler.|
|radio|{{{<input name=level type=radio value="Beginner" />Beginner<input name=level type=radio value="Expert" />Expert<input name=level type=radio value="Guru" />Guru}}}||
|reset|{{{<input name=btnReset type=reset />}}}|no data|
|select-one|{{{<select name=browser ><option>Firefox<option>Internet Explorer<option>Opera<option>Other</select >}}}||
|select-multiple|{{{<select name=music MULTIPLE ><option> R&B <option> Jazz <option> Blues <option> New Age</select >}}}||
|submit|{{{<input name=btnSubmit type=submit />}}}|no data|
|text|{{{<input name=userName type=text/>}}}||
|textarea|{{{<TEXTAREA name=notes rows=4 cols=80 ></TEXTAREA>}}}||

For details consult the Web or a textbook on HTML editing.
The {{{<<formTiddler ...>>}}} macro defined by the FormTiddlerPlugin. 

When a tiddler T1 references the (FormTemplate) tiddler T2 in the FormTiddlerMacro, the data of T1 can be edited through the INPUT elements defined by T2.
/***
<<checkForDataTiddlerPlugin>>
|''Name:''|FormTiddlerPlugin|
|''Version:''|1.0.5 (2006-02-24)|
|''Source:''|http://tiddlywiki.abego-software.de/#FormTiddlerPlugin|
|''Author:''|UdoBorkowski (ub [at] abego-software [dot] de)|
|''Licence:''|[[BSD open source license]]|
|''Macros:''|formTiddler, checkForDataTiddlerPlugin, newTiddlerWithForm|
|''Requires:''|DataTiddlerPlugin|
|''TiddlyWiki:''|1.2.38+, 2.0|
|''Browser:''|Firefox 1.0.4+; InternetExplorer 6.0|
!Description
Use form-based tiddlers to enter your tiddler data using text fields, listboxes, checkboxes etc. (All standard HTML Form input elements supported).

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

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

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

!Revision history
* v1.0.5 (2006-02-24)
** Removed "debugger;" instruction
* v1.0.4 (2006-02-07)
** Bug: On IE no data is written to data section when field values changed (thanks to KenGirard for reporting)
* v1.0.3 (2006-02-05)
** Bug: {{{"No form template specified in <<formTiddler>>"}}} when using formTiddler macro on InternetExplorer (thanks to KenGirard for reporting)
* v1.0.2 (2006-01-06)
** Support TiddlyWiki 2.0
* v1.0.1 (2005-12-22)
** Features: 
*** Support InternetExplorer
*** Added newTiddlerWithForm Macro
* v1.0.0 (2005-12-14)
** initial version

!Code
***/
//{{{

//============================================================================
//============================================================================
// FormTiddlerPlugin
//============================================================================
//============================================================================


version.extensions.FormTiddlerPlugin = {
 major: 1, minor: 0, revision: 5,
 date: new Date(2006, 2, 24), 
 type: 'plugin',
 source: "http://tiddlywiki.abego-software.de/#FormTiddlerPlugin"
};

// For backward compatibility with v1.2.x
//
if (!window.story) window.story=window; 
if (!TiddlyWiki.prototype.getTiddler) TiddlyWiki.prototype.getTiddler = function(title) { return t = this.tiddlers[title]; return (t != undefined && t instanceof Tiddler) ? t : null; } 

//============================================================================
// formTiddler Macro
//============================================================================

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

config.macros.formTiddler = {
 // Standard Properties
 label: "formTiddler",
 version: {major: 1, minor: 0, revision: 4, date: new Date(2006, 2, 7)},
 prompt: "Edit tiddler data using forms",

 // Define the "setters" that set the values of INPUT elements of a given type
 // (must match the corresponding "getter")
 setter: { 
 button: function(e, value) {/*contains no data */ },
 checkbox: function(e, value) {e.checked = value;},
 file: function(e, value) {try {e.value = value;} catch(e) {/* ignore, possibly security error*/}},
 hidden: function(e, value) {e.value = value;},
 password: function(e, value) {e.value = value;},
 radio: function(e, value) {e.checked = (e.value == value);},
 reset: function(e, value) {/*contains no data */ },
 "select-one": function(e, value) {config.macros.formTiddler.setSelectOneValue(e,value);},
 "select-multiple": function(e, value) {config.macros.formTiddler.setSelectMultipleValue(e,value);},
 submit: function(e, value) {/*contains no data */},
 text: function(e, value) {e.value = value;},
 textarea: function(e, value) {e.value = value;}
 },

 // Define the "getters" that return the value of INPUT elements of a given type
 // Return undefined to not store any data.
 getter: { 
 button: function(e, value) {return undefined;},
 checkbox: function(e, value) {return e.checked;},
 file: function(e, value) {return e.value;},
 hidden: function(e, value) {return e.value;},
 password: function(e, value) {return e.value;},
 radio: function(e, value) {return e.checked ? e.value : undefined;},
 reset: function(e, value) {return undefined;},
 "select-one": function(e, value) {return config.macros.formTiddler.getSelectOneValue(e);},
 "select-multiple": function(e, value) {return config.macros.formTiddler.getSelectMultipleValue(e);},
 submit: function(e, value) {return undefined;},
 text: function(e, value) {return e.value;},
 textarea: function(e, value) {return e.value;}
 }
};


// -------------------------------------------------------------------------------
// The formTiddler Macro Handler 
// -------------------------------------------------------------------------------

config.macros.formTiddler.handler = function(place,macroName,params,wikifier,paramString,tiddler) {
 if (!config.macros.formTiddler.checkForExtensions(place, macroName)) {
 return;
 }
 
 // --- Parsing ------------------------------------------

 var i = 0; // index running over the params

 // get the name of the form template tiddler
 var formTemplateName = undefined;
 if (i < params.length) {
 formTemplateName = params[i];
 i++;
 }

 if (!formTemplateName) {
 config.macros.formTiddler.createErrorElement(place, "No form template specified in <<" + macroName + ">>.");
 return;
 }


 // --- Processing ------------------------------------------

 // Get the form template text. 
 // (This contains the INPUT elements for the form.)
 var formTemplateTiddler = store.getTiddler(formTemplateName);
 if (!formTemplateTiddler) {
 config.macros.formTiddler.createErrorElement(place, "Form template '" + formTemplateName + "' not found.");
 return;
 }
 var templateText = formTemplateTiddler.text;
 if(!templateText) {
 // Shortcut: when template text is empty we do nothing.
 return;
 }

 // Get the name of the tiddler containing this "formTiddler" macro
 // (i.e. the tiddler, that will be edited and that contains the data)
 var tiddlerName = config.macros.formTiddler.getContainingTiddlerName(place);

 // Append a "form" element. 
 var formName = "form"+formTemplateName+"__"+tiddlerName;
 var e = document.createElement("form");
 e.setAttribute("name", formName);
 place.appendChild(e);

 // "Embed" the elements defined by the templateText (i.e. the INPUT elements) 
 // into the "form" element we just created
 wikify(templateText, e);

 // Initialize the INPUT elements.
 config.macros.formTiddler.initValuesAndHandlersInFormElements(formName, DataTiddler.getDataObject(tiddlerName));
}


// -------------------------------------------------------------------------------
// Form Data Access 
// -------------------------------------------------------------------------------

// Internal.
//
// Initialize the INPUT elements of the form with the values of their "matching"
// data fields in the tiddler. Also setup the onChange handler to ensure that
// changes in the INPUT elements are stored in the tiddler's data.
//
config.macros.formTiddler.initValuesAndHandlersInFormElements = function(formName, data) {
 // config.macros.formTiddler.trace("initValuesAndHandlersInFormElements(formName="+formName+", data="+data+")");

 // find the form
 var form = config.macros.formTiddler.findForm(formName);
 if (!form) {
 return;
 }

 try {
 var elems = form.elements;
 for (var i = 0; i < elems.length; i++) {
 var c = elems[i];
 
 var setter = config.macros.formTiddler.setter[c.type];
 if (setter) {
 var value = data[c.name];
 if (value != null) {
 setter(c, value);
 }
 c.onchange = onFormTiddlerChange;
 } else {
 config.macros.formTiddler.displayFormTiddlerError("No setter defined for INPUT element of type '"+c.type+"'. (Element '"+c.name+"' in form '"+formName+"')");
 }
 }
 } catch(e) {
 config.macros.formTiddler.displayFormTiddlerError("Error when updating elements with new formData. "+e);
 }
}


// Internal.
//
// @return [may be null]
//
config.macros.formTiddler.findForm = function(formName) {
 // We must manually iterate through the document's forms, since
 // IE does not support the "document[formName]" approach

 var forms = window.document.forms;
 for (var i = 0; i < forms.length; i++) {
 var form = forms[i];
 if (form.name == formName) {
 return form;
 }
 }

 return null;
}


// Internal.
//
config.macros.formTiddler.setSelectOneValue = function(element,value) {
 var n = element.options.length;
 for (var i = 0; i < n; i++) {
 element.options[i].selected = element.options[i].value == value;
 }
}

// Internal.
//
config.macros.formTiddler.setSelectMultipleValue = function(element,value) {
 var values = {};
 for (var i = 0; i < value.length; i++) {
 values[value[i]] = true;
 }
 
 var n = element.length;
 for (var i = 0; i < n; i++) {
 element.options[i].selected = !(!values[element.options[i].value]);
 }
}

// Internal.
//
config.macros.formTiddler.getSelectOneValue = function(element) {
 var i = element.selectedIndex;
 return (i >= 0) ? element.options[i].value : null;
}

// Internal.
//
config.macros.formTiddler.getSelectMultipleValue = function(element) {
 var values = [];
 var n = element.length;
 for (var i = 0; i < n; i++) {
 if (element.options[i].selected) {
 values.push(element.options[i].value);
 }
 }
 return values;
}



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

// Internal.
//
config.macros.formTiddler.checkForExtensions = function(place,macroName) {
 if (!version.extensions.DataTiddlerPlugin) {
 config.macros.formTiddler.createErrorElement(place, "<<" + macroName + ">> requires the DataTiddlerPlugin. (You can get it from http://tiddlywiki.abego-software.de/#DataTiddlerPlugin)");
 return false;
 }
 return true;
}

// Internal.
//
// Displays a trace message in the "TiddlyWiki" message pane.
// (used for debugging)
//
config.macros.formTiddler.trace = function(s) {
 displayMessage("Trace: "+s);
}

// Internal.
//
// Display some error message in the "TiddlyWiki" message pane.
//
config.macros.formTiddler.displayFormTiddlerError = function(s) {
 alert("FormTiddlerPlugin Error: "+s);
}

// Internal.
//
// Creates an element that holds an error message
// 
config.macros.formTiddler.createErrorElement = function(place, message) {
 return createTiddlyElement(place,"span",null,"formTiddlerError",message);
}

// Internal.
//
// Returns the name of the tiddler containing the given element.
// 
config.macros.formTiddler.getContainingTiddlerName = function(element) {
 return story.findContainingTiddler(element).id.substr(7);
}

// -------------------------------------------------------------------------------
// Event Handlers 
// -------------------------------------------------------------------------------

// This function must be called by the INPUT elements whenever their
// data changes. Typically this is done through an "onChange" handler.
//
function onFormTiddlerChange (e) {
 // config.macros.formTiddler.trace("onFormTiddlerChange "+e);

 if (!e) var e = window.event;

 var target = resolveTarget(e);
 var tiddlerName = config.macros.formTiddler.getContainingTiddlerName(target);
 var getter = config.macros.formTiddler.getter[target.type];
 if (getter) {
 var value = getter(target);
 DataTiddler.setData(tiddlerName, target.name, value);
 } else {
 config.macros.formTiddler.displayFormTiddlerError("No getter defined for INPUT element of type '"+target.type+"'. (Element '"+target.name+"' used in tiddler '"+tiddlerName+"')");
 }
}

// ensure that the function can be used in HTML event handler
window.onFormTiddlerChange = onFormTiddlerChange;


// -------------------------------------------------------------------------------
// Stylesheet Extensions (may be overridden by local StyleSheet)
// -------------------------------------------------------------------------------

setStylesheet(
 ".formTiddlerError{color: #ffffff;background-color: #880000;}",
 "formTiddler");


//============================================================================
// checkForDataTiddlerPlugin Macro
//============================================================================

config.macros.checkForDataTiddlerPlugin = {
 // Standard Properties
 label: "checkForDataTiddlerPlugin",
 version: {major: 1, minor: 0, revision: 0, date: new Date(2005, 12, 14)},
 prompt: "Check if the DataTiddlerPlugin exists"
}

config.macros.checkForDataTiddlerPlugin.handler = function(place,macroName,params) {
 config.macros.formTiddler.checkForExtensions(place, config.macros.formTiddler.label);
}



//============================================================================
// newTiddlerWithForm Macro
//============================================================================

config.macros.newTiddlerWithForm = {
 // Standard Properties
 label: "newTiddlerWithForm",
 version: {major: 1, minor: 0, revision: 1, date: new Date(2006, 1, 6)},
 prompt: "Creates a new Tiddler with a <<formTiddler ...>> macro"
}

config.macros.newTiddlerWithForm.handler = function(place,macroName,params) {
 // --- Parsing ------------------------------------------

 var i = 0; // index running over the params

 // get the name of the form template tiddler
 var formTemplateName = undefined;
 if (i < params.length) {
 formTemplateName = params[i];
 i++;
 }

 if (!formTemplateName) {
 config.macros.formTiddler.createErrorElement(place, "No form template specified in <<" + macroName + ">>.");
 return;
 }

 // get the button label
 var buttonLabel = undefined;
 if (i < params.length) {
 buttonLabel = params[i];
 i++;
 }

 if (!buttonLabel) {
 config.macros.formTiddler.createErrorElement(place, "No button label specified in <<" + macroName + ">>.");
 return;
 }

 // get the (optional) tiddlerName script and "askUser"
 var tiddlerNameScript = undefined;
 var askUser = false;
 if (i < params.length) {
 tiddlerNameScript = params[i];
 i++;

 if (i < params.length && params[i] == "askUser") {
 askUser = true;
 i++;
 }
 }

 // --- Processing ------------------------------------------

 if(!readOnly) {
 var onClick = function() {
 var tiddlerName;
 if (tiddlerNameScript) {
 try {
 tiddlerName = eval(tiddlerNameScript);
 } catch (ex) {
 }
 }
 if (!tiddlerName || askUser) {
 tiddlerName = prompt("Please specify a tiddler name.", askUser ? tiddlerName : "");
 }
 while (tiddlerName && store.getTiddler(tiddlerName)) {
 tiddlerName = prompt("A tiddler named '"+tiddlerName+"' already exists.\n\n"+"Please specify a tiddler name.", tiddlerName);
 }

 // tiddlerName is either null (user canceled) or a name that is not yet in the store.
 if (tiddlerName) {
 var body = "<<formTiddler [["+formTemplateName+"]]>>";
 var tags = [];
 store.saveTiddler(tiddlerName,tiddlerName,body,config.options.txtUserName,new Date(),tags);
 story.displayTiddler(null,tiddlerName,1);
 }
 }

 createTiddlyButton(place,buttonLabel,buttonLabel,onClick);
 }
}

//}}}


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

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.

Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or other
materials provided with the distribution.

Neither the name of abego Software nor the names of its contributors may be
used to endorse or promote products derived from this software without specific
prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
***/
/***
|Name|FullScreenPlugin|
|Created by|SaqImtiaz|
|Location|http://tw.lewcid.org/#FullScreenPlugin|
|Version|1.1|
|Requires|~TW2.x|
!Description:
Toggle between viewing tiddlers fullscreen and normally. Very handy for when you need more viewing space.

!Demo:
Click the ↕ button in the toolbar for this tiddler. Click it again to turn off fullscreen.

!Installation:
Copy the contents of this tiddler to your TW, tag with systemConfig, save and reload your TW.
Edit the ViewTemplate to add the fullscreen command to the toolbar.

!History:
*25-07-06: ver 1.1
*20-07-06: ver 1.0

!Code
***/
//{{{
var lewcidFullScreen = false;

config.commands.fullscreen =
{
            text:" ↕ ",
            tooltip:"Fullscreen mode"
};

config.commands.fullscreen.handler = function (event,src,title)
{
            if (lewcidFullScreen == false)
               {
                lewcidFullScreen = true;
                setStylesheet('#sidebar, .header, #mainMenu{display:none;} #displayArea{margin:0em 0 0 0 !important;}',"lewcidFullScreenStyle");
               }
            else
               {
                lewcidFullScreen = false;
                setStylesheet(' ',"lewcidFullScreenStyle");
               }
}

config.macros.fullscreen={};
config.macros.fullscreen.handler =  function(place,macroName,params,wikifier,paramString,tiddler)
{
        var label = params[0]||" ↕ ";
        var tooltip = params[1]||"Fullscreen mode";
        createTiddlyButton(place,label,tooltip,config.commands.fullscreen.handler);
}

var lewcid_fullscreen_closeTiddler = Story.prototype.closeTiddler;
Story.prototype.closeTiddler =function(title,animate,slowly)
{
           lewcid_fullscreen_closeTiddler.apply(this,arguments);
           if (story.isEmpty() && lewcidFullScreen == true)
              config.commands.fullscreen.handler();
}


Slider.prototype.lewcidStop = Slider.prototype.stop;
Slider.prototype.stop = function()
{
           this.lewcidStop();
           if (story.isEmpty() && lewcidFullScreen == true)
              config.commands.fullscreen.handler();
}
//}}}
/***
|Name:|HideWhenPlugin|
|Description:|Allows conditional inclusion/exclusion in templates|
|Version:|3.2a|
|Date:|27-Jun-2011|
|Source:|http://mptw.tiddlyspot.com/#HideWhenPlugin|
|Author:|Simon Baird <simon.baird@gmail.com>|
|License:|http://mptw.tiddlyspot.com/#TheBSDLicense|
For use in ViewTemplate and EditTemplate. Example usage:
{{{<div macro="showWhenTagged Task">[[TaskToolbar]]</div>}}}
{{{<div macro="showWhen tiddler.modifier == 'BartSimpson'"><img src="bart.gif"/></div>}}}

Warning: the showWhen and hideWhen macros will blindly eval paramString.
This could be used to execute harmful javascript from a tiddler.

(TODO: Make some effort to sanitize paramString. Perhaps disallow the equals sign?)
***/
//{{{

window.hideWhenLastTest = false;

window.removeElementWhen = function(test,place) {
  window.hideWhenLastTest = test;
  if (test) {
    jQuery(place).empty()
    place.parentNode.removeChild(place);
  }
};

merge(config.macros,{

  hideWhen: { handler: function(place,macroName,params,wikifier,paramString,tiddler) {
    removeElementWhen( eval(paramString), place );
  }},

  showWhen: { handler: function(place,macroName,params,wikifier,paramString,tiddler) {
    removeElementWhen( !eval(paramString), place );
  }},

  hideWhenTagged: { handler: function (place,macroName,params,wikifier,paramString,tiddler) {
    removeElementWhen( tiddler.tags.containsAll(params), place );
  }},

  showWhenTagged: { handler: function (place,macroName,params,wikifier,paramString,tiddler) {
    removeElementWhen( !tiddler.tags.containsAll(params), place );
  }},

  hideWhenTaggedAny: { handler: function (place,macroName,params,wikifier,paramString,tiddler) {
    removeElementWhen( tiddler.tags.containsAny(params), place );
  }},

  showWhenTaggedAny: { handler: function (place,macroName,params,wikifier,paramString,tiddler) {
    removeElementWhen( !tiddler.tags.containsAny(params), place );
  }},

  hideWhenTaggedAll: { handler: function (place,macroName,params,wikifier,paramString,tiddler) {
    removeElementWhen( tiddler.tags.containsAll(params), place );
  }},

  showWhenTaggedAll: { handler: function (place,macroName,params,wikifier,paramString,tiddler) {
    removeElementWhen( !tiddler.tags.containsAll(params), place );
  }},

  hideWhenExists: { handler: function(place,macroName,params,wikifier,paramString,tiddler) {
    removeElementWhen( store.tiddlerExists(params[0]) || store.isShadowTiddler(params[0]), place );
  }},

  showWhenExists: { handler: function(place,macroName,params,wikifier,paramString,tiddler) {
    removeElementWhen( !(store.tiddlerExists(params[0]) || store.isShadowTiddler(params[0])), place );
  }},

  hideWhenTitleIs: { handler: function(place,macroName,params,wikifier,paramString,tiddler) {
    removeElementWhen( tiddler.title == params[0], place );
  }},

  showWhenTitleIs: { handler: function(place,macroName,params,wikifier,paramString,tiddler) {
    removeElementWhen( tiddler.title != params[0], place );
  }},

  'else': { handler: function(place,macroName,params,wikifier,paramString,tiddler) {
    removeElementWhen( !window.hideWhenLastTest, place );
  }}

});

//}}}
/***
|Name|InlineJavascriptPlugin|
|Source|http://www.TiddlyTools.com/#InlineJavascriptPlugin|
|Version|1.6.0|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|plugin|
|Requires||
|Overrides||
|Description|Insert Javascript executable code directly into your tiddler content.|

[Snip - see plugin documentation at the link above]

<<<
!!!!!Credits
<<<
This feature was developed by EricShulman from [[ELS Design Studios|http:/www.elsdesign.com]]
<<<
!!!!!Code
***/
//{{{
version.extensions.inlineJavascript= {major: 1, minor: 6, revision: 0, date: new Date(2007,2,19)};

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

	handler: function(w) {
		var lookaheadRegExp = new RegExp(this.lookahead,"mg");
		lookaheadRegExp.lastIndex = w.matchStart;
		var lookaheadMatch = lookaheadRegExp.exec(w.source)
		if(lookaheadMatch && lookaheadMatch.index == w.matchStart) {
			if (lookaheadMatch[1]) { // load a script library
				// make script tag, set src, add to body to execute, then remove for cleanup
				var script = document.createElement("script"); script.src = lookaheadMatch[1];
				document.body.appendChild(script); document.body.removeChild(script);
			}
			if (lookaheadMatch[5]) { // there is script code
				if (lookaheadMatch[4]) // show inline script code in tiddler output
					wikify("{{{\n"+lookaheadMatch[0]+"\n}}}\n",w.output);
				if (lookaheadMatch[2]) { // create a link to an 'onclick' script
					// add a link, define click handler, save code in link (pass 'place'), set link attributes
					var link=createTiddlyElement(w.output,"a",null,"tiddlyLinkExisting",lookaheadMatch[2]);
					link.onclick=function(){try{return(eval(this.code))}catch(e){alert(e.description?e.description:e.toString())}}
					link.code="function _out(place){"+lookaheadMatch[5]+"\n};_out(this);"
					link.setAttribute("title",lookaheadMatch[3]?lookaheadMatch[3]:"");
					link.setAttribute("href","javascript:;");
					link.style.cursor="pointer";
				}
				else { // run inline script code
					var code="function _out(place){"+lookaheadMatch[5]+"\n};_out(w.output);"
					code=code.replace(/document.write\(/gi,'place.innerHTML+=(');
					try { var out = eval(code); } catch(e) { out = e.description?e.description:e.toString(); }
					if (out && out.length) wikify(out,w.output,w.highlightRegExp,w.tiddler);
				}
			}
			w.nextMatch = lookaheadMatch.index + lookaheadMatch[0].length;
		}
	}
} )
//}}}
/***
|Name:|InstantTimestampPlugin|
|Description:|A handy way to insert timestamps in your tiddler content|
|Version:|1.0.10a|
|Date:|27-Jun-2011|
|Source:|http://mptw.tiddlyspot.com/#InstantTimestampPlugin|
|Author:|Simon Baird <simon.baird@gmail.com>|
|License:|http://mptw.tiddlyspot.com/#TheBSDLicense|
!!Usage
If you enter {ts} in your tiddler content (without the spaces) it will be replaced with a timestamp when you save the tiddler. Full list of formats:
* {ts} or {t} -> timestamp
* {ds} or {d} -> datestamp
* !ts or !t at start of line -> !!timestamp
* !ds or !d at start of line -> !!datestamp
(I added the extra ! since that's how I like it. Remove it from translations below if required)
!!Notes
* Change the timeFormat and dateFormat below to suit your preference.
* See also http://mptw2.tiddlyspot.com/#AutoCorrectPlugin
* You could invent other translations and add them to the translations array below.
***/
//{{{

config.InstantTimestamp = {

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

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

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

  ],

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

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

};

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

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

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

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

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

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

//}}}
/***
|Name:|LessBackupsPlugin|
|Description:|Intelligently limit the number of backup files you create|
|Version:|3.0.1a|
|Date:|27-Jun-2011|
|Source:|http://mptw.tiddlyspot.com/#LessBackupsPlugin|
|Author:|Simon Baird|
|Email:|simon.baird@gmail.com|
|License:|http://mptw.tiddlyspot.com/#TheBSDLicense|
!!Description
You end up with just backup one per year, per month, per weekday, per hour, minute, and second.  So total number won't exceed about 200 or so. Can be reduced by commenting out the seconds/minutes/hours line from modes array
!!Notes
Works in IE and Firefox only.  Algorithm by Daniel Baird. IE specific code by by Saq Imtiaz.
***/
//{{{

var MINS  = 60 * 1000;
var HOURS = 60 * MINS;
var DAYS  = 24 * HOURS;

if (!config.lessBackups) {
  config.lessBackups = {
    // comment out the ones you don't want or set config.lessBackups.modes in your 'tweaks' plugin
    modes: [
      ["YYYY",  365*DAYS], // one per year for ever
      ["MMM",   31*DAYS],  // one per month
      ["ddd",   7*DAYS],   // one per weekday
      //["d0DD",  1*DAYS],   // one per day of month
      ["h0hh",  24*HOURS], // one per hour
      ["m0mm",  1*HOURS],  // one per minute
      ["s0ss",  1*MINS],   // one per second
      ["latest",0]         // always keep last version. (leave this).
    ]
  };
}

window.getSpecialBackupPath = function(backupPath) {

  var now = new Date();

  var modes = config.lessBackups.modes;

  for (var i=0;i<modes.length;i++) {

    // the filename we will try
    var specialBackupPath = backupPath.replace(/(\.)([0-9]+\.[0-9]+)(\.html)$/,
        '$1'+now.formatString(modes[i][0]).toLowerCase()+'$3')

    // open the file
    try {
      if (config.browser.isIE) {
        var fsobject = new ActiveXObject("Scripting.FileSystemObject")
        var fileExists  = fsobject.FileExists(specialBackupPath);
        if (fileExists) {
          var fileObject = fsobject.GetFile(specialBackupPath);
          var modDate = new Date(fileObject.DateLastModified).valueOf();
        }
      }
      else {
        netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
        var file = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile);
        file.initWithPath(specialBackupPath);
        var fileExists = file.exists();
        if (fileExists) {
          var modDate = file.lastModifiedTime;
        }
      }
    }
    catch(e) {
      // give up
      return backupPath;
    }

    // expiry is used to tell if it's an 'old' one. Eg, if the month is June and there is a
    // June file on disk that's more than an month old then it must be stale so overwrite
    // note that "latest" should be always written because the expiration period is zero (see above)
    var expiry = new Date(modDate + modes[i][1]);
    if (!fileExists || now > expiry)
      return specialBackupPath;
  }
}

// hijack the core function
window.getBackupPath_mptw_orig = window.getBackupPath;
window.getBackupPath = function(localPath) {
  return getSpecialBackupPath(getBackupPath_mptw_orig(localPath));
}

//}}}
/***
|''Name:''|LoadRemoteFileThroughProxy (previous LoadRemoteFileHijack)|
|''Description:''|When the TiddlyWiki file is located on the web (view over http) the content of [[SiteProxy]] tiddler is added in front of the file url. If [[SiteProxy]] does not exist "/proxy/" is added. |
|''Version:''|1.1.0|
|''Date:''|mar 17, 2007|
|''Source:''|http://tiddlywiki.bidix.info/#LoadRemoteFileHijack|
|''Author:''|BidiX (BidiX (at) bidix (dot) info)|
|''License:''|[[BSD open source license|http://tiddlywiki.bidix.info/#%5B%5BBSD%20open%20source%20license%5D%5D ]]|
|''~CoreVersion:''|2.2.0|
***/
//{{{
version.extensions.LoadRemoteFileThroughProxy = {
 major: 1, minor: 1, revision: 0, 
 date: new Date("mar 17, 2007"), 
 source: "http://tiddlywiki.bidix.info/#LoadRemoteFileThroughProxy"};

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

bidix.core.loadRemoteFile = loadRemoteFile;
loadRemoteFile = function(url,callback,params)
{
 if ((document.location.toString().substr(0,4) == "http") && (url.substr(0,4) == "http")){ 
 url = store.getTiddlerText("SiteProxy", "/proxy/") + url;
 }
 return bidix.core.loadRemoteFile(url,callback,params);
}
//}}}
<<fontSize "font-size:">> [[AboutRay]] [[MarkupCheatsheet]] [[Big Data Reference articles]] <<tiddler ToggleRightSidebar>>
!Inline Formatting
|!Option|!Syntax|!Output|
|bold font|{{{''bold''}}}|''bold''|
|italic type|{{{//italic//}}}|//italic//|
|underlined text|{{{__underlined__}}}|__underlined__|
|strikethrough text|{{{--strikethrough--}}}|--strikethrough--|
|superscript text|{{{^^super^^script}}}|^^super^^script|
|subscript text|{{{~~sub~~script}}}|~~sub~~script|
|highlighted text|{{{@@highlighted@@}}}|@@highlighted@@|
|preformatted text|<html><code>{{{preformatted}}}</code></html>|{{{preformatted}}}|
!Block Elements
!!Headings
{{{
!Heading 1
!!Heading 2
!!!Heading 3
!!!!Heading 4
!!!!!Heading 5
}}}
<<<
!Heading 1
!!Heading 2
!!!Heading 3
!!!!Heading 4
!!!!!Heading 5
<<<
!!Lists
{{{
* unordered list, level 1
** unordered list, level 2
*** unordered list, level 3

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

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

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

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

<<<
blockquote
<<<
}}}
<<<
> blockquote, level 1
>> blockquote, level 2
>>> blockquote, level 3

> blockquote
<<<
!!Preformatted Text
<html><pre>
{{{
preformatted (e.g. code)
}}}
</pre></html>
<<<
{{{
preformatted (e.g. code)
}}}
<<<
!!Tables
{{{
|CssClass|k
|!heading column 1|!heading column 2|
|row 1, column 1|row 1, column 2|
|row 2, column 1|row 2, column 2|
|>|COLSPAN|
|ROWSPAN| … |
|~| … |
|CssProperty:value;…| … |
|caption|c
}}}
''Annotation:''
* The {{{>}}} marker creates a "colspan", causing the current cell to merge with the one to the right.
* The {{{~}}} marker creates a "rowspan", causing the current cell to merge with the one above.
<<<
|CssClass|k
|!heading column 1|!heading column 2|
|row 1, column 1|row 1, column 2|
|row 2, column 1|row 2, column 2|
|>|COLSPAN|
|ROWSPAN| … |
|~| … |
|CssProperty:value;…| … |
|caption|c
<<<
!!Images /% TODO %/
cf. [[TiddlyWiki.com|http://www.tiddlywiki.com/#EmbeddedImages]]
!Hyperlinks
* [[WikiWords|WikiWord]] are automatically transformed to hyperlinks to the respective tiddler
** the automatic transformation can be suppressed by preceding the respective WikiWord with a tilde ({{{~}}}): {{{~WikiWord}}}
* [[PrettyLinks]] are enclosed in square brackets and contain the desired tiddler name: {{{[[tiddler name]]}}}
** optionally, a custom title or description can be added, separated by a pipe character ({{{|}}}): {{{[[title|target]]}}}<br>''N.B.:'' In this case, the target can also be any website (i.e. URL).
!Custom Styling
* {{{@@CssProperty:value;CssProperty:value;…@@}}}<br>''N.B.:'' CSS color definitions should use lowercase letters to prevent the inadvertent creation of WikiWords.
* <html><code>{{customCssClass{…}}}</code></html>
* raw HTML can be inserted by enclosing the respective code in HTML tags: {{{<html> … </html>}}}
!Special Markers
* {{{<br>}}} forces a manual line break
* {{{----}}} creates a horizontal ruler
* [[HTML entities|http://www.tiddlywiki.com/#HtmlEntities]]
* {{{<<macroName>>}}} calls the respective [[macro|Macros]]
* To hide text within a tiddler so that it is not displayed, it can be wrapped in {{{/%}}} and {{{%/}}}.<br/>This can be a useful trick for hiding drafts or annotating complex markup.
* To prevent wiki markup from taking effect for a particular section, that section can be enclosed in three double quotes: e.g. {{{"""WikiWord"""}}}.
<!--{{{-->
<link rel='alternate' type='application/rss+xml' title='RSS' href='index.xml' />
<!--}}}-->


<style type="text/css">#contentWrapper {display:none;}</style><div id="SplashScreen" style="border: 3px solid #ccc; display: block; text-align: center; width: 320px; margin: 100px auto; padding: 50px; color:#000; font-size: 28px; font-family:Tahoma; background-color:#eee;"><b>Rayspot01</b> is loading<blink> ...</blink><br><br><span style="font-size: 14px; color:red;">Requires Javascript.</span></div>
Name: MptwBlack
Background: #000
Foreground: #fff
PrimaryPale: #333
PrimaryLight: #555
PrimaryMid: #888
PrimaryDark: #aaa
SecondaryPale: #111
SecondaryLight: #222
SecondaryMid: #555
SecondaryDark: #888
TertiaryPale: #222
TertiaryLight: #666
TertiaryMid: #888
TertiaryDark: #aaa
Error: #300

Name: MptwBlue
Background: #fff
Foreground: #000
PrimaryPale: #cdf
PrimaryLight: #57c
PrimaryMid: #114
PrimaryDark: #012
SecondaryPale: #ffc
SecondaryLight: #fe8
SecondaryMid: #db4
SecondaryDark: #841
TertiaryPale: #eee
TertiaryLight: #ccc
TertiaryMid: #999
TertiaryDark: #666
Error: #f88

//{{{
// Pretty sure this is incomplete and experimental
// TODO: Fix it or remove it.

(function($){

merge(config.macros,{
  mptwCollapse: {
    handler: function(place,macroName,params) {
      createTiddlyButton(place, params[0] == '+' ? '\u25AD' : '\u25AC', 'collapse/uncollapse', function(){
        $(story.findContainingTiddler(place)).toggleClass('collapsed');
      });
    }
  }
});

/* this doesn't work unless you have a modified ViewTempate */
config.shadowTiddlers["MptwCollapsePluginStyles"] = ""
  +".collapsed .uncollapsedView { display:none;       }"
  +".collapsedView              { display:none;       }"
  +".collapsed .collapsedView   { display:block;      }"
  +".tiddler.collapsed          { padding-bottom:1em; }"
  +".tiddler.collapsed .title   { font-size:100%;     }"
;

store.addNotification("MptwCollapsePluginStyles",refreshStyles);

})(jQuery);

//}}}
/***
|Name:|MptwConfigPlugin|
|Description:|Miscellaneous tweaks used by MPTW|
|Version:|1.0a|
|Date:|27-Jun-2011|
|Source:|http://mptw.tiddlyspot.com/#MptwConfigPlugin|
|Author:|Simon Baird <simon.baird@gmail.com>|
|License:|http://mptw.tiddlyspot.com/#MptwConfigPlugin|
!!Note: instead of editing this you should put overrides in MptwUserConfigPlugin
***/
//{{{
var originalReadOnly = readOnly;
var originalShowBackstage = showBackstage;

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

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

config.options.chkSaveBackups = true;         // do save backups
config.options.txtBackupFolder = 'twbackup';  // put backups in a backups folder

config.options.chkAutoSave = (window.location.protocol == "file:"); // do autosave if we're in local file

config.mptwVersion = "2.7.4";

config.macros.mptwVersion={handler:function(place){wikify(config.mptwVersion,place);}};

if (config.options.txtTheme == '')
  config.options.txtTheme = 'MptwTheme';

// add to default GettingStarted
config.shadowTiddlers.GettingStarted += "\n\nSee also [[MPTW]].";

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

// these are used by ViewTemplate
config.mptwDateFormat = 'DD/MM/YY';
config.mptwJournalFormat = 'Journal DD/MM/YY';

//}}}
Name: MptwGreen
Background: #fff
Foreground: #000
PrimaryPale: #9b9
PrimaryLight: #385
PrimaryMid: #031
PrimaryDark: #020
SecondaryPale: #ffc
SecondaryLight: #fe8
SecondaryMid: #db4
SecondaryDark: #841
TertiaryPale: #eee
TertiaryLight: #ccc
TertiaryMid: #999
TertiaryDark: #666
Error: #f88

Name: MptwRed
Background: #fff
Foreground: #000
PrimaryPale: #eaa
PrimaryLight: #c55
PrimaryMid: #711
PrimaryDark: #500
SecondaryPale: #ffc
SecondaryLight: #fe8
SecondaryMid: #db4
SecondaryDark: #841
TertiaryPale: #eee
TertiaryLight: #ccc
TertiaryMid: #999
TertiaryDark: #666
Error: #f88

|Name|MptwRounded|
|Description|Mptw Theme with some rounded corners (Firefox only)|
|ViewTemplate|MptwTheme##ViewTemplate|
|EditTemplate|MptwTheme##EditTemplate|
|PageTemplate|MptwTheme##PageTemplate|
|StyleSheet|##StyleSheet|

!StyleSheet
/*{{{*/

[[MptwTheme##StyleSheet]]

.tiddler,
.sliderPanel,
.button,
.tiddlyLink,
.tabContents
{ -moz-border-radius: 1em; }

.tab {
	-moz-border-radius-topleft: 0.5em;
	-moz-border-radius-topright: 0.5em;
}
#topMenu {
	-moz-border-radius-bottomleft: 2em;
	-moz-border-radius-bottomright: 2em;
}

/*}}}*/

Name: MptwSmoke
Background: #fff
Foreground: #000
PrimaryPale: #aaa
PrimaryLight: #777
PrimaryMid: #111
PrimaryDark: #000
SecondaryPale: #ffc
SecondaryLight: #fe8
SecondaryMid: #db4
SecondaryDark: #841
TertiaryPale: #eee
TertiaryLight: #ccc
TertiaryMid: #999
TertiaryDark: #666
Error: #f88

|Name|MptwStandard|
|Description|Mptw Theme with the default TiddlyWiki PageLayout and Styles|
|ViewTemplate|MptwTheme##ViewTemplate|
|EditTemplate|MptwTheme##EditTemplate|
Name: MptwTeal
Background: #fff
Foreground: #000
PrimaryPale: #B5D1DF
PrimaryLight: #618FA9
PrimaryMid: #1a3844
PrimaryDark: #000
SecondaryPale: #ffc
SecondaryLight: #fe8
SecondaryMid: #db4
SecondaryDark: #841
TertiaryPale: #f8f8f8
TertiaryLight: #bbb
TertiaryMid: #999
TertiaryDark: #888
Error: #f88
|Name|MptwTheme|
|Description|Mptw Theme including custom PageLayout|
|PageTemplate|##PageTemplate|
|ViewTemplate|##ViewTemplate|
|EditTemplate|##EditTemplate|
|StyleSheet|##StyleSheet|

http://mptw.tiddlyspot.com/#MptwTheme ($Rev: 1829 $)

!PageTemplate
<!--{{{-->
<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>
<!-- horizontal MainMenu -->
<div id='topMenu' refresh='content' tiddler='MainMenu'></div>
<!-- original MainMenu menu -->
<!-- <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>
<!--}}}-->

!ViewTemplate
<!--{{{-->
<div class="uncollapsedView">
[[MptwTheme##ViewTemplateToolbar]]

<div class="tagglyTagged" macro="tags"></div>

<div class='titleContainer'>
	<span class='title' macro='view title'></span>
	<span macro="miniTag"></span>
</div>

<div class='subtitle'>
	(updated <span macro='view modified date {{config.mptwDateFormat?config.mptwDateFormat:"MM/0DD/YY"}}'></span>
	by <span macro='view modifier link'></span>)
	<!--
	(<span macro='message views.wikified.createdPrompt'></span>
	<span macro='view created date {{config.mptwDateFormat?config.mptwDateFormat:"MM/0DD/YY"}}'></span>)
	-->
</div>

<div macro="showWhen tiddler.tags.containsAny(['css','html','pre','systemConfig']) && !tiddler.text.match('{{'+'{')">
	<div class='viewer'><pre macro='view text'></pre></div>
</div>
<div macro="else">
	<div class='viewer' macro='view text wikified'></div>
</div>

<div class="tagglyTagging" macro="tagglyTagging"></div>
</div>
<div class="collapsedView">
	<span class='toolbar'>
		<span macro='toolbar closeTiddler'></span>
		<span macro='mptwCollapse +'></span>
	</span>
	<span class='title' macro='view title'></span>
</div>

<!--}}}-->

!ViewTemplateToolbar
<!--{{{-->
<div class='toolbar'>
	<span macro="showWhenTagged systemConfig">
		<span macro="toggleTag systemConfigDisable . '[[disable|systemConfigDisable]]'"></span>
	</span>
	<span macro="showWhenTagged systemTheme"><span macro="applyTheme"></span></span>
	<span macro="showWhenTagged systemPalette"><span macro="applyPalette"></span></span>
	<span macro="showWhen tiddler.tags.contains('css') || tiddler.title == 'StyleSheet'"><span macro="refreshAll"></span></span>
	<span style="padding:1em;"></span>
	<span macro='toolbar closeTiddler closeOthers +editTiddler deleteTiddler > fields syncing permalink references jump'></span> <span macro='newHere label:"new here"'></span>
	<span macro='newJournalHere {{config.mptwJournalFormat?config.mptwJournalFormat:"MM/0DD/YY"}}'></span>
	<!--span macro='mptwCollapse -'></span-->
</div>
<!--}}}-->

!EditTemplate
<!--{{{-->
<div class="toolbar" macro="toolbar +saveTiddler saveCloseTiddler closeOthers -cancelTiddler cancelCloseTiddler deleteTiddler"></div>
<div class="title" macro="view title"></div>
<div class="editLabel">Title</div><div class="editor" macro="edit title"></div>
<div macro='annotations'></div>
<div class="editLabel">Content</div><div class="editor" macro="edit text"></div>
<div class="editLabel">Tags</div><div class="editor" macro="edit tags"></div>
<div class="editorFooter"><span macro="message views.editor.tagPrompt"></span><span macro="tagChooser"></span></div>
<!--}}}-->

!StyleSheet
/*{{{*/

/* a contrasting background so I can see where one tiddler ends and the other begins */
body {
	background: [[ColorPalette::TertiaryLight]];
}

/* sexy colours and font for the header */
.headerForeground {
	color: [[ColorPalette::PrimaryPale]];
}
.headerShadow, .headerShadow a {
	color: [[ColorPalette::PrimaryMid]];
}

/* separate the top menu parts */
.headerForeground, .headerShadow {
	padding: 1em 1em 0;
}

.headerForeground, .headerShadow {
	font-family: 'Trebuchet MS', sans-serif;
	font-weight:bold;
}
.headerForeground .siteSubtitle {
	color: [[ColorPalette::PrimaryLight]];
}
.headerShadow .siteSubtitle {
	color: [[ColorPalette::PrimaryMid]];
}

/* make shadow go and down right instead of up and left */
.headerShadow {
	left: 1px;
	top: 1px;
}

/* prefer monospace for editing */
.editor textarea, .editor input {
	font-family: 'Consolas', monospace;
	background-color:[[ColorPalette::TertiaryPale]];
}


/* sexy tiddler titles */
.title {
	font-size: 250%;
	color: [[ColorPalette::PrimaryLight]];
	font-family: 'Trebuchet MS', sans-serif;
}

/* more subtle tiddler subtitle */
.subtitle {
	padding:0px;
	margin:0px;
	padding-left:1em;
	font-size: 90%;
	color: [[ColorPalette::TertiaryMid]];
}
.subtitle .tiddlyLink {
	color: [[ColorPalette::TertiaryMid]];
}

/* a little bit of extra whitespace */
.viewer {
	padding-bottom:3px;
}

/* don't want any background color for headings */
h1,h2,h3,h4,h5,h6 {
	background-color: transparent;
	color: [[ColorPalette::Foreground]];
}

/* give tiddlers 3d style border and explicit background */
.tiddler {
	background: [[ColorPalette::Background]];
	border-right: 2px [[ColorPalette::TertiaryMid]] solid;
	border-bottom: 2px [[ColorPalette::TertiaryMid]] solid;
	margin-bottom: 1em;
	padding:1em 2em 2em 1.5em;
}

/* make options slider look nicer */
#sidebarOptions .sliderPanel {
	border:solid 1px [[ColorPalette::PrimaryLight]];
}

/* the borders look wrong with the body background */
#sidebar .button {
	border-style: none;
}

/* this means you can put line breaks in SidebarOptions for readability */
#sidebarOptions br {
	display:none;
}
/* undo the above in OptionsPanel */
#sidebarOptions .sliderPanel br {
	display:inline;
}

/* horizontal main menu stuff */
#displayArea {
	margin: 1em 15.7em 0em 1em; /* use the freed up space */
}
#topMenu br {
	display: none;
}
#topMenu {
	background: [[ColorPalette::PrimaryMid]];
	color:[[ColorPalette::PrimaryPale]];
}
#topMenu {
	padding:2px;
}
#topMenu .button, #topMenu .tiddlyLink, #topMenu a {
	margin-left: 0.5em;
	margin-right: 0.5em;
	padding-left: 3px;
	padding-right: 3px;
	color: [[ColorPalette::PrimaryPale]];
	font-size: 115%;
}
#topMenu .button:hover, #topMenu .tiddlyLink:hover {
	background: [[ColorPalette::PrimaryDark]];
}

/* make 2.2 act like 2.1 with the invisible buttons */
.toolbar {
	visibility:hidden;
}
.selected .toolbar {
	visibility:visible;
}

/* experimental. this is a little borked in IE7 with the button 
 * borders but worth it I think for the extra screen realestate */
.toolbar { float:right; }

/* fix for TaggerPlugin. from sb56637. improved by FND */
.popup li .tagger a {
   display:inline;
}

/* makes theme selector look a little better */
#sidebarOptions .sliderPanel .select .button {
  padding:0.5em;
  display:block;
}
#sidebarOptions .sliderPanel .select br {
	display:none;
}

/* make it print a little cleaner */
@media print {
	#topMenu {
		display: none ! important;
	}
	/* not sure if we need all the importants */
	.tiddler {
		border-style: none ! important;
		margin:0px ! important;
		padding:0px ! important;
		padding-bottom:2em ! important;
	}
	.tagglyTagging .button, .tagglyTagging .hidebutton {
		display: none ! important;
	}
	.headerShadow {
		visibility: hidden ! important;
	}
	.tagglyTagged .quickopentag, .tagged .quickopentag {
		border-style: none ! important;
	}
	.quickopentag a.button, .miniTag {
		display: none ! important;
	}
}

/* get user styles specified in StyleSheet */
[[StyleSheet]]

/*}}}*/

|Name|MptwTrim|
|Description|Mptw Theme with a reduced header to increase useful space|
|ViewTemplate|MptwTheme##ViewTemplate|
|EditTemplate|MptwTheme##EditTemplate|
|StyleSheet|MptwTheme##StyleSheet|
|PageTemplate|##PageTemplate|

!PageTemplate
<!--{{{-->

<!-- horizontal MainMenu -->
<div id='topMenu' macro='gradient vert [[ColorPalette::PrimaryLight]] [[ColorPalette::PrimaryMid]]'>
<span refresh='content' tiddler='SiteTitle' style="padding-left:1em;font-weight:bold;"></span>:
<span refresh='content' tiddler='MainMenu'></span>
</div>
<div id='sidebar'>
	<div id='sidebarOptions'>
		<div refresh='content' tiddler='SideBarOptions'></div>
		<div style="margin-left:0.1em;"
			macro='slider chkTabSliderPanel SideBarTabs {{"tabs \u00bb"}} "Show Timeline, All, Tags, etc"'></div>
	</div>
</div>
<div id='displayArea'>
	<div id='messageArea'></div>
	<div id='tiddlerDisplay'></div>
</div>

/***
|Description:|A place to put your config tweaks so they aren't overwritten when you upgrade MPTW|
See http://www.tiddlywiki.org/wiki/Configuration_Options for other options you can set. In some cases where there are clashes with other plugins it might help to rename this to zzMptwUserConfigPlugin so it gets executed last.
***/
//{{{

// example: set your preferred date format
//config.mptwDateFormat = 'MM/0DD/YY';
//config.mptwJournalFormat = 'Journal MM/0DD/YY';

// example: set the theme you want to start with
//config.options.txtTheme = 'MptwRoundTheme';

// example: switch off autosave, switch on backups and set a backup folder
//config.options.chkSaveBackups = true;
//config.options.chkAutoSave = false;
//config.options.txtBackupFolder = 'backups';

// uncomment to disable 'new means new' functionality for the new journal macro
//config.newMeansNewForJournalsToo = false;

//}}}
body {
 background: #fffaae;
 color: #000;
}

.tiddler {
 background: #fffaae;
 padding: 1em 1em 0.5em 1em;
 margin-bottom: 1em;
 border: none;
}

.viewer .button {
 background: #e4ff70;
 color: #000;
 border: none;
}

.viewer .button:hover {
 background: #228b22;
 color: #fffaae;
}

.title {
text-align: right;
background: #e4ff70;
 -moz-border-radius: 0.5em;
padding: 0.2em;
}

#jsMath_button {
display: none;
}

/* navigator always visible
.pageFooterOff #navigator{
 visibility: visible;
}*/

/* remove clock 
.slideClock{
 display: none;
}*/
/*{{{*/
input {font-size: 60%;}

button {font-size: 60%;}

.txtOptionInput {
 width: 15em;
}

.tabContents li{
 list-style: none;
}

.viewer .center {
margin-left: auto;
margin-right: auto;
}

.center {
text-align:center;
}
/*}}}*/
[img[URL for your image here]]
<html>
<style>
.rolodex table {
border: 0px solid;
background-color:#eeeff;
}

.rolodex tr, .rolodex td {
border: 0px solid;
}
</style>
<span class="rolodex">
 <table>
 <tr>
 <td align="right"><b>Author(s):</b></td>
 <td colspan="3"><input name=author type=text style="width:300%" /></td></tr>
 <tr>
 <td align="right"><b>Article title:</b></td>
 <td colspan="3"><input name=booktitle type=text style="width:300%" /></td></tr>
 <tr>
 <td align="right"><b>Publisher information:</b></td>
 <td colspan="3"><input name=pubinfo type=text style="font-style:italic; width:300%;" /></td></tr>
 <tr>
 <td align="right"><b>Article url:</b></td>
 <td colspan="3"><input name=arturl type=text style="width:300%" /></td></tr>
 <tr>
 <td align="right"><b>Pub date:</b></td>
 <td colspan="3"><input name=pubdate type=text style="width:300%" /></td></tr>
 <tr>
 <td align="right"><b>Rating:</b></td>
 <td colspan="3"><input name=rating type=text style="width:300%" /></td></tr><tr>
 <tr>
 <td align="right"><b>Subject:</b></td>
 <select name=subject >
  <option>Big Data
  <option>This is Thailand
  <option>Transhuman
  <option>Futurist
  <option>aaa
  <option>bbb
  <option>ccc
  <option>ddd
  <option>ddd
  <option>ddd
  <option>Other
 </select >
 <tr></span> </html>

1. In viewing mode, add data to form fields
2. In edit mode, add your notes below and finish with {{{<<notes heading:'Rays Notes'>>!!!Comments
<<comment>>}}}
!Article

<html>
<style>
.rolodex table {
border: 0px solid;
background-color:#eeeff;
}

.rolodex tr, .rolodex td {
border: 0px solid;
}
</style>
<span class="rolodex">
 <table>
 <tr>
 <td align="right"><b>Author(s):</b></td>
 <td colspan="3"><input name=author type=text style="width:300%" /></td></tr>
 <tr>
 <td align="right"><b>Article title (put in "quotes"):</b></td>
 <td colspan="3"><input name=articletitle type=text style="width:300%" /></td></tr>
 <tr>
 <td align="right"><b>Journal Title:</b></td>
 <td colspan="3"><input name=journalinfo type=text style="width:300%" /></td></tr>
 <tr>
 <td align="right"><b>Volume (year): page numbers:</b></td>
 <td colspan="3"><input name=pagenumbers type=text style="width:300%" /></td></tr>
 <tr>
 <td align="right"><b>url:</b></td>
 <td colspan="3"><input name=url type=text style="width:300%" /></td></tr>
 <tr>
 <td align="right"><b>Synopsis:</b></td>
 <td colspan="3"><input name=synopsis type=text style="width:300%" /></td></tr>
 <tr>
 <td align="right"><b>Primary topic:</b></td>
 <td colspan="3"><input name=primtopic type=text style="width:300%" /></td></tr>
 <tr></span> </html>
1. In viewing mode, add data to form fields
2. In edit mode, add your notes below and finish with {{{<<notes heading:'Rays Notes'>>!!!Comments<<comment>>}}}
3. In edit mode, add an url for an image of the magazine or journal cover at the top of the tiddler if you wish. Here's how: {{{[img[YOUR URL HERE]]}}}

! Article

/***
|Name:|NewHerePlugin|
|Description:|Creates the new here and new journal macros|
|Version:|3.0a|
|Date:|27-Jun-2011|
|Source:|http://mptw.tiddlyspot.com/#NewHerePlugin|
|Author:|Simon Baird <simon.baird@gmail.com>|
|License|http://mptw.tiddlyspot.com/#TheBSDLicense|
***/
//{{{
merge(config.macros, {
  newHere: {
    handler: function(place,macroName,params,wikifier,paramString,tiddler) {
      wikify("<<newTiddler "+paramString+" tag:[["+tiddler.title+"]]>>",place,null,tiddler);
    }
  },
  newJournalHere: {
    handler: function(place,macroName,params,wikifier,paramString,tiddler) {
      wikify("<<newJournal "+paramString+" tag:[["+tiddler.title+"]]>>",place,null,tiddler);
    }
  }
});

//}}}
/***
|Name:|NewMeansNewPlugin|
|Description:|If 'New Tiddler' already exists then create 'New Tiddler (1)' and so on|
|Version:|1.1.1a|
|Date:|27-Jun-2011|
|Source:|http://mptw.tiddlyspot.com/empty.html#NewMeansNewPlugin|
|Author:|Simon Baird <simon.baird@gmail.com>|
|License|http://mptw.tiddlyspot.com/#TheBSDLicense|
!!Note: I think this should be in the core
***/
//{{{

// change this or set config.newMeansNewForJournalsToo it in MptwUuserConfigPlugin
if (config.newMeansNewForJournalsToo == undefined) config.newMeansNewForJournalsToo = true;

String.prototype.getNextFreeName = function() {
  numberRegExp = / \(([0-9]+)\)$/;
  var match = numberRegExp.exec(this);
  if (match) {
  var num = parseInt(match[1]) + 1;
    return this.replace(numberRegExp," ("+num+")");
  }
  else {
    return this + " (1)";
  }
}

config.macros.newTiddler.checkForUnsaved = function(newName) {
  var r = false;
  story.forEachTiddler(function(title,element) {
    if (title == newName)
      r = true;
  });
  return r;
}

config.macros.newTiddler.getName = function(newName) {
  while (store.getTiddler(newName) || config.macros.newTiddler.checkForUnsaved(newName))
    newName = newName.getNextFreeName();
  return newName;
}


config.macros.newTiddler.onClickNewTiddler = function()
{
  var title = this.getAttribute("newTitle");
  if(this.getAttribute("isJournal") == "true") {
    title = new Date().formatString(title.trim());
  }

  // ---- these three lines should be the only difference between this and the core onClickNewTiddler
  if (config.newMeansNewForJournalsToo || this.getAttribute("isJournal") != "true")
    title = config.macros.newTiddler.getName(title);

  var params = this.getAttribute("params");
  var tags = params ? params.split("|") : [];
  var focus = this.getAttribute("newFocus");
  var template = this.getAttribute("newTemplate");
  var customFields = this.getAttribute("customFields");
  if(!customFields && !store.isShadowTiddler(title))
    customFields = String.encodeHashMap(config.defaultCustomFields);
  story.displayTiddler(null,title,template,false,null,null);
  var tiddlerElem = story.getTiddler(title);
  if(customFields)
    story.addCustomFields(tiddlerElem,customFields);
  var text = this.getAttribute("newText");
  if(typeof text == "string")
    story.getTiddlerField(title,"text").value = text.format([title]);
  for(var t=0;t<tags.length;t++)
    story.setTiddlerTag(title,tags[t],+1);
  story.focusTiddler(title,focus);
  return false;
};

//}}}
Looker Wins Backers and Cash on New-Gen BI Vision

Posted by Martin Veitch on August 16 2013
Until March this year in stealth mode, Looker has been making more noise about its business intelligence platform in the last few months and will gain a lot more attention after raising $16m in funding this week.
Looker is an attempt to rewrite the tenets of BI for the Big Data generation. We all know that we have more data than ever to query because surveillance cameras, geo-location sensors and a million other sources are capturing information in real time. Technologies like Hadoop provide a way to contain all this data and make it ready for interrogation. Looker sees itself as providing the final piece of the jigsaw: a BI environment designed for this all-new world.
However, speaking by phone from the company’s HQ in Santa Cruz, California, Looker CEO Frank Bien said the reason VCs had been sniffing around it so much is because customers were spreading the gospel.
“We had a lot of interest and clearly companies that are built on passionate, happy customers can do well,” he said. “I’ve never experienced such a passionate customer base and VCs were calling into our customer base randomly.”
He adds that, while everybody was talking about Big Data, “nobody went out and rebuilt BI”, leaving “a really large gap” in the market for a new entrant. While companies like Tableau and QlikView have shown that BI can be applied to users rather than data analyst specialists, Looker is “not about dumbing down BI”, Bien said. Instead, the aim is to create a value chain or continuum between specialists and end users, from the CEO to the account manager, to get at fast, actionable information “without constantly going back to the scientists”.
Under the Looker model, analysts can spend a few hours modelling using the program’s proprietary SQL calls so end-users can pick it up further down the line and get value without extensive training or know-how.
The program can be deployed on premise or in the cloud, for example on Amazon Web Services using the Redshift data warehouse. About half of Looker’s 40-plus customers are deploying in the cloud and Bien has seen a “big uptick in Redshift … there’s a lot of value and it’s just so fast”. Payment is based on utility.
Looker will also often be deployed against a Greenplum/Pivotal, Vertica or similar back-end, with Looker providing the “last mile” BI capability, Bien said.
“Analysts want a programmatic approach to data and not something kludge-y in the same way that no modern web developer would use Dreamweaver; sometimes it’s faster to develop code snippets.”
Bien likens the Looker effect to “taking the blinkers off. We’re helping companies explore their data. It’s like teaching someone to fish rather than giving them food.”
Of course, the big goal is insights: eureka moments that change strategies, markets even. As an example, he refers to the people behind the Hotel Tonight app discovering that a large number of recommendations were coming from bartenders and other service staff recommending the site.
Bien lashes a “big over-emphasis on the predictive world. SAS Institute and SPSS have a lot of value but we’re operating in the 80%. Big Data has a giant infrastructure with no tools and people have been trying to build the most complex tools thinking maths will get us the answer. Folks have been waiting for a modern tool to explore and something that gives power to the analyst. BI is falling apart because it’s still a Windows world. These tools were developed 20 years ago for a world that’s not relevant today.”
I ask Bien for a company to compare Looker against. He rejects QlikView and instead cites Splunk, (interview here) another disruptor with a passionate following. A Splunk for the BI world? That’s not a bad aim.
 
Martin Veitch is Editorial Director at IDG Connect
/***
|''Name:''|PasswordOptionPlugin|
|''Description:''|Extends TiddlyWiki options with non encrypted password option.|
|''Version:''|1.0.2|
|''Date:''|Apr 19, 2007|
|''Source:''|http://tiddlywiki.bidix.info/#PasswordOptionPlugin|
|''Author:''|BidiX (BidiX (at) bidix (dot) info)|
|''License:''|[[BSD open source license|http://tiddlywiki.bidix.info/#%5B%5BBSD%20open%20source%20license%5D%5D ]]|
|''~CoreVersion:''|2.2.0 (Beta 5)|
***/
//{{{
version.extensions.PasswordOptionPlugin = {
	major: 1, minor: 0, revision: 2, 
	date: new Date("Apr 19, 2007"),
	source: 'http://tiddlywiki.bidix.info/#PasswordOptionPlugin',
	author: 'BidiX (BidiX (at) bidix (dot) info',
	license: '[[BSD open source license|http://tiddlywiki.bidix.info/#%5B%5BBSD%20open%20source%20license%5D%5D]]',
	coreVersion: '2.2.0 (Beta 5)'
};

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

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

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

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

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

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

merge(config.optionsDesc,{
		pasPassword: "Test password"
	});
*/
//}}}
Click <<slideShow button:'Presenting Big Data' style:'MyStyleSheet' repeat>> to start slideshow, then use Ctrl+ or Ctrl- to fit comfortably on your screen. You can discover simple controls near the bottom of the screen with your mouse.

-s-
!What is @@Big Data@@
@@Big Data@@ is a buzzword used to describe a massive volume of both structured and unstructured data that is so large that it's difficult to process using traditional database and software techniques.
Definition source: //Webopedia//

-s-
!What is the dream about @@Big Data@@
The Dreamers [read "Consultants and the service companies they work for"] claim that competitive advantage is available to those innovative companies who are prepared to collect and analyse their mountains of data to disclose the pearls of knowledge/wisdom contained therein.

The BIG assumptions in this dream are:
* the Data is of good quality
* the parsing algorithms are soundly created

Ray's take on these assumptions:
* Data is usually not of good quality
* Parsing algorithms are most likely to have not been tested/validated

-s-
!A little about numbers
|!Term|!What it looks like|!Example of digital space|
|1 byte|1|Stores 1 alphanumeric character|
|1 kilobyte|1,000|Stores a couple of sentences|
|1 megabyte|1,000,000|Stores a long novel|
|1 gigabyte|1,000,000,000|Stores a feature movie|
|1 terabyte|1,000,000,000,000||
|1 petabyte|1,000,000,000,000,000||
|1 exabyte|1,000,000,000,000,000,000||
|1 zettabyte|1,000,000,000,000,000,000,000||


-s-
!Some current examples of Big data
1. NSA Data, about which Edward Snowden has been Whistleblowing


-s-
!Gathering material from the Internet
Its not hard, as the topic is on fire...here is some from just one source on one day
|!Article|!Source|!Date|!Synopsis|
|http://www.theguardian.com/technology/2013/aug/23/nasdaq-crash-data|The Guardian|20130823|We cannot control Big Data|
|http://www.theguardian.com/technology/2013/aug/23/tech-giants-data|The Guardian|20130823|Big Data Farms|
|http://www.theguardian.com/business/2013/aug/23/spending-on-data-centres-reaches-150-billion-dollars|The Guardian|20130823|Google's Big Data Farms|

-s-
!I hope you found this useful.

You are welcome to [[give me feedback|http://www.allraysworld.com/dont-be-shy.html]]
/***
|Name:|PrettyDatesPlugin|
|Description:|Provides a new date format ('pppp') that displays times such as '2 days ago'|
|Version:|1.0a|
|Date:|27-Jun-2011|
|Source:|http://mptw.tiddlyspot.com/#PrettyDatesPlugin|
|Author:|Simon Baird <simon.baird@gmail.com>|
|License:|http://mptw.tiddlyspot.com/#TheBSDLicense|
!!Notes
* If you want to you can rename this plugin. :) Some suggestions: LastUpdatedPlugin, RelativeDatesPlugin, SmartDatesPlugin, SexyDatesPlugin.
* Inspired by http://ejohn.org/files/pretty.js
***/
//{{{
Date.prototype.prettyDate = function() {
  var diff = (((new Date()).getTime() - this.getTime()) / 1000);
  var day_diff = Math.floor(diff / 86400);

  if (isNaN(day_diff))      return "";
  else if (diff < 0)        return "in the future";
  else if (diff < 60)       return "just now";
  else if (diff < 120)      return "1 minute ago";
  else if (diff < 3600)     return Math.floor(diff/60) + " minutes ago";
  else if (diff < 7200)     return "1 hour ago";
  else if (diff < 86400)    return Math.floor(diff/3600) + " hours ago";
  else if (day_diff == 1)   return "Yesterday";
  else if (day_diff < 7)    return day_diff + " days ago";
  else if (day_diff < 14)   return  "a week ago";
  else if (day_diff < 31)   return Math.ceil(day_diff/7) + " weeks ago";
  else if (day_diff < 62)   return "a month ago";
  else if (day_diff < 365)  return "about " + Math.ceil(day_diff/31) + " months ago";
  else if (day_diff < 730)  return "a year ago";
  else                      return Math.ceil(day_diff/365) + " years ago";
}

Date.prototype.formatString_orig_mptw = Date.prototype.formatString;

Date.prototype.formatString = function(template) {
  return this.formatString_orig_mptw(template).replace(/pppp/,this.prettyDate());
}

// for MPTW. otherwise edit your ViewTemplate as required.
// config.mptwDateFormat = 'pppp (DD/MM/YY)';
config.mptwDateFormat = 'pppp';

//}}}
/***
|Name:|QuickOpenTagPlugin|
|Description:|Changes tag links to make it easier to open tags as tiddlers|
|Version:|3.0.1a|
|Date:|27-Jun-2011|
|Source:|http://mptw.tiddlyspot.com/#QuickOpenTagPlugin|
|Author:|Simon Baird <simon.baird@gmail.com>|
|License:|http://mptw.tiddlyspot.com/#TheBSDLicense|
***/
//{{{
config.quickOpenTag = {

  dropdownChar: (document.all ? "\u25bc" : "\u25be"), // the little one doesn't work in IE?

  createTagButton: function(place,tag,excludeTiddler) {
    // little hack so we can do this: <<tag PrettyTagName|RealTagName>>
    var splitTag = tag.split("|");
    var pretty = tag;
    if (splitTag.length == 2) {
      tag = splitTag[1];
      pretty = splitTag[0];
    }

    var sp = createTiddlyElement(place,"span",null,"quickopentag");
    createTiddlyText(createTiddlyLink(sp,tag,false),pretty);

    var theTag = createTiddlyButton(sp,config.quickOpenTag.dropdownChar,
                        config.views.wikified.tag.tooltip.format([tag]),onClickTag);
    theTag.setAttribute("tag",tag);
    if (excludeTiddler)
      theTag.setAttribute("tiddler",excludeTiddler);
        return(theTag);
  },

  miniTagHandler: function(place,macroName,params,wikifier,paramString,tiddler) {
    var tagged = store.getTaggedTiddlers(tiddler.title);
    if (tagged.length > 0) {
      var theTag = createTiddlyButton(place,config.quickOpenTag.dropdownChar,
                          config.views.wikified.tag.tooltip.format([tiddler.title]),onClickTag);
      theTag.setAttribute("tag",tiddler.title);
      theTag.className = "miniTag";
    }
  },

  allTagsHandler: function(place,macroName,params) {
    var tags = store.getTags(params[0]);
    var filter = params[1]; // new feature
    var ul = createTiddlyElement(place,"ul");
    if(tags.length == 0)
      createTiddlyElement(ul,"li",null,"listTitle",this.noTags);
    for(var t=0; t<tags.length; t++) {
      var title = tags[t][0];
      if (!filter || (title.match(new RegExp('^'+filter)))) {
        var info = getTiddlyLinkInfo(title);
        var theListItem =createTiddlyElement(ul,"li");
        var theLink = createTiddlyLink(theListItem,tags[t][0],true);
        var theCount = " (" + tags[t][1] + ")";
        theLink.appendChild(document.createTextNode(theCount));
        var theDropDownBtn = createTiddlyButton(theListItem," " +
          config.quickOpenTag.dropdownChar,this.tooltip.format([tags[t][0]]),onClickTag);
        theDropDownBtn.setAttribute("tag",tags[t][0]);
      }
    }
  },

  // todo fix these up a bit
  styles: [
"/*{{{*/",
"/* created by QuickOpenTagPlugin */",
".tagglyTagged .quickopentag, .tagged .quickopentag ",
" { margin-right:1.2em; border:1px solid #eee; padding:2px; padding-right:0px; padding-left:1px; }",
".quickopentag .tiddlyLink { padding:2px; padding-left:3px; }",
".quickopentag a.button { padding:1px; padding-left:2px; padding-right:2px;}",
"/* extra specificity to make it work right */",
"#displayArea .viewer .quickopentag a.button, ",
"#displayArea .viewer .quickopentag a.tiddyLink, ",
"#mainMenu .quickopentag a.tiddyLink, ",
"#mainMenu .quickopentag a.tiddyLink ",
" { border:0px solid black; }",
"#displayArea .viewer .quickopentag a.button, ",
"#mainMenu .quickopentag a.button ",
" { margin-left:0px; padding-left:2px; }",
"#displayArea .viewer .quickopentag a.tiddlyLink, ",
"#mainMenu .quickopentag a.tiddlyLink ",
" { margin-right:0px; padding-right:0px; padding-left:0px; margin-left:0px; }",
"a.miniTag {font-size:150%;} ",
"#mainMenu .quickopentag a.button ",
" /* looks better in right justified main menus */",
" { margin-left:0px; padding-left:2px; margin-right:0px; padding-right:0px; }",
"#topMenu .quickopentag { padding:0px; margin:0px; border:0px; }",
"#topMenu .quickopentag .tiddlyLink { padding-right:1px; margin-right:0px; }",
"#topMenu .quickopentag .button { padding-left:1px; margin-left:0px; border:0px; }",
"/*}}}*/",
    ""].join("\n"),

  init: function() {
    // we fully replace these builtins. can't hijack them easily
    window.createTagButton = this.createTagButton;
    config.macros.allTags.handler = this.allTagsHandler;
    config.macros.miniTag = { handler: this.miniTagHandler };
    config.shadowTiddlers["QuickOpenTagStyles"] = this.styles;
    store.addNotification("QuickOpenTagStyles",refreshStyles);
  }
}

config.quickOpenTag.init();

//}}}
/***
|Name:|RenameTagsPlugin|
|Description:|Allows you to easily rename or delete tags across multiple tiddlers|
|Version:|3.1|
|Date:|17-Jun-2013|
|Source:|http://mptw.tiddlyspot.com/#RenameTagsPlugin|
|Author:|Simon Baird <simon.baird@gmail.com>|
|License|http://mptw.tiddlyspot.com/#TheBSDLicense|
Rename a tag and you will be prompted to rename it in all its tagged tiddlers.
***/
//{{{
config.renameTags = {

  prompts: {
    rename: "Rename the tag '%0' to '%1' in %2 tidder%3?",
    remove: "Remove the tag '%0' from %1 tidder%2?"
  },

  removeTag: function(tag,tiddlers) {
    store.suspendNotifications();
    for (var i=0;i<tiddlers.length;i++) {
      store.setTiddlerTag(tiddlers[i].title,false,tag);
    }
    store.resumeNotifications();
    store.notifyAll();
  },

  renameTag: function(oldTag,newTag,tiddlers) {
    store.suspendNotifications();
    for (var i=0;i<tiddlers.length;i++) {
      var title = tiddlers[i].title;
      store.setTiddlerTag(title, false, oldTag); // remove old
      store.setTiddlerTag(title, true, newTag);  // add new
      store.getTiddler(title).modified = new Date(); // touch modified date
    }
    store.resumeNotifications();
    store.notifyAll();
  },

  storeMethods: {

    saveTiddler_orig_renameTags: TiddlyWiki.prototype.saveTiddler,

    saveTiddler: function(title,newTitle,newBody,modifier,modified,tags,fields,clearChangeCount,created,creator) {
      if (title != newTitle) {
        var tagged = this.getTaggedTiddlers(title);
        if (tagged.length > 0) {
          // then we are renaming a tag
          if (confirm(config.renameTags.prompts.rename.format([title,newTitle,tagged.length,tagged.length>1?"s":""])))
            config.renameTags.renameTag(title,newTitle,tagged);

          if (!this.tiddlerExists(title) && newBody == "")
            // dont create unwanted tiddler
            return null;
        }
      }
      return this.saveTiddler_orig_renameTags(title,newTitle,newBody,modifier,modified,tags,fields,clearChangeCount,created,creator);
    },

    removeTiddler_orig_renameTags: TiddlyWiki.prototype.removeTiddler,

    removeTiddler: function(title) {
      var tagged = this.getTaggedTiddlers(title);
      if (tagged.length > 0)
        if (confirm(config.renameTags.prompts.remove.format([title,tagged.length,tagged.length>1?"s":""])))
          config.renameTags.removeTag(title,tagged);
      return this.removeTiddler_orig_renameTags(title);
    }

  },

  init: function() {
    merge(TiddlyWiki.prototype,this.storeMethods);
  }
}

config.renameTags.init();

//}}}
/***
|Name:|SaveCloseTiddlerPlugin|
|Description:|Provides two extra toolbar commands, saveCloseTiddler and cancelCloseTiddler|
|Version:|3.0a|
|Date:|27-Jun-2011|
|Source:|http://mptw.tiddlyspot.com/#SaveCloseTiddlerPlugin|
|Author:|Simon Baird <simon.baird@gmail.com>|
|License:|http://mptw.tiddlyspot.com/#TheBSDLicense|
To use these add them to the commands in ToolbarCommands under EditToolbar,
or in the MptwTheme tiddler under EditTemplate.
***/
//{{{
merge(config.commands,{

  saveCloseTiddler: {
    text: 'done/close',
    tooltip: 'Save changes to this tiddler and close it',
    handler: function(ev,src,title) {
      var closeTitle = title;
      var newTitle = story.saveTiddler(title,ev.shiftKey);
      if (newTitle)
        closeTitle = newTitle;
      return config.commands.closeTiddler.handler(ev,src,closeTitle);
    }
  },

  cancelCloseTiddler: {
    text: 'cancel/close',
    tooltip: 'Undo changes to this tiddler and close it',
    handler: function(ev,src,title) {
      // the same as closeTiddler now actually
      return config.commands.closeTiddler.handler(ev,src,title);
    }
  }

});

//}}}
/***
|Name:|SelectThemePlugin|
|Description:|Lets you easily switch theme and palette|
|Version:|1.0.1a|
|Date:|27-Jun-2011|
|Source:|http://mptw.tiddlyspot.com/#SelectThemePlugin|
|Author:|Simon Baird <simon.baird@gmail.com>|
|License:|http://mptw.tiddlyspot.com/#TheBSDLicense|
!Notes
* Borrows largely from ThemeSwitcherPlugin by Martin Budden http://www.martinswiki.com/#ThemeSwitcherPlugin
* Theme is cookie based. But set a default by setting config.options.txtTheme in MptwConfigPlugin (for example)
* Palette is not cookie based. It actually overwrites your ColorPalette tiddler when you select a palette, so beware.
!Usage
* {{{<<selectTheme>>}}} makes a dropdown selector
* {{{<<selectPalette>>}}} makes a dropdown selector
* {{{<<applyTheme>>}}} applies the current tiddler as a theme
* {{{<<applyPalette>>}}} applies the current tiddler as a palette
* {{{<<applyTheme TiddlerName>>}}} applies TiddlerName as a theme
* {{{<<applyPalette TiddlerName>>}}} applies TiddlerName as a palette
***/
//{{{

config.macros.selectTheme = {
  label: {
    selectTheme:"select theme",
    selectPalette:"select palette"
  },
  prompt: {
    selectTheme:"Select the current theme",
    selectPalette:"Select the current palette"
  },
  tags: {
    selectTheme:'systemTheme',
    selectPalette:'systemPalette'
  }
};

config.macros.selectTheme.handler = function(place,macroName)
{
  var btn = createTiddlyButton(place,this.label[macroName],this.prompt[macroName],this.onClick);
  // want to handle palettes and themes with same code. use mode attribute to distinguish
  btn.setAttribute('mode',macroName);
};

config.macros.selectTheme.onClick = function(ev)
{
  var e = ev ? ev : window.event;
  var popup = Popup.create(this);
  var mode = this.getAttribute('mode');
  var tiddlers = store.getTaggedTiddlers(config.macros.selectTheme.tags[mode]);
  // for default
  if (mode == "selectPalette") {
    var btn = createTiddlyButton(createTiddlyElement(popup,'li'),"(default)","default color palette",config.macros.selectTheme.onClickTheme);
    btn.setAttribute('theme',"(default)");
    btn.setAttribute('mode',mode);
  }
  for(var i=0; i<tiddlers.length; i++) {
    var t = tiddlers[i].title;
    var name = store.getTiddlerSlice(t,'Name');
    var desc = store.getTiddlerSlice(t,'Description');
    var btn = createTiddlyButton(createTiddlyElement(popup,'li'), name?name:t, desc?desc:config.macros.selectTheme.label['mode'], config.macros.selectTheme.onClickTheme);
    btn.setAttribute('theme',t);
    btn.setAttribute('mode',mode);
  }
  Popup.show();
  return stopEvent(e);
};

config.macros.selectTheme.onClickTheme = function(ev)
{
  var mode = this.getAttribute('mode');
  var theme = this.getAttribute('theme');
  if (mode == 'selectTheme')
    story.switchTheme(theme);
  else // selectPalette
    config.macros.selectTheme.updatePalette(theme);
  return false;
};

config.macros.selectTheme.updatePalette = function(title)
{
  if (title != "") {
    store.deleteTiddler("ColorPalette");
    if (title != "(default)")
      store.saveTiddler("ColorPalette","ColorPalette",store.getTiddlerText(title),
          config.options.txtUserName,undefined,"");
    refreshAll();
    if(config.options.chkAutoSave)
      saveChanges(true);
  }
};

config.macros.applyTheme = {
  label: "apply",
  prompt: "apply this theme or palette" // i'm lazy
};

config.macros.applyTheme.handler = function(place,macroName,params,wikifier,paramString,tiddler) {
  var useTiddler = params[0] ? params[0] : tiddler.title;
  var btn = createTiddlyButton(place,this.label,this.prompt,config.macros.selectTheme.onClickTheme);
  btn.setAttribute('theme',useTiddler);
  btn.setAttribute('mode',macroName=="applyTheme"?"selectTheme":"selectPalette"); // a bit untidy here
}

config.macros.selectPalette = config.macros.selectTheme;
config.macros.applyPalette = config.macros.applyTheme;

config.macros.refreshAll = { handler: function(place,macroName,params,wikifier,paramString,tiddler) {
  createTiddlyButton(place,"refresh","refresh layout and styles",function() { refreshAll(); });
}};

//}}}
<<search>><<closeAll>><<permaview>><<newTiddler title:"Add title here" label:"new article" text:{{"<<formTiddler NewArticleTemplatex\>\>"}} tag:"article">><<newTiddler>><<newJournal "DD MMM YYYY" "journal">><<saveChanges>><<tiddler TspotSidebar>><<slider chkSliderOptionsPanel OptionsPanel "options »" "Change TiddlyWiki advanced options">>
a place to aggregate @@Big Issues@@ material
Rayspot01
/***
|''Name:''|SlideShowPlugin|
|''Description:''|Creates a simple slide show type display|
|''Version:''|1.6|
|''Date:''|Feb 12, 2008|
|''Source:''|http://www.math.ist.utl.pt/~psoares/addons.html|
|''Documentation:''|[[SlideShowPlugin Documentation|SlideShowPluginDoc]]|
|''Author:''|Paulo Soares and [[Clint Checketts|http://www.checkettsweb.com]]|
|''License:''|[[Creative Commons Attribution-Share Alike 3.0 License|http://creativecommons.org/licenses/by-sa/3.0/]]|
|''~CoreVersion:''|2.1.0|
***/
//{{{
config.macros.slideShow = {label: "slide show", maxTOCLength: 30};
config.macros.slideShow.messages = {gotoLabel: "Go to slide:"};
config.views.wikified.slideShow = {text: "slide show", tooltip: "Start slide show"};
config.views.wikified.slideShow.quit = {text: "end", tooltip: "Quit the slide show"};
config.views.wikified.slideShow.firstSlide = {text: "<<", tooltip: "first slide"};
config.views.wikified.slideShow.previousSlide = {text: "<", tooltip: "previous slide"};
config.views.wikified.slideShow.nextSlide = {text: ">", tooltip: "next slide"};
config.views.wikified.slideShow.lastSlide = {text: ">>", tooltip: "last slide"};
config.views.wikified.slideShow.resetClock = {text: " ", tooltip: "reset"};

config.formatters.push( {
	name: "SlideSeparator",
	match: "^-s-+$\\n?",
	handler: function(w) {
		createTiddlyElement(w.output,"hr",null,'slideSeparator');
	}
});

function changeStyleSheet(tiddlerName) {
	setStylesheet(store.getRecursiveTiddlerText("StyleSheetColors"),"StyleSheetColors");
	setStylesheet(store.getRecursiveTiddlerText("StyleSheetLayout"),"StyleSheetLayout");
	setStylesheet(store.getRecursiveTiddlerText(tiddlerName == null ? "StyleSheet" : tiddlerName,""),"StyleSheet");
}

//Excellent (and versatile) reparser created by Paul Petterson for parsing the paramString in a macro
function reparse( params ) {
	var re = /([^:\s]+)(?:\:((?:\d+)|(?:["'](?:[^"']+)["']))|\s|$)/g;
	var ret = new Array();
	var m;
	while( (m = re.exec( params )) != null ) ret[ m[1] ] = m[2]?m[2]:true;
	return ret;
}

function getElementsByClass(searchClass,node,tag) {
	var classElements = new Array();
	if ( node == null ) node = document;
	if ( tag == null ) tag = '*';
	var els = node.getElementsByTagName(tag);
	var elsLen = els.length;
	var pattern = new RegExp("(^|\\s)"+searchClass+"(\\s|$)");
	var j=0;
	for (var i = 0; i < elsLen; i++) {
		if ( pattern.test(els[i].className) ) {
			classElements[j] = els[i];
			j++;
		}
	}
	return classElements;
}

// 'keys' code adapted from S5 which in turn was adapted from MozPoint (http://mozpoint.mozdev.org/)
function keys(key) {
with(config.macros.slideShow){
	if (document.getElementById('contentWrapper').className == "slideShowMode"){
		if (!key) {
			key = event;
			key.which = key.keyCode;
		}
 		switch (key.which) {
			case 32: // spacebar
				if(time>0){
					if(autoAdvance){
						clearInterval(autoAdvance);
						autoAdvance = null;
					} else {
						autoAdvance=setInterval("GoToSlide(1)", time);
					}
				}
				break;
			case 34: // page down
			case 39: // rightkey
				GoToSlide("n");
				break;
			case 40: // downkey
				GoToSlide(-1);
				break;
			case 33: // page up
			case 37: // leftkey
				GoToSlide("p");
				break;
			case 38: // upkey
				GoToSlide(1);
				break;
			case 36: // home
				GoToSlide("f");
				break;
			case 35: // end
				GoToSlide("l");
				break;
			case 27: // escape
				endSlideShow();
				break;
			case 66: // B
				blankScreen();
				break;
		}
	}
	return false;
}
}

function blankScreen(){
	var blanker = document.getElementById('slideBlanker');
	if (blanker.style.display == 'block'){
		blanker.style.display = 'none';
	} else {
		blanker.style.display = 'block';
	}
}

function clicker(e) {
	if (!e) var e = window.event;
	var target = resolveTarget(e);
	//Whenever something is clicked that won't advance the slide make sure that the table of contents gets hidden
	if (target.getAttribute('href') != null || isParentOrSelf(target, 'toc') || isParentOrSelf(target,'embed') || isParentOrSelf(target,'object') || isParentOrSelf(target, 'slideFooter') || isParentOrSelf(target, 'navigator')){
		 //Don't hide the TOC if the indexNumbers (which trigger the index) is clicked
		if(isParentOrSelf(target,'indexNumbers') || isParentOrSelf(target,'jumpInput')){
 			return true;
		}
		showHideTOC('none');
		return true;
	}
	//Advance a slide if the TOC is visible otherwise make sure that the TOC gets hidden
	if ((!e.which && e.button == 1) || e.which == 1) {
		if (document.getElementById('toc').style.display != 'block'){
			GoToSlide("n");
		} else {
			showHideTOC('none');
		}
	}
	if ((!e.which && e.button == 2) || e.which == 3) {
		if (document.getElementById('toc').style.display != 'block'){
			GoToSlide("p");
		} else {
			showHideTOC('none');
		}
		return false;
	}
}

function isParentOrSelf(element, id) {
	if (element == null || element.nodeName=='BODY') return false;
	else if (element.id == id) return true;
	else return isParentOrSelf(element.parentNode, id);
}

GoToSlide = function(step) {
	var new_pos;
	var slideHolder = document.getElementById('slideContainer');
	//The parse float ensures that the attribute is returned as a number and not a string.
	var cur_pos = parseFloat(slideHolder.getAttribute('currentslide'));
	var numberSlides = parseFloat(slideHolder.getAttribute('numberSlides'));
	switch (step) {
		case "f":
			new_pos=0;
			break;
		case "l":
			new_pos=numberSlides-1;
			break;
		case "n":
			var numberOverlays = parseFloat(slideHolder.childNodes[cur_pos].getAttribute('numberOverlays'));
			var currentOverlay = parseFloat(slideHolder.getAttribute('currentOverlay'));
			if(numberOverlays==0 || currentOverlay==numberOverlays){
				if(noClicks==false) new_pos=cur_pos+1;
			} else {
				var className="Overlay"+currentOverlay;
				var overlay=getElementsByClass(className,slideHolder.childNodes[cur_pos]);
				for(var i=0; i<overlay.length; i++) {overlay[i].className=className+' previousOverlay';}
				currentOverlay++;
				slideHolder.setAttribute('currentOverlay',currentOverlay);
				className="Overlay"+currentOverlay;
				overlay=getElementsByClass(className,slideHolder.childNodes[cur_pos]);
				for(i=0; i<overlay.length; i++) {overlay[i].className=className+' currentOverlay';}
				return false;
			}
			break;
		case "p":
			var numberOverlays = parseFloat(slideHolder.childNodes[cur_pos].getAttribute('numberOverlays'));
			var currentOverlay = parseFloat(slideHolder.getAttribute('currentOverlay'));
			if(numberOverlays==0 || currentOverlay==0){
				if(noClicks==false) new_pos=cur_pos-1;
			} else {
				var className="Overlay"+currentOverlay;
				var overlays=getElementsByClass(className,slideHolder.childNodes[cur_pos]);
				for(var i=0; i<overlays.length; i++) {overlays[i].className=className+' nextOverlay';}
				currentOverlay--;
				className="Overlay"+currentOverlay;
				overlays=getElementsByClass(className,slideHolder.childNodes[cur_pos]);
				for(i=0; i<overlays.length; i++) {overlays[i].className=className+' currentOverlay';}
				slideHolder.setAttribute('currentOverlay',currentOverlay);
				return false;
			}
			break;
		default:
			new_pos=cur_pos+step;
	}
	if(slideShowCircularMode && new_pos == numberSlides) new_pos=0;
	if(slideShowCircularMode && new_pos<0) new_pos=(numberSlides - 1);
	if(step!=0 && new_pos>=0 && new_pos<numberSlides) {
		slideHolder.childNodes[cur_pos].style.display='none';
		slideHolder.childNodes[new_pos].style.display='block';
		slideHolder.setAttribute('currentslide',new_pos);
		var numberOverlays = parseFloat(slideHolder.childNodes[new_pos].getAttribute('numberOverlays'));
		if(step=="p"){
			var currentOverlay=numberOverlays;
			var state=' previousOverlay';
		} else {
			var currentOverlay=0;
			var state=' nextOverlay';
		}
		slideHolder.setAttribute('currentOverlay',currentOverlay);
		if(numberOverlays>0) {
			for(var i=1; i<=numberOverlays; i++){
				var className="Overlay"+i;
				var overlays=getElementsByClass(className,slideHolder.childNodes[new_pos]);
				for(var j=0; j<overlays.length; j++) {overlays[j].className=className+state;}
			}
			if(step=="p"){
				var className="Overlay"+numberOverlays;
				var overlays=getElementsByClass(className,slideHolder.childNodes[new_pos]);
				for(var j=0; j<overlays.length; j++) {overlays[j].className=className+' currentOverlay';}
			}
		}
		new_pos++;
		var indexNumbers = document.getElementById('indexNumbers');
		indexNumbers.firstChild.data = new_pos+'/'+numberSlides;
		if((new_pos==numberSlides) && !slideShowCircularMode && autoAdvance) clearInterval(autoAdvance);
		return true;
	}
	return false;
}

function tocShowSlide(e) {
	if (!e) var e = window.event;
	var target = resolveTarget(e);
	var slide = target.getAttribute('slideNumber');
	var cur_pos = document.getElementById('slideContainer').getAttribute('currentslide');
	var step = slide-cur_pos;
	if(step!=0) GoToSlide(step);
	showHideTOC('none');
	return;
}

//Toggle the display of the table of contents
function showHideTOC(display){
	var toc = document.getElementById('toc');
	//Reset the input box
	document.getElementById('jumpInput').value = "";
	if (display == null || display.length == null){
		if (toc.style.display == 'none' || toc.style.display == ''){
			toc.style.display = 'block';
			document.getElementById('jumpInput').focus();
		} else {
			toc.style.display = 'none';
		}
	} else {
		toc.style.display = display;
		if (display == 'block')
			document.getElementById('jumpInput').focus();
	}
}

function padZero(x){return (x>=10 || x<0 ? "" : "0")+x;}

setClock = function(){
	var actualTime = new Date();
	var newTime = actualTime.getTime() - clockStartTime;
	newTime = clockMultiplier*newTime+clockInterval+clockCorrection;
	actualTime.setTime(newTime);
	newTime = padZero(actualTime.getHours()) + ":" + padZero(actualTime.getMinutes());
//+ ":" + padZero(actualTime.getSeconds());
	var clock = document.getElementById('slideClock');
	clock.firstChild.nodeValue = newTime;
}

function resetClock(){
	var time = new Date(0);
	if(clockStartTime>time){
		var startTime = new Date();
		clockStartTime=startTime.getTime();
	}
}

var title;
var place;
var autoAdvance=null;
var slideClock=null;
var noOverlays=false;
var noClicks=false;
var forceRefresh=false;
var time = 0;
var slideShowCircularMode;
var slideShowStyleSheet;
var slideShowParams;
var clockMultiplier;
var clockInterval;
var clockCorrection=0;
var clockStartTime;
var openTiddlers;

config.macros.slideShow.handler = function(aPlace,macroName,params,wikifier,paramString,tiddler){
	if(tiddler instanceof Tiddler){
		var lingo = config.views.wikified.slideShow;
		if (!e) var e = window.event;
 		place = aPlace;
		title = tiddler.title;
		params = reparse(paramString);
		var onclick = function(){config.macros.slideShow.onClickSlideShow(params);};
		createTiddlyButton(aPlace,lingo.text,lingo.tooltip,onclick);
	}
}

config.macros.slideShow.onClickSlideShow = function(newParams) {
//	if(typeof(newParams)=="number") newParams=slideShowParams;
	openTiddlers = new Array;
	var viewer=document.getElementById('tiddlerDisplay');
	for(var i=0; i<viewer.childNodes.length; i++){
		var name = viewer.childNodes[i].getAttribute('tiddler');
		openTiddlers.push(name);
	}
	document.oncontextmenu = function(e){return false;}
	clockMultiplier = 1;
	clockInterval = 0;
	var startTime = new Date(0);
	slideShowCircularMode = false;
	time = 0;
	slideShowStyleSheet = null;
	if(newParams['style']){
		slideShowStyleSheet = eval(newParams['style']);
	} 
	if(newParams['repeat']){
		slideShowCircularMode = true;
	}
	if(newParams['noClicks']){
		noClicks = true;
	}
	if(newParams['forceRefresh']){
		forceRefresh = true;
	}
	if(newParams['slidePause'] > 0){
		time = newParams['slidePause'];
	}
	if(newParams['clock']){
		clockCorrection=startTime.getTimezoneOffset()*60000;
		startTime = new Date();
		var clockType= eval(newParams['clock']);
		if(clockType != '+') {
			clockMultiplier = -1;
			clockInterval = -clockType*60000;
		}
	}
	clockStartTime=startTime.getTime();
	if(newParams['noOverlays']){
		noOverlays = true;
	}
	clearMessage();
	//Attach the key and mouse listeners
	document.onkeyup = keys;
	document.onmouseup = clicker;
	story.refreshTiddler(title,"SlideShowViewTemplate",true);
	createSlides(newParams);
	slideClock=setInterval('setClock()', 1000); 
	if(time>0) autoAdvance=setInterval("GoToSlide(1)", time); 
	story.closeAllTiddlers(title);
	toggleSlideStyles();
	return;
}

config.macros.slideShow.endSlideShow=function(){
	var showHolder = document.getElementById('slideShowWrapper');
	showHolder.parentNode.removeChild(showHolder);
	document.oncontextmenu =  function(e){};
	if(autoAdvance) clearInterval(autoAdvance);
	if(slideClock) clearInterval(slideClock);
	noClicks=false;
	story.refreshTiddler(title,null,true);
	story.closeAllTiddlers();
	toggleSlideStyles();
	story.displayTiddlers(null,openTiddlers,DEFAULT_VIEW_TEMPLATE);
	document.onmouseup = function(){};
}

function isInteger(s){
	var i;
	for (i = 0; i < s.length; i++){
		// Check that current character is number.
		var c = s.charAt(i);
		if (((c < "0") || (c > "9"))) return false;
	}
	// All characters are numbers.
	return true;
}

function jumpInputToSlide(e){
	if (!e) {
		e = window.event;
		e.which = e.keyCode;
	}
	if(e.which==13){
		var jumpInput= document.getElementById("jumpInput").value;
		if(isInteger(jumpInput)){
			var step=jumpInput-document.getElementById('slideContainer').getAttribute('currentslide')-1;
			if (GoToSlide(step)){
				showHideTOC('none'); 
			}
		}
	}
	return;
}

//Used to shorten the TOC fields
function abbreviateLabel(label){
	var maxTOCLength = config.macros.slideShow.maxTOCLength;
	if(label.length>maxTOCLength) {
		var temp = new Array();
		temp = label.split(' ');
		label = temp[0];
		for(var j=1; j<temp.length; j++){
			if((label.length+temp[j].length)<=maxTOCLength){
				label += " " + temp[j];
			} else {
				label += " ...";
				break;
			}
		}
	}
	return label;
}

function createSlides(newParams){
	var lingo = config.views.wikified.slideShow;
	//Remove dblClick on edit function
	var theTiddler = document.getElementById("tiddler"+title);
	theTiddler.ondblclick = function() {};
	// Grab the 'viewer' element and give it a signature so the show can be resumed if stopped
	var tiddlerElements = theTiddler.childNodes;
	var viewer;
	for (var i = 0; i < tiddlerElements.length; i++){
		if (tiddlerElements[i].className == "viewer") viewer = tiddlerElements[i];
	}
	viewer.id = 'slideShowWrapper';
	//Hide the text that comes before the first H1 element (I think I may put this into a cover page type thing)
	while(viewer.childNodes.length > 0 && viewer.firstChild.nodeName.toUpperCase() != "HR" && viewer.firstChild.className!="slideSeparator") {
		viewer.removeChild(viewer.firstChild);
	}
	//Cycle through the content and each time you hit an H1 begin a new slide div
	var slideNumber = 0;
	var slideHolder = document.createElement('DIV');
	slideHolder.id = "slideContainer";
	slideHolder.setAttribute('currentslide',0);

	while(viewer.childNodes.length > 0){
		//Create a new slide a append it to the slide holder
		if (viewer.firstChild.nodeName.toUpperCase() == "HR" && viewer.firstChild.className=="slideSeparator"){
			slideNumber++;
			var slide = document.createElement('DIV');
			slide.id = "slideNumber"+slideNumber;
			slide.className = "slide";
			if (slideNumber > 1) {
				//slideHolder.setAttribute('currentslide',0);
				slide.style.display='none';
			} else {
				slide.style.display='block';
			}
			slideHolder.appendChild(slide); 
			viewer.removeChild(viewer.firstChild);
		} else {
			if(viewer.firstChild.nodeName=="SPAN" && viewer.firstChild.className=="" && viewer.firstChild.hasChildNodes()) {
				var anchor=viewer.firstChild.nextSibling;
				for (var ii=0;ii<viewer.firstChild.childNodes.length;ii++) {
					var clone=viewer.firstChild.childNodes[ii].cloneNode(true);
					viewer.insertBefore(clone,anchor);
				}
				viewer.removeChild(viewer.firstChild);
			} else {
				slide.appendChild(viewer.firstChild);
			}
		}
	} 
	//Stick the slides back into the viewer

	var blanker= createTiddlyElement(viewer,"DIV","slideBlanker");
	blanker.style.display="none";

	viewer.appendChild(slideHolder);
	slideHolder.setAttribute('numberSlides',slideNumber);
	//Create the navigation bar
	var slidefooter = createTiddlyElement(viewer,"DIV","slideFooter","slideFooterOff");
	var navigator = createTiddlyElement(slidefooter,"SPAN","navigator");
	//Make it so that when the footer is hovered over the class will change to make it visible
	slidefooter.onmouseover = function () {slidefooter.className = "slideFooterOn"};
	slidefooter.onmouseout = function () {slidefooter.className = "slideFooterOff"};
	//Create the control button for the navigation 
	var onClickQuit = function(){config.macros.slideShow.endSlideShow();};
	createTiddlyButton(navigator,lingo.quit.text,lingo.quit.tooltip,onClickQuit);
	createTiddlyButton(navigator,lingo.firstSlide.text,lingo.firstSlide.tooltip,first_slide);
	createTiddlyButton(navigator,lingo.previousSlide.text,lingo.previousSlide.tooltip,previous_slide);
	createTiddlyButton(navigator,lingo.nextSlide.text,lingo.nextSlide.tooltip,next_slide);
	createTiddlyButton(navigator,lingo.lastSlide.text,lingo.lastSlide.tooltip,last_slide); 
	createTiddlyButton(navigator,lingo.resetClock.text,lingo.resetClock.tooltip,resetClock,"button","slideClock");
	var indexNumbers = createTiddlyElement(slidefooter,"SPAN","indexNumbers","indexNumbers","1/"+slideNumber)
	indexNumbers.onclick = showHideTOC;
	var toc = createTiddlyElement(slidefooter,"UL","toc");
	var ovl=1;
	for (var i=0;i<slideHolder.childNodes.length;i++) {
		if(!noOverlays) {
			var ovl=1;
			while(1){
				var className="Overlay"+ovl;
				var overlays=getElementsByClass(className,slideHolder.childNodes[i]);
				if(overlays.length>0){
					for(var j=0; j<overlays.length; j++) {overlays[j].className+=' nextOverlay';}
					ovl++;
				} else {break;}
			}
		}
		slideHolder.childNodes[i].setAttribute("numberOverlays",ovl-1);
		slideHolder.setAttribute("currentOverlay",0);
		//Loop through each slide and check the header's content
		var tocLabel = null; 
		for (var j=0;j<slideHolder.childNodes[i].childNodes.length;j++) {
			var node = slideHolder.childNodes[i].childNodes[j];
			if(node.nodeName=="H1" || node.nodeName=="H2" || node.nodeName=="H3" || node.nodeName=="H4") {
				var htstring = node.innerHTML;
				var stripped = htstring.replace(/(<([^>]+)>)/ig,"");
				tocLabel = abbreviateLabel(stripped);
				var tocLevel="tocLevel"+node.nodeName.charAt(1);
				var tocItem = createTiddlyElement(toc,"LI",null,tocLevel);
				var tocLink = createTiddlyElement(tocItem,"A",null,"tocItem",tocLabel);
				tocLink.setAttribute("slideNumber",i);
				tocLink.onclick=tocShowSlide;
			}
		}
	}
	//Input box to jump to s specific slide
	var tocItem = createTiddlyElement(toc,"LI",null,"tocJumpItem",config.macros.slideShow.messages.gotoLabel);
	var tocJumpInput = createTiddlyElement(tocItem,"INPUT","jumpInput");
	tocJumpInput.type="text";
	tocJumpInput.onkeyup=jumpInputToSlide;
}

var next_slide= function(e){GoToSlide(1);}
var first_slide= function(e){GoToSlide("f");}
var previous_slide= function(e){GoToSlide(-1);}
var last_slide= function(e){GoToSlide("l");}

function toggleSlideStyles(){
	var contentWrapper = document.getElementById('contentWrapper');
	if (contentWrapper.className == "slideShowMode"){
		contentWrapper.className = "";
		refreshPageTemplate();
		setStylesheet("#backstageShow{display: block;}","SlideShowStyleSheet"); 
		changeStyleSheet();
	} else{
		contentWrapper.className = "slideShowMode";
		refreshPageTemplate("SlideShowPageTemplate");
		setStylesheet(store.getRecursiveTiddlerText("SlideShowStyleSheet"),"SlideShowStyleSheet");
		if(slideShowStyleSheet) changeStyleSheet(slideShowStyleSheet);
	}
}

config.shadowTiddlers.SlideShowPageTemplate="<!--{{{-->\n<div id='displayArea'>\n<div id='tiddlerDisplay'></div>\n</div>\n<!--}}}-->";

config.shadowTiddlers.SlideShowViewTemplate="<!--{{{-->\n<div class='title' macro='view title'></div>\n<div class='viewer' macro='view text wikified'></div>\n<!--}}}-->";

config.shadowTiddlers.SlideShowStyleSheet = "/***\n!Slide Mode Styles\n***/\n/*{{{*/\n#slideBlanker {\n position:absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n z-index: 90; \n background-color: #000;\n}\n#backstageShow{\n display: none !important;\n}\n\n#contentWrapper.slideShowMode #slideContainer{\n display: block;\n}\n\n#contentWrapper.slideShowMode .Comment{\n display: none;\n}\n\n#contentWrapper.slideShowMode .nextOverlay{\n visibility: hidden;\n}\n\n#contentWrapper.slideShowMode .currentOverlay{\n visibility: visible;\n}\n\n#contentWrapper.slideShowMode .previousOverlay{\n visibility: visible;\n}\n\n#jump{\n text-align: right;\n}\n\n.slideFooterOff #navigator{\n visibility: hidden;\n}\n\n.slideFooterOn #navigator{\n visibility: visible;\n}\n\n#contentWrapper.slideShowMode #slideClock{\n cursor: pointer; margin: 0 5px 0 5px; border: 1px solid #db4\n}\n\n#contentWrapper.slideShowMode,\n #contentWrapper.slideShowMode #displayArea{\n width: 100%;\n font-size: 1.5em;\n margin: 0 !important;\n padding: 0;\n}\n\n#slideContainer{\n display: none;\n}\n\n.indexNumbers{\n cursor: pointer;\n}\n\n#navigator{\n visibility: hidden;\n bottom: 0;\n}\n\n#toc{\n display: none;\n position: absolute;\n font-size: .75em;\n bottom: 2em;\n right: 0;\n background: #fff;\n border: 1px solid #000;\n text-align: left;\n}\n\nul#toc, #toc li{\n margin: 0;\n padding: 0;\n list-style: none;\n line-height: 1em;\n}\n\n.tocJumpItem{\n margin-right: 2em;\n}\n\n.tocJumpItem input{\nmargin-right: 1em;\n border: 0;\n}\n\n#toc a,\n#toc a.button{\n display: block;\n padding: .1em;\n}\n\n#toc .tocLevel1{\nfont-size: .8em;\n}\n\n#toc .tocLevel2{\n margin-left: 1em;\n font-size: .75em;\n}\n\n#toc .tocLevel3{\n margin-left: 2em;\nfont-size: .75em;\n}\n\n#toc .tocLevel4{\n margin-left: 3em;\nfont-size: .65em;\n}\n\n#toc a{\n cursor: pointer;\n}\n\nh1{\n min-height: 1em;\n}\n\n.slide h1{\n min-height: 0;\n}\n\n/* The '>' selector is ignored by IE6 and earlier so the proper rules are given */\n#slideFooter{\n position: fixed;\n bottom: 2px;\n right: 2px;\n width: 100%;\n text-align: right;\n}\n\n/* This is a hack to trick IE6 and earlier to put the navbar on the bottom of the page */\n* html #slideFooter {\n position: absolute;\n width: 100%;\n text-align: right;\n right: auto; bottom: auto;\n left: expression( ( -20 - slideFooter.offsetWidth + ( document.documentElement.clientWidth ? document.documentElement.clientWidth : document.body.clientWidth ) + ( ignoreMe2 = document.documentElement.scrollLeft ? document.documentElement.scrollLeft : document.body.scrollLeft ) ) + 'px' );\n top: expression( ( -10 - slideFooter.offsetHeight + ( document.documentElement.clientHeight ? document.documentElement.clientHeight : document.body.clientHeight ) + ( ignoreMe = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop ) ) + 'px' );\n}\n\n\n\n/*}}}*/";

config.shadowTiddlers.SlideShowPluginDoc="The documentation is missing. It is available [[here|http://www.math.ist.utl.pt/~psoares/addons.html#SlideShowPluginDoc]].";
//}}}
!Description
This plugin turns a TiddlyWiki tiddler into a simple slide show type display. Most features that are usually found in presentation software are available. It should work in a way that does not interfere with TiddlyWiki. When you close the slide show you get back to your good old TW. 

This plugin has been tested in Firefox and Internet Explorer. Let me know if something seems broken.
!Usage
To use this plugin you //must// be using TiddlyWiki 2.0. Some optional features (as the incremental display) require version 2.0.8 or higher. To install the plugin copy the tiddlers SlideShowPlugin, SlideShowPageTemplate and SlideShowViewTemplate to your TW, label the first one with the //systemConfig// tag, save the TW and refresh the browser.

To make a slide show simply drop {{{<<slideShow>>}}} at the beginning of a tiddler and use {{{-s-}}} to start each slide. 

If you move your mouse over the bottom of the browser window you will see a few navigation buttons, a clock and a table of contents that shows up when you click the slide number.

Any block of text marked as {{{{{Comment{For my eyes only!}}}}}} will not be displayed in the slide show.

See these and other features in this [[SlideShowExample]].
!Incremental display
A succession of overlays (or layers) can be defined in each slide by marking blocks of text with {{{{{Overlay1{...some text...}}}}}}, {{{{{Overlay2{...some text...}}}}}}, {{{{{Overlay3{...some text...}}}}}}, ...

To costumize the way overlays are shown you can redefine the following CSS classes
*contentWrapper.slideShowMode .previousOverlay 
*contentWrapper.slideShowMode .currentOverlay 
*contentWrapper.slideShowMode .nextOverlay 
in a ~StyleSheet. The default style simply hides the next overlays and shows the current and the previous ones as normal text.
!Slide show parameters
*The slide show can be themed by providing a ~StyleSheet ({{{<<slideShow style:'MyStyleSheet'>>}}})
*By default, there is a clock at bottom of the browser window that displays the current time. This clock can also show the presentation elapsed time with {{{<<slideShow clock:'+'>>}}} or a countdown clock with {{{<<slideShow clock:'-20'>>}}} (for 20 minutes). In these two cases, if you click on the clock display it will be restarted
*The slide show can be set to loop ({{{<<slideShow repeat>>}}})
*You can set it so each slide changes after X milliseconds ({{{<<slideShow slidePause:X>>}}}) (auto advance mode)
*To not use the mouse to navigate through the presentation use  {{{<<slideShow noClicks>>>}}}. This is useful when there are clickable elements in the presentation
*{{{<<slideShow forceRefresh>>>}}} forces a refresh of the presentation tiddler (useful when a presentation is built from separate tiddlers using the {{{<<tiddler>>}}} macro)
*Overlays can be disabled  with {{{<<slideShow noOverlays>>}}}
*These parameters can be mixed and matched in any order: {{{<<slideShow slidePause:1000 repeat>>}}} is the same as {{{<<slideShow repeat slidePause:1000>>}}}
!Slide show navigation
You can navigate through a slide show using the keyboard or the mouse. To quickly move to titled sections you can use the table of contents. 
!!Mouse navigation
Left (right) clicking on a slide jumps to the next (previous) overlay. To move to the beginning of the next or previous slide you must use the navigation bar at the bottom of the browser's window. If there are no overlays defined both operations are equivalent.
!!Keyboard
The following keys are defined:
*Left arrow - previous overlay
*Down arrow - previous slide
*Right arrow - next overlay
*Up arrow - next slide
*Home - first slide
*End - last slide
*Escape - exit slide show
*Spacebar - pause/resume slide show in auto advance mode
*B - blank screen
!Revision history
*1.6
**removed seconds from clock
**added B key to blank screen
**a few fixes to make it work with IE7
*1.5.3
**fix for ~TW2.2
**forceRefresh and noClicks
**removed autoStart feature
**templates are now in shadow tiddlers
*1.5.2 13/02/2007
**fixed a conflict with TW pageFooter
*1.5.1 10/11/2006
**added SlideShowPageTemplate and SlideShowViewTemplate. This way, the plugin no longer requires a standard TW layout. Thanks to Andrew Lister for the idea.
*1.5.0 18/09/2006
**fixed restoring stylesheet on exit
**changed (again!) the way how slides are separated (slide shows prepared for previous versions must be fixed)
*1.4.0 20/04/2006
**changed the way how slides are separated (slide shows prepared for previous versions must be fixed)
**now works with content included with the {{{<<tiddler>>}}} macro
**added incremental display (overlays)
**improved documentation
**assorted small fixes
*1.3.1 10/03/2006
**removed empty slide titles
**fixed wrong numberSlides when slides have div's
**fixed wrong time in Windows
*1.3.0 26/02/2006
**restore open tiddlers on exit
**fixed problem with markup in headers (should work with NestedSlidersPlugin)
**added slide comments (blocks of text in the tiddler that don't show up in the presentation)
*1.2.1 28/01/2006
**pause timed slideshow with spacebar
**added clock with 3 different modes
**fixed bugs with style and abbreviation options
**general cleanup
*1.2.0 07/01/2006
**added a resume feature
**added themes support
*1.1.5 14/12/2005
**added mouse support
**cleaned up navbar generation
*1.1.0 12/12/2005
**added support for IE
**added key listeners
*1.0.0 11/12/2005
**initial release
!Todo
*Time code is still very hackerish and unreliable.
/***

''Inspired by [[TiddlyPom|http://www.warwick.ac.uk/~tuspam/tiddlypom.html]]''

|Name|SplashScreenPlugin|
|Created by|SaqImtiaz|
|Location|http://tw.lewcid.org/#SplashScreenPlugin|
|Version|0.21 |
|Requires|~TW2.08+|
!Description:
Provides a simple splash screen that is visible while the TW is loading.

!Installation
Copy the source text of this tiddler to your TW in a new tiddler, tag it with systemConfig and save and reload. The SplashScreen will now be installed and will be visible the next time you reload your TW.

!Customizing
Once the SplashScreen has been installed and you have reloaded your TW, the splash screen html will be present in the MarkupPreHead tiddler. You can edit it and customize to your needs.

!History
* 20-07-06 : version 0.21, modified to hide contentWrapper while SplashScreen is displayed.
* 26-06-06 : version 0.2, first release

!Code
***/
//{{{
var old_lewcid_splash_restart=restart;

restart = function()
{   if (document.getElementById("SplashScreen"))
        document.getElementById("SplashScreen").style.display = "none";
      if (document.getElementById("contentWrapper"))
        document.getElementById("contentWrapper").style.display = "block";
    
    old_lewcid_splash_restart();
   
    if (splashScreenInstall)
       {if(config.options.chkAutoSave)
			{saveChanges();}
        displayMessage("TW SplashScreen has been installed, please save and refresh your TW.");
        }
}


var oldText = store.getTiddlerText("MarkupPreHead");
if (oldText.indexOf("SplashScreen")==-1)
   {var siteTitle = store.getTiddlerText("SiteTitle");
   var splasher='\n\n<style type="text/css">#contentWrapper {display:none;}</style><div id="SplashScreen" style="border: 3px solid #ccc; display: block; text-align: center; width: 320px; margin: 100px auto; padding: 50px; color:#000; font-size: 28px; font-family:Tahoma; background-color:#eee;"><b>'+siteTitle +'</b> is loading<blink> ...</blink><br><br><span style="font-size: 14px; color:red;">Requires Javascript.</span></div>';
   if (! store.tiddlerExists("MarkupPreHead"))
       {var myTiddler = store.createTiddler("MarkupPreHead");}
   else
      {var myTiddler = store.getTiddler("MarkupPreHead");}
      myTiddler.set(myTiddler.title,oldText+splasher,config.options.txtUserName,null,null);
      store.setDirty(true);
      var splashScreenInstall = true;
}
//}}}
Storage considerations for a big data infrastructure
Sarah Wilson 20130904

According to Jon Toigo, CEO and managing principal of Toigo Partners International and chairman of the Data Management Institute, big data analytics once referred to the process of mining large amounts of data to find specific pieces of information, but the term big data is now commonly used in a broader sense to describe large volumes of growing data.

Toigo believes object storage is one of the best ways to achieve a successful big data infrastructure because of the level of granularity it allows when managing storage. He even sees it as the "future of storage." But when determining how to store big data, he said, administrators must first consider what the big data is being used for; for example, capacity demand might be more important to one big data infrastructure than privacy is to another.

In this podcast with associate site editor Sarah Wilson, Toigo shares his thoughts on what big data is, the best ways to store it and some of the problems storage administrators of big data infrastructures might come across. Listen to the podcast or read the transcript below.

''What are some of the storage challenges IT pros face in a big data infrastructure?''

Jon Toigo: Well, first of all, I think we have to figure out what we mean by big data. The first usage I heard of the term -- and this was probably four or five years ago -- referred to the combination of multiple databases and, in some cases, putting unstructured data into some kind of framework to mirror real-time analysis. The point was we were going to gather all this data together. We were going to associate it with each other, and we were going to allow the data, in many cases, to inform us of changes and give us information that was useful.

The classic case was finding a terror suspect based on what you know about the potential terrorist maybe [using] the documentation he has from various countries, the airline booking databases that are out there for major airlines and the routes he might take, vehicle renting information if he's going to rent a vehicle and fill it with explosives -- all these things could be correlated. It was finding that proverbial needle in a haystack, and that was what big data analysis was all about. Another use was spotting potential voter fraud by looking at death records and drivers' licenses, white pages directory listings and voter registration databases, and combining all that stuff to look for folks who registered to vote who may already be deceased.

The bottom line is that these were the classic examples that we were going to use big data analytics for. And it expresses both what big data is and what big data analytics are. Big data is simply the collection of stuff to be analyzed. Today, I'm hearing a lot of vendors use the term big data to refer to just about anything. It's a reference to the reality that we all confront -- we've got a lot of data and it's growing, mostly in the form of files, and we have problems curating that data, storing it, and using it efficiently and cost-effectively. So like most terms these days, big data seems to have been co-opted by marketers, and now it means whatever the marketing department says it means for the marketing department that's articulating the value.

So problem No. 1 is to define what you mean by big data. And then we get into a whole other set of problems when figuring out how to store a growing volume of data for a really long time versus finding a way to stand up many data sources that can be used collectively to achieve some analytical purpose.

So if you understand what I'm saying, the challenge here is diffused by the fact that nobody has a good definition for what big data is.

''In the case of really large volumes of data, what makes object storage so popular?''

Toigo: First of all, I think object storage is the future of storage, and I don't know anybody who would disagree with that. There are a lot of vendors who are kind of ahead of the curve, and they're evangelizing it. Object storage is like the next evolution of how we're going to store data. It's the only way to wrangle files, which now constitute over half of the data we're storing. And they're mostly controlled by users so we don't have a lot of information about what's going on inside that file. It's sort of an anonymous piece of data. If we want to create some sort of organized methodology for storing them for a period of time -- maybe migrate them through a tiering process and pay attention to what their relevance is from a business standpoint -- we're going to need a more granular way to do data management, and that's what object storage has offered to do for a very long time.

Theoretically, certain types of big data analysis processes could be facilitated by object storage. For those who focus on metadata -- counting operations, for example -- object storage removes some of the problems associated with unstructured data, depending on how you implement the object-oriented system itself. It could allow a mix and match of certain kinds of files, plus reorganization for comparative purposes and so forth. A company called Caringo is one I've been following for about five years now, and it has a great story to tell in this space; [it's] been evangelizing object storage with zeal for quite some time.

The one caveat is that there are a lot of different protocols for doing object storage that started to appear in the market, partly because of the popularity and trendiness of things like big data. And like so many technologies, the industry seems absolutely hell-bent on creating exclusive stovepipe object storage methodologies that are going to create issues downstream for mixing and matching data organized using different object storage paradigms. I think that's going to hurt, for example, the use of clouds as object storage repositories, because you're going to have multiple clouds, and each cloud might be organized around a different object storage paradigm and it won't be able to share its data with another cloud. That could be a big impediment going forward.

Object storage basically is a way to put some additional value -- think of it as an additional metadata construct -- over the top of the file and give it a unique identifier so it doesn't get stepped on, and [you can] include it in some sort of a database structure so you're able to move it around, use it and reference it. If you think about the way the NSA [National Security Agency] is supposedly using telephone record data and all these conflicts that have come out, they're not interested in the contents of the telephone conversation specifically; they're interested in the network of contacts [or] the relationships between data. That's something object storage would be ideally suited for: a mechanism to connect the dots and show metadata relationships between data as opposed to the contents of the data itself. So in terms of the number of people who visit a website, it's not as important for me to know which people visited that website as [it is to know] the number of people who came there after a certain article was posted. These are places where simple counting operations may substitute for a detailed analysis of what's going on inside the file. So I see object storage definitely as the future. Will we get there in my lifetime? I don't know; it might just be like how long we've been waiting on holographic storage.

''In addition to object storage, what other types of storage are best for a big data infrastructure?''

Toigo: Now, again, this comes down to what you want to do with your big data. There are some practical issues obviously to consider. For example, you may need to have a method for reducing the amount of space that's occupied by big data to constrain storage capacity demand and the associated expense, and you'll need a way to do that that doesn't impact your object storage method. So if you use object storage, your ability to derive information expeditiously might be confused if you take these object-oriented data entries and compress them or deduplicate them, or something of that nature. That might spoil that data and make it unusable from an analytical perspective. You need to be very circumspect with what you're going to do with the data, how you're going to store it and, if you're going to reduce it, what the impact of that reduction will be.

Another example is the problem of privacy, which enters into a lot of big data analytics processes. There may be a desire to share data sets. For example, treatment modalities inside health care -- how many people have had [a certain] kind of cancer and what was the effectiveness of a particular drug treatment on that cancer -- but there are constraints in sharing the data that belongs to those health records. HIPAA [Health Insurance Portability and Accountability Act] prevents you from being able to disclose private patient health care. You can't have the patient's name, social security number or patient identification associated with the data itself. That's also a problem with the NSA. That's one of the problems behind the big NSA surveillance program, but it's a big deal for health care's big data efforts in the future.

So how do you minimize the alteration to data to redact sensitive stuff, but don't dilute or harm the data in such a way that it would reduce its value from the standpoint of analytics? Contemporary encryption, which is a technology some people would like to use to protect privacy, is probably not going to work or play well with big data analytics as we understand it today. I chatted with IBM's Jeff Jonas, a chief scientist who deals with their big data stuff, about this at IBM's Edge conference about a month ago, and he expressed a need for what he would call a one-way hash. And for those people who aren't familiar with what a one-way hash is, it's a mechanism that preserves data usefulness and integrity but excludes the sensitive details from the data. He described it this way: You can give somebody some pork and a grinder and they can use it to make sausage, but if you give them sausage and a grinder, they can't reverse-engineer it to make a pig. That would be an ideal way that one-way hashing could be used to retain the value of data without revealing any of the details that are better not shared. So I think about that and say there's still some room for technology improvement here to determine how we're going to share the data and how we're going to store it.

And finally, some continuity planning is sort of my shtick. I find myself asking, if this big data complex -- the infrastructure we're storing this big data on -- is so important and so mission-critical, how are we going to protect it from loss or corruption when all the devices it's stored on are subject to a broad range of problems, whether they be man-made threats or natural threats? I wouldn't deploy a big data complex without figuring out first how to provide its continuity, availability and integrity. So in other words, I'm not going to give you a prescription for the best options on storing data as much as I'm trying to express that there are a number of considerations that you better have in your head before you just start to throw data out there on storage.
/***
|Name:|TagglyTaggingPlugin|
|Description:|tagglyTagging macro is a replacement for the builtin tagging macro in your ViewTemplate|
|Version:|3.3.2a|
|Date:|27-Jun-2011|
|Source:|http://mptw.tiddlyspot.com/#TagglyTaggingPlugin|
|Author:|Simon Baird <simon.baird@gmail.com>|
|License:|http://mptw.tiddlyspot.com/#TheBSDLicense|
!Notes
See http://mptw.tiddlyspot.com/#TagglyTagging
***/
//{{{

merge(String.prototype,{

  parseTagExpr: function(debug) {

    if (this.trim() == "")
      return "(true)";

    var anyLogicOp = /(!|&&|\|\||\(|\))/g;
    var singleLogicOp = /^(!|&&|\|\||\(|\))$/;

    var spaced = this.
      // because square brackets in templates are no good
      // this means you can use [(With Spaces)] instead of [[With Spaces]]
      replace(/\[\(/g," [[").
      replace(/\)\]/g,"]] ").
      // space things out so we can use readBracketedList. tricky eh?
      replace(anyLogicOp," $1 ");

    var expr = "";

    var tokens = spaced.readBracketedList(false); // false means don't uniq the list. nice one JR!

    for (var i=0;i<tokens.length;i++)
      if (tokens[i].match(singleLogicOp))
        expr += tokens[i];
      else
        expr += "tiddler.tags.contains('%0')".format([tokens[i].replace(/'/,"\\'")]); // fix single quote bug. still have round bracket bug i think

    if (debug)
      alert(expr);

    return '('+expr+')';
  }

});

merge(TiddlyWiki.prototype,{
  getTiddlersByTagExpr: function(tagExpr,sortField) {

    var result = [];

    var expr = tagExpr.parseTagExpr();

    store.forEachTiddler(function(title,tiddler) {
      if (eval(expr))
        result.push(tiddler);
    });

    if(!sortField)
      sortField = "title";

    result.sort(function(a,b) {return a[sortField] < b[sortField] ? -1 : (a[sortField] == b[sortField] ? 0 : +1);});

    return result;
  }
});

config.taggly = {

  // for translations
  lingo: {
    labels: {
      asc:        "\u2191", // down arrow
      desc:       "\u2193", // up arrow
      title:      "title",
      modified:   "modified",
      created:    "created",
      show:       "+",
      hide:       "-",
      normal:     "normal",
      group:      "group",
      commas:     "commas",
      sitemap:    "sitemap",
      numCols:    "cols\u00b1", // plus minus sign
      label:      "Tagged as '%0':",
      exprLabel:  "Matching tag expression '%0':",
      excerpts:   "excerpts",
      descr:      "descr",
      slices:     "slices",
      contents:   "contents",
      sliders:    "sliders",
      noexcerpts: "title only",
      noneFound:  "(none)"
    },

    tooltips: {
      title:      "Click to sort by title",
      modified:   "Click to sort by modified date",
      created:    "Click to sort by created date",
      show:       "Click to show tagging list",
      hide:       "Click to hide tagging list",
      normal:     "Click to show a normal ungrouped list",
      group:      "Click to show list grouped by tag",
      sitemap:    "Click to show a sitemap style list",
      commas:     "Click to show a comma separated list",
      numCols:    "Click to change number of columns",
      excerpts:   "Click to show excerpts",
      descr:      "Click to show the description slice",
      slices:     "Click to show all slices",
      contents:   "Click to show entire tiddler contents",
      sliders:    "Click to show tiddler contents in sliders",
      noexcerpts: "Click to show entire title only"
    },

    tooDeepMessage: "* //sitemap too deep...//"
  },

  config: {
    showTaggingCounts: true,
    listOpts: {
      // the first one will be the default
      sortBy:     ["title","modified","created"],
      sortOrder:  ["asc","desc"],
      hideState:  ["show","hide"],
      listMode:   ["normal","group","sitemap","commas"],
      numCols:    ["1","2","3","4","5","6"],
      excerpts:   ["noexcerpts","excerpts","descr","slices","contents","sliders"]
    },
    valuePrefix: "taggly.",
    excludeTags: ["excludeLists","excludeTagging"],
    excerptSize: 50,
    excerptMarker: "/%"+"%/",
    siteMapDepthLimit: 25
  },

  getTagglyOpt: function(title,opt) {
    var val = store.getValue(title,this.config.valuePrefix+opt);
    return val ? val : this.config.listOpts[opt][0];
  },

  setTagglyOpt: function(title,opt,value) {
    // create it silently if it doesn't exist
    if (!store.tiddlerExists(title)) {
      store.saveTiddler(title,title,config.views.editor.defaultText.format([title]),config.options.txtUserName,new Date(),"");

      // <<tagglyTagging expr:"...">> creates a tiddler to store its display settings
      // Make those tiddlers less noticeable by tagging as excludeSearch and excludeLists
      // Because we don't want to hide real tags, check that they aren't actually tags before doing so
      // Also tag them as tagglyExpression for manageability
      // (contributed by RA)
      if (!store.getTaggedTiddlers(title).length) {
        store.setTiddlerTag(title,true,"excludeSearch");
        store.setTiddlerTag(title,true,"excludeLists");
        store.setTiddlerTag(title,true,"tagglyExpression");
      }
    }

    // if value is default then remove it to save space
    return store.setValue(title, this.config.valuePrefix+opt, value == this.config.listOpts[opt][0] ? null : value);
  },

  getNextValue: function(title,opt) {
    var current = this.getTagglyOpt(title,opt);
    var pos = this.config.listOpts[opt].indexOf(current);
    // supposed to automagically don't let cols cycle up past the number of items
    // currently broken in some situations, eg when using an expression
    // lets fix it later when we rewrite for jquery
    // the columns thing should be jquery table manipulation probably
    var limit = (opt == "numCols" ? store.getTaggedTiddlers(title).length : this.config.listOpts[opt].length);
    var newPos = (pos + 1) % limit;
    return this.config.listOpts[opt][newPos];
  },

  toggleTagglyOpt: function(title,opt) {
    var newVal = this.getNextValue(title,opt);
    this.setTagglyOpt(title,opt,newVal);
  },

  createListControl: function(place,title,type) {
    var lingo = config.taggly.lingo;
    var label;
    var tooltip;
    var onclick;

    if ((type == "title" || type == "modified" || type == "created")) {
      // "special" controls. a little tricky. derived from sortOrder and sortBy
      label = lingo.labels[type];
      tooltip = lingo.tooltips[type];

      if (this.getTagglyOpt(title,"sortBy") == type) {
        label += lingo.labels[this.getTagglyOpt(title,"sortOrder")];
        onclick = function() {
          config.taggly.toggleTagglyOpt(title,"sortOrder");
          return false;
        }
      }
      else {
        onclick = function() {
          config.taggly.setTagglyOpt(title,"sortBy",type);
          config.taggly.setTagglyOpt(title,"sortOrder",config.taggly.config.listOpts.sortOrder[0]);
          return false;
        }
      }
    }
    else {
      // "regular" controls, nice and simple
      label = lingo.labels[type == "numCols" ? type : this.getNextValue(title,type)];
      tooltip = lingo.tooltips[type == "numCols" ? type : this.getNextValue(title,type)];
      onclick = function() {
        config.taggly.toggleTagglyOpt(title,type);
        return false;
      }
    }

    // hide button because commas don't have columns
    if (!(this.getTagglyOpt(title,"listMode") == "commas" && type == "numCols"))
      createTiddlyButton(place,label,tooltip,onclick,type == "hideState" ? "hidebutton" : "button");
  },

  makeColumns: function(orig,numCols) {
    var listSize = orig.length;
    var colSize = listSize/numCols;
    var remainder = listSize % numCols;

    var upperColsize = colSize;
    var lowerColsize = colSize;

    if (colSize != Math.floor(colSize)) {
      // it's not an exact fit so..
      upperColsize = Math.floor(colSize) + 1;
      lowerColsize = Math.floor(colSize);
    }

    var output = [];
    var c = 0;
    for (var j=0;j<numCols;j++) {
      var singleCol = [];
      var thisSize = j < remainder ? upperColsize : lowerColsize;
      for (var i=0;i<thisSize;i++)
        singleCol.push(orig[c++]);
      output.push(singleCol);
    }

    return output;
  },

  drawTable: function(place,columns,theClass) {
    var newTable = createTiddlyElement(place,"table",null,theClass);
    var newTbody = createTiddlyElement(newTable,"tbody");
    var newTr = createTiddlyElement(newTbody,"tr");
    for (var j=0;j<columns.length;j++) {
      var colOutput = "";
      for (var i=0;i<columns[j].length;i++)
        colOutput += columns[j][i];
      var newTd = createTiddlyElement(newTr,"td",null,"tagglyTagging"); // todo should not need this class
      wikify(colOutput,newTd);
    }
    return newTable;
  },

  createTagglyList: function(place,title,isTagExpr) {
    switch(this.getTagglyOpt(title,"listMode")) {
      case "group":  return this.createTagglyListGrouped(place,title,isTagExpr); break;
      case "normal": return this.createTagglyListNormal(place,title,false,isTagExpr); break;
      case "commas": return this.createTagglyListNormal(place,title,true,isTagExpr); break;
      case "sitemap":return this.createTagglyListSiteMap(place,title,isTagExpr); break;
    }
  },

  getTaggingCount: function(title,isTagExpr) {
    // thanks to Doug Edmunds
    if (this.config.showTaggingCounts) {
      var tagCount = config.taggly.getTiddlers(title,'title',isTagExpr).length;
      if (tagCount > 0)
        return " ("+tagCount+")";
    }
    return "";
  },

  getTiddlers: function(titleOrExpr,sortBy,isTagExpr) {
    return isTagExpr ? store.getTiddlersByTagExpr(titleOrExpr,sortBy) : store.getTaggedTiddlers(titleOrExpr,sortBy);
  },

  getExcerpt: function(inTiddlerTitle,title,indent) {
    if (!indent)
      indent = 1;

    var displayMode = this.getTagglyOpt(inTiddlerTitle,"excerpts");
    var t = store.getTiddler(title);

    if (t && displayMode == "excerpts") {
      var text = t.text.replace(/\n/," ");
      var marker = text.indexOf(this.config.excerptMarker);
      if (marker != -1) {
        return " {{excerpt{<nowiki>" + text.substr(0,marker) + "</nowiki>}}}";
      }
      else if (text.length < this.config.excerptSize) {
        return " {{excerpt{<nowiki>" + t.text + "</nowiki>}}}";
      }
      else {
        return " {{excerpt{<nowiki>" + t.text.substr(0,this.config.excerptSize) + "..." + "</nowiki>}}}";
      }
    }
    else if (t && displayMode == "contents") {
      return "\n{{contents indent"+indent+"{\n" + t.text + "\n}}}";
    }
    else if (t && displayMode == "sliders") {
      return "<slider slide>\n{{contents{\n" + t.text + "\n}}}\n</slider>";
    }
    else if (t && displayMode == "descr") {
      var descr = store.getTiddlerSlice(title,'Description');
      return descr ? " {{excerpt{" + descr  + "}}}" : "";
    }
    else if (t && displayMode == "slices") {
      var result = "";
      var slices = store.calcAllSlices(title);
      for (var s in slices)
        result += "|%0|<nowiki>%1</nowiki>|\n".format([s,slices[s]]);
      return result ? "\n{{excerpt excerptIndent{\n" + result  + "}}}" : "";
    }
    return "";
  },

  notHidden: function(t,inTiddler) {
    if (typeof t == "string")
      t = store.getTiddler(t);
    return (!t || !t.tags.containsAny(this.config.excludeTags) ||
        (inTiddler && this.config.excludeTags.contains(inTiddler)));
  },

  // this is for normal and commas mode
  createTagglyListNormal: function(place,title,useCommas,isTagExpr) {

    var list = config.taggly.getTiddlers(title,this.getTagglyOpt(title,"sortBy"),isTagExpr);

    if (this.getTagglyOpt(title,"sortOrder") == "desc")
      list = list.reverse();

    var output = [];
    var first = true;
    for (var i=0;i<list.length;i++) {
      if (this.notHidden(list[i],title)) {
        var countString = this.getTaggingCount(list[i].title);
        var excerpt = this.getExcerpt(title,list[i].title);
        if (useCommas)
          output.push((first ? "" : ", ") + "[[" + list[i].title + "]]" + countString + excerpt);
        else
          output.push("*[[" + list[i].title + "]]" + countString + excerpt + "\n");

        first = false;
      }
    }

    return this.drawTable(place,
      this.makeColumns(output,useCommas ? 1 : parseInt(this.getTagglyOpt(title,"numCols"))),
      useCommas ? "commas" : "normal");
  },

  // this is for the "grouped" mode
  createTagglyListGrouped: function(place,title,isTagExpr) {
    var sortBy = this.getTagglyOpt(title,"sortBy");
    var sortOrder = this.getTagglyOpt(title,"sortOrder");

    var list = config.taggly.getTiddlers(title,sortBy,isTagExpr);

    if (sortOrder == "desc")
      list = list.reverse();

    var leftOvers = []
    for (var i=0;i<list.length;i++)
      leftOvers.push(list[i].title);

    var allTagsHolder = {};
    for (var i=0;i<list.length;i++) {
      for (var j=0;j<list[i].tags.length;j++) {

        if (list[i].tags[j] != title) { // not this tiddler

          if (this.notHidden(list[i].tags[j],title)) {

            if (!allTagsHolder[list[i].tags[j]])
              allTagsHolder[list[i].tags[j]] = "";

            if (this.notHidden(list[i],title)) {
              allTagsHolder[list[i].tags[j]] += "**[["+list[i].title+"]]"
                    + this.getTaggingCount(list[i].title) + this.getExcerpt(title,list[i].title) + "\n";

              leftOvers.setItem(list[i].title,-1); // remove from leftovers. at the end it will contain the leftovers

            }
          }
        }
      }
    }

    var allTags = [];
    for (var t in allTagsHolder)
      allTags.push(t);

    var sortHelper = function(a,b) {
      if (a == b) return 0;
      if (a < b) return -1;
      return 1;
    };

    allTags.sort(function(a,b) {
      var tidA = store.getTiddler(a);
      var tidB = store.getTiddler(b);
      if (sortBy == "title") return sortHelper(a,b);
      else if (!tidA && !tidB) return 0;
      else if (!tidA) return -1;
      else if (!tidB) return +1;
      else return sortHelper(tidA[sortBy],tidB[sortBy]);
    });

    var leftOverOutput = "";
    for (var i=0;i<leftOvers.length;i++)
      if (this.notHidden(leftOvers[i],title))
        leftOverOutput += "*[["+leftOvers[i]+"]]" + this.getTaggingCount(leftOvers[i]) + this.getExcerpt(title,leftOvers[i]) + "\n";

    var output = [];

    if (sortOrder == "desc")
      allTags.reverse();
    else if (leftOverOutput != "")
      // leftovers first...
      output.push(leftOverOutput);

    for (var i=0;i<allTags.length;i++)
      if (allTagsHolder[allTags[i]] != "")
        output.push("*[["+allTags[i]+"]]" + this.getTaggingCount(allTags[i]) + this.getExcerpt(title,allTags[i]) + "\n" + allTagsHolder[allTags[i]]);

    if (sortOrder == "desc" && leftOverOutput != "")
      // leftovers last...
      output.push(leftOverOutput);

    return this.drawTable(place,
        this.makeColumns(output,parseInt(this.getTagglyOpt(title,"numCols"))),
        "grouped");

  },

  // used to build site map
  treeTraverse: function(title,depth,sortBy,sortOrder,isTagExpr) {

    var list = config.taggly.getTiddlers(title,sortBy,isTagExpr);

    if (sortOrder == "desc")
      list.reverse();

    var indent = "";
    for (var j=0;j<depth;j++)
      indent += "*"

    var childOutput = "";

    if (depth > this.config.siteMapDepthLimit)
      childOutput += indent + this.lingo.tooDeepMessage + "\n";
    else
      for (var i=0;i<list.length;i++)
        if (list[i].title != title)
          if (this.notHidden(list[i].title,this.config.inTiddler))
            childOutput += this.treeTraverse(list[i].title,depth+1,sortBy,sortOrder,false);

    if (depth == 0)
      return childOutput;
    else
      return indent + "[["+title+"]]" + this.getTaggingCount(title) + this.getExcerpt(this.config.inTiddler,title,depth) + "\n" + childOutput;
  },

  // this if for the site map mode
  createTagglyListSiteMap: function(place,title,isTagExpr) {
    this.config.inTiddler = title; // nasty. should pass it in to traverse probably
    var output = this.treeTraverse(title,0,this.getTagglyOpt(title,"sortBy"),this.getTagglyOpt(title,"sortOrder"),isTagExpr);
    return this.drawTable(place,
        this.makeColumns(output.split(/(?=^\*\[)/m),parseInt(this.getTagglyOpt(title,"numCols"))), // regexp magic
        "sitemap"
        );
  },

  macros: {
    tagglyTagging: {
      handler: function (place,macroName,params,wikifier,paramString,tiddler) {
        var parsedParams = paramString.parseParams("tag",null,true);
        var refreshContainer = createTiddlyElement(place,"div");

        // do some refresh magic to make it keep the list fresh - thanks Saq
        refreshContainer.setAttribute("refresh","macro");
        refreshContainer.setAttribute("macroName",macroName);

        var tag = getParam(parsedParams,"tag");
        var expr = getParam(parsedParams,"expr");

        if (expr) {
          refreshContainer.setAttribute("isTagExpr","true");
          refreshContainer.setAttribute("title",expr);
          refreshContainer.setAttribute("showEmpty","true");
        }
        else {
          refreshContainer.setAttribute("isTagExpr","false");
          if (tag) {
                refreshContainer.setAttribute("title",tag);
            refreshContainer.setAttribute("showEmpty","true");
          }
          else {
                refreshContainer.setAttribute("title",tiddler.title);
            refreshContainer.setAttribute("showEmpty","false");
          }
        }
        this.refresh(refreshContainer);
      },

      refresh: function(place) {
        var title = place.getAttribute("title");
        var isTagExpr = place.getAttribute("isTagExpr") == "true";
        var showEmpty = place.getAttribute("showEmpty") == "true";
        jQuery(place).empty()
        jQuery(place).addClass("tagglyTagging");
        var countFound = config.taggly.getTiddlers(title,'title',isTagExpr).length
        if (countFound > 0 || showEmpty) {
          var lingo = config.taggly.lingo;
          config.taggly.createListControl(place,title,"hideState");
          if (config.taggly.getTagglyOpt(title,"hideState") == "show") {
            createTiddlyElement(place,"span",null,"tagglyLabel",
                isTagExpr ? lingo.labels.exprLabel.format([title]) : lingo.labels.label.format([title]));
            config.taggly.createListControl(place,title,"title");
            config.taggly.createListControl(place,title,"modified");
            config.taggly.createListControl(place,title,"created");
            config.taggly.createListControl(place,title,"listMode");
            config.taggly.createListControl(place,title,"excerpts");
            config.taggly.createListControl(place,title,"numCols");
            config.taggly.createTagglyList(place,title,isTagExpr);
            if (countFound == 0 && showEmpty)
              createTiddlyElement(place,"div",null,"tagglyNoneFound",lingo.labels.noneFound);
          }
        }
      }
    }
  },

  // todo fix these up a bit
  styles: [
"/*{{{*/",
"/* created by TagglyTaggingPlugin */",
".tagglyTagging { padding-top:0.5em; }",
".tagglyTagging li.listTitle { display:none; }",
".tagglyTagging ul {",
" margin-top:0px; padding-top:0.5em; padding-left:2em;",
" margin-bottom:0px; padding-bottom:0px;",
"}",
".tagglyTagging { vertical-align: top; margin:0px; padding:0px; }",
".tagglyTagging table { margin:0px; padding:0px; }",
".tagglyTagging .button { visibility:hidden; margin-left:3px; margin-right:3px; }",
".tagglyTagging .button, .tagglyTagging .hidebutton {",
" color:[[ColorPalette::TertiaryLight]]; font-size:90%;",
" border:0px; padding-left:0.3em;padding-right:0.3em;",
"}",
".tagglyTagging .button:hover, .hidebutton:hover, ",
".tagglyTagging .button:active, .hidebutton:active  {",
" border:0px; background:[[ColorPalette::TertiaryPale]]; color:[[ColorPalette::TertiaryDark]];",
"}",
".selected .tagglyTagging .button { visibility:visible; }",
".tagglyTagging .hidebutton { color:[[ColorPalette::Background]]; }",
".selected .tagglyTagging .hidebutton { color:[[ColorPalette::TertiaryLight]] }",
".tagglyLabel { color:[[ColorPalette::TertiaryMid]]; font-size:90%; }",
".tagglyTagging ul {padding-top:0px; padding-bottom:0.5em; margin-left:1em; }",
".tagglyTagging ul ul {list-style-type:disc; margin-left:-1em;}",
".tagglyTagging ul ul li {margin-left:0.5em; }",
".editLabel { font-size:90%; padding-top:0.5em; }",
".tagglyTagging .commas { padding-left:1.8em; }",
"/* not technically tagglytagging but will put them here anyway */",
".tagglyTagged li.listTitle { display:none; }",
".tagglyTagged li { display: inline; font-size:90%; }",
".tagglyTagged ul { margin:0px; padding:0px; }",
".excerpt { color:[[ColorPalette::TertiaryDark]]; }",
".excerptIndent { margin-left:4em; }",
"div.tagglyTagging table,",
"div.tagglyTagging table tr,",
"td.tagglyTagging",
" {border-style:none!important; }",
".tagglyTagging .contents { border-bottom:2px solid [[ColorPalette::TertiaryPale]]; padding:0 1em 1em 0.5em;",
"  margin-bottom:0.5em; }",
".tagglyTagging .indent1  { margin-left:3em;  }",
".tagglyTagging .indent2  { margin-left:4em;  }",
".tagglyTagging .indent3  { margin-left:5em;  }",
".tagglyTagging .indent4  { margin-left:6em;  }",
".tagglyTagging .indent5  { margin-left:7em;  }",
".tagglyTagging .indent6  { margin-left:8em;  }",
".tagglyTagging .indent7  { margin-left:9em;  }",
".tagglyTagging .indent8  { margin-left:10em; }",
".tagglyTagging .indent9  { margin-left:11em; }",
".tagglyTagging .indent10 { margin-left:12em; }",
".tagglyNoneFound { margin-left:2em; color:[[ColorPalette::TertiaryMid]]; font-size:90%; font-style:italic; }",
"/*}}}*/",
    ""].join("\n"),

  init: function() {
    merge(config.macros,this.macros);
    config.shadowTiddlers["TagglyTaggingStyles"] = this.styles;
    store.addNotification("TagglyTaggingStyles",refreshStyles);
  }
};

config.taggly.init();

//}}}

/***
InlineSlidersPlugin
By Saq Imtiaz
http://tw.lewcid.org/sandbox/#InlineSlidersPlugin

// syntax adjusted to not clash with NestedSlidersPlugin
// added + syntax to start open instead of closed

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

//}}}
/***
|''Name:''|TiddlerNotesPlugin|
|''Description:''|Add notes to tiddlers without modifying the original content|
|''Author:''|Saq Imtiaz ( lewcid@gmail.com )|
|''Source:''|http://tw.lewcid.org/#TiddlerNotesPlugin|
|''Code Repository:''|http://tw.lewcid.org/svn/plugins|
|''Version:''|2.1|
|''Date:''|26/10/07|
|''License:''|[[Creative Commons Attribution-ShareAlike 3.0 License|http://creativecommons.org/licenses/by-sa/3.0/]]|
|''~CoreVersion:''|2.2.3|

!!Concept:
*The TiddlerNotesPlugin allows you to add notes to tiddlers, without needing to edit the original tiddler. This means that your original content will remain unaltered, and if you update it in the future, you won’t lose your notes. Notes are stored in separate tiddlers, but can be viewed and edited from within the original tiddler.
*For a tiddler titled "~MySlide", the notes are by default saved in a tiddler titled "~MySlide-Notes" and is given a tag of "Notes". The suffix and tags of the notes tiddlers are customizable. You can have one or multiple notes per tiddlers. So it is possible to have for example, teacher's notes and student's notes in the same file.
*Notes can be configured to start off blank, or pre-filled with the contents of the original tiddler.

!!Usage:
*{{{<<notes>>}}} is the simplest usage form.
* additional optional parameters include:
**{{{heading:}}} the heading to use for the notes box
**{{{tag:}}} the tag to be given to the notes tiddler
**{{{suffix:}}} the suffix to be used when naming the notes tiddler
* a full macro call could look like: {{{<<notes heading:"My Notes" tag:"NoteTiddlers" suffix:"Comments">>}}}
* To avoid adding {{{<<notes>>}}} to each tiddler you want notes for, you could add the macro call to the ViewTemplate
** below the line {{{<div class='viewer' macro='view text wikified'></div>}}} add the following line: <br> {{{<div class='viewer' macro='notes'></div>}}}
** Used in combination with the ~HideWhenPlugin or ~PublisherPlugin, you could have notes be shown only for tiddlers with specific tags. The ~PublisherPlugin would allow you for instance to only have the ~TeachersNotes visible to the teacher, and the ~StudentsNotes for the same tiddler visible to the Student.

!!Configuration
*<<option chkPrefillNotes>> Enable to pre-fill notes with the original tiddler's contents

!!Demo:
* [[MySlide]]

***/
// /%
//!BEGIN-PLUGIN-CODE

if (!config.options.chkPrefillNotes)
	config.options.chkPrefillNotes = false;
	
function createTiddlyElement(theParent,theElement,theID,theClass,theText,attribs)
{
	var e = document.createElement(theElement);
	if(theClass != null)
		e.className = theClass;
	if(theID != null)
		e.setAttribute("id",theID);
	if(theText != null)
		e.appendChild(document.createTextNode(theText));
	if(attribs){
		for(var n in attribs){
			e.setAttribute(n,attribs[n]);
		}
	}
	if(theParent != null)
		theParent.appendChild(e);
	return e;
}

function createTiddlyButton(theParent,theText,theTooltip,theAction,theClass,theId,theAccessKey,attribs)
{
	var theButton = document.createElement("a");
	if(theAction) {
		theButton.onclick = theAction;
		theButton.setAttribute("href","javascript:;");
	}
	if(theTooltip)
		theButton.setAttribute("title",theTooltip);
	if(theText)
		theButton.appendChild(document.createTextNode(theText));
	if(theClass)
		theButton.className = theClass;
	else
		theButton.className = "button";
	if(theId)
		theButton.id = theId;
	if(attribs){
		for(var n in attribs){
			e.setAttribute(n,attribs[n]);
		}
	}
	if(theParent)
		theParent.appendChild(theButton);
	if(theAccessKey)
		theButton.setAttribute("accessKey",theAccessKey);
	return theButton;
}

config.macros.notes={
	
	cancelWarning: "Are you sure you want to abandon changes to your notes for '%0'?",
	editLabel: "edit notes",
	editTitle: "double click to edit",
	saveLabel: "save notes",
	saveTitle: "double click to save",
	cancelLabel: "cancel",
	heading: "Notes",
	suffix: "Notes",
	tag: "Notes",
	
	saveNotes: function(ev){
		e = ev? ev : window.event;
		var theTarget = resolveTarget(e);
		if (theTarget.nodeName.toLowerCase() == "textarea")
			return false;
		var title = story.findContainingTiddler(theTarget).getAttribute("tiddler");
		story.setDirty(title,false);
		var box = document.getElementById("notesContainer"+title);
		var textarea = document.getElementById("notesTextArea"+title);
		if(textarea.getAttribute("oldText")!=textarea.value && !hasClass(theTarget,"cancelNotesButton")){
			var suffix = box.getAttribute("suffix");
			var t = store.getTiddler(title+"-"+suffix);
			store.saveTiddler(title+"-"+suffix,title+"-"+suffix,textarea.value,config.options.txtUserName,new Date(),t?t.tags:box.getAttribute("tag"),t?t.fields:{});
		}
		story.refreshTiddler(title,1,true);
		autoSaveChanges(true);
		return false;
	},
	
	editNotes: function(box,tiddler){
		removeChildren(box);
		story.setDirty(tiddler,true);
		box.title = this.saveTitle;
		box.ondblclick = this.saveNotes;
		createTiddlyButton(box,this.cancelLabel,this.cancelLabel,this.saveNotes,"cancelNotesButton");
		createTiddlyButton(box,this.saveLabel,this.saveLabel,this.saveNotes,"saveNotesButton");
		wikify("!!"+box.getAttribute("heading")+"\n",box);
		addClass(box,"editor");
		var wrapper1 = createTiddlyElement(null,"fieldset",null,"fieldsetFix");
		var wrapper2 = createTiddlyElement(wrapper1,"div");
		var e = createTiddlyElement(wrapper2,"textarea","notesTextArea"+tiddler);
		var v = store.getValue(tiddler+"-"+box.getAttribute("suffix"),"text");
		if(!v) 
			v = config.options.chkPrefillNotes? store.getValue(tiddler,"text"):'';
		e.value = v;
		e.setAttribute("oldText",v);
		var rows = 10;
		var lines = v.match(/\n/mg);
		var maxLines = Math.max(parseInt(config.options.txtMaxEditRows),5);
		if(lines != null && lines.length > rows)
			rows = lines.length + 5;
		rows = Math.min(rows,maxLines);
		e.setAttribute("rows",rows);
		box.appendChild(wrapper1);
	},
	
	editNotesButtonOnclick: function(e){
		var title = story.findContainingTiddler(this).getAttribute("tiddler");
		var box = document.getElementById("notesContainer"+title);
		config.macros.notes.editNotes(box,title);
		return false;
	},
	
	ondblclick : function(ev){
		e = ev? ev : window.event;
		var theTarget = resolveTarget(e);
		var title = story.findContainingTiddler(theTarget).getAttribute("tiddler");
		var box = document.getElementById("notesContainer"+title);
		config.macros.notes.editNotes(box,title);
		e.cancelBubble = true;
		if(e.stopPropagation) e.stopPropagation();
		return false;
	},
	
	handler : function(place,macroName,params,wikifier,paramString,tiddler){
		
		params = paramString.parseParams("anon",null,true,false,false);
		var heading = getParam(params,"heading",this.heading);
		var tag = getParam(params,"tag",this.tag);
		var suffix = getParam(params,"suffix",this.suffix);
		var box = createTiddlyElement(place,"div","notesContainer"+tiddler.title,"TiddlerNotes",null,{"source":tiddler.title,params:paramString,heading:heading,tag:tag,suffix:suffix});
		createTiddlyButton(box,this.editLabel,this.editLabel,this.editNotesButtonOnclick,"editNotesButton");
		wikify("!!"+heading+"\n",box);
		box.title=this.editTitle;
		box.ondblclick = this.ondblclick;
		wikify("<<tiddler [["+tiddler.title+"-"+suffix+"]]>>",box);
	}		
};

Story.prototype.old_notes_closeTiddler = Story.prototype.closeTiddler;
Story.prototype.closeTiddler = function(title,animate,unused){
	if(story.isDirty(title)) {
		if(!confirm(config.macros.notes.cancelWarning.format([title])))
			return false;
	}
	return this.old_notes_closeTiddler.apply(this,arguments);
}

setStylesheet(".TiddlerNotes {\n"+ " background:#eee;\n"+ " border:1px solid #ccc;\n"+ " padding:10px;\n"+ " margin:15px;\n"+ "}\n"+ "\n"+ ".cancelNotesButton,.editNotesButton, .saveNotesButton {\n"+ " float:right;\n"+ " border:1px solid #ccc;\n"+ " padding:2px 5px;\n"+ "}\n"+ "\n"+ ".saveNotesButton{\n"+ " margin-right:0.5em;\n"+ "}\n"+ "\n"+ ".TiddlerNotes.editor textarea{\n"+ " border:1px solid #ccc;\n"+ "}","NotesPluginStyles");
//!END-PLUGIN-CODE
// %/
/%
!info
|Name|ToggleRightSidebar|
|Source|http://www.TiddlyTools.com/#ToggleRightSidebar|
|Version|2.0.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|transclusion|
|Description|show/hide right sidebar (SideBarOptions)|
Usage
<<<
{{{
<<tiddler ToggleRightSidebar>>
<<tiddler ToggleRightSidebar with: label tooltip>>
}}}
Try it: <<tiddler ToggleRightSidebar##show
	with: {{config.options.chkShowRightSidebar?'►':'◄'}}>>
<<<
Configuration:
<<<
copy/paste the following settings into a tiddler tagged with <<tag systemConfig>> and then modify the values to suit your preferences:
{{{
config.options.chkShowRightSidebar=true;
config.options.txtToggleRightSideBarLabelShow="◄";
config.options.txtToggleRightSideBarLabelHide="►";
}}}
<<<
!end
!show
<<tiddler {{
	var co=config.options;
	if (co.chkShowRightSidebar===undefined) co.chkShowRightSidebar=true;
	var sb=document.getElementById('sidebar');
	var da=document.getElementById('displayArea');
	if (sb) {
		sb.style.display=co.chkShowRightSidebar?'block':'none';
		da.style.marginRight=co.chkShowRightSidebar?'':'1em';
	}
'';}}>><html><nowiki><a href='javascript:;' title="$2"
onmouseover="
	this.href='javascript:void(eval(decodeURIComponent(%22(function(){try{('
	+encodeURIComponent(encodeURIComponent(this.onclick))
	+')()}catch(e){alert(e.description?e.description:e.toString())}})()%22)))';"
onclick="
	var co=config.options;
	var opt='chkShowRightSidebar';
	var show=co[opt]=!co[opt];
	var sb=document.getElementById('sidebar');
	var da=document.getElementById('displayArea');
	if (sb) {
		sb.style.display=show?'block':'none';
		da.style.marginRight=show?'':'1em';
	}
	saveOptionCookie(opt);
	var labelShow=co.txtToggleRightSideBarLabelShow||'&#x25C4;';
	var labelHide=co.txtToggleRightSideBarLabelHide||'&#x25BA;';
	if (this.innerHTML==labelShow||this.innerHTML==labelHide) 
		this.innerHTML=show?labelHide:labelShow;
	this.title=(show?'hide':'show')+' right sidebar';
	var sm=document.getElementById('storyMenu');
	if (sm) config.refreshers.content(sm);
	return false;
">$1</a></html>
!end
%/<<tiddler {{
	var src='ToggleRightSidebar';
	src+(tiddler&&tiddler.title==src?'##info':'##show');
}} with: {{
	var co=config.options;
	var labelShow=co.txtToggleRightSideBarLabelShow||'&#x25C4;';
	var labelHide=co.txtToggleRightSideBarLabelHide||'&#x25BA;';
	'$1'!='$'+'1'?'$1':(co.chkShowRightSidebar?labelHide:labelShow);
}} {{
	var tip=(config.options.chkShowRightSidebar?'hide':'show')+' right sidebar';
	'$2'!='$'+'2'?'$2':tip;
}}>>
/***
|Name:|ToggleTagPlugin|
|Description:|Makes a checkbox which toggles a tag in a tiddler|
|Version:|3.1.0a|
|Date:|27-Jun-2011|
|Source:|http://mptw.tiddlyspot.com/#ToggleTagPlugin|
|Author:|Simon Baird <simon.baird@gmail.com>|
|License:|http://mptw.tiddlyspot.com/#TheBSDLicense|
!!Usage
{{{<<toggleTag }}}//{{{TagName TiddlerName LabelText}}}//{{{>>}}}
* TagName - the tag to be toggled, default value "checked"
* TiddlerName - the tiddler to toggle the tag in, default value the current tiddler
* LabelText - the text (gets wikified) to put next to the check box, default value is '{{{[[TagName]]}}}' or '{{{[[TagName]] [[TiddlerName]]}}}'
(If a parameter is '.' then the default will be used)
* TouchMod flag - if non empty then touch the tiddlers mod date. Note, can set config.toggleTagAlwaysTouchModDate to always touch mod date
!!Examples
|Code|Description|Example|h
|{{{<<toggleTag>>}}}|Toggles the default tag (checked) in this tiddler|<<toggleTag>>|
|{{{<<toggleTag TagName>>}}}|Toggles the TagName tag in this tiddler|<<toggleTag TagName>>|
|{{{<<toggleTag TagName TiddlerName>>}}}|Toggles the TagName tag in the TiddlerName tiddler|<<toggleTag TagName TiddlerName>>|
|{{{<<toggleTag TagName TiddlerName 'click me'>>}}}|Same but with custom label|<<toggleTag TagName TiddlerName 'click me'>>|
|{{{<<toggleTag . . 'click me'>>}}}|dot means use default value|<<toggleTag . . 'click me'>>|
!!Notes
* If TiddlerName doesn't exist it will be silently created
* Set label to '-' to specify no label
* See also http://mgtd-alpha.tiddlyspot.com/#ToggleTag2
!!Known issues
* Doesn't smoothly handle the case where you toggle a tag in a tiddler that is current open for editing
* Should convert to use named params
***/
//{{{

if (config.toggleTagAlwaysTouchModDate == undefined) config.toggleTagAlwaysTouchModDate = false;

merge(config.macros,{

  toggleTag: {

    createIfRequired: true,
    shortLabel: "[[%0]]",
    longLabel: "[[%0]] [[%1]]",

    handler: function(place,macroName,params,wikifier,paramString,tiddler) {
      var tiddlerTitle = tiddler ? tiddler.title : '';
      var tag   = (params[0] && params[0] != '.') ? params[0] : "checked";
      var title = (params[1] && params[1] != '.') ? params[1] : tiddlerTitle;
      var defaultLabel = (title == tiddlerTitle ? this.shortLabel : this.longLabel);
      var label = (params[2] && params[2] != '.') ? params[2] : defaultLabel;
      var touchMod = (params[3] && params[3] != '.') ? params[3] : "";
      label = (label == '-' ? '' : label); // dash means no label
      var theTiddler = (title == tiddlerTitle ? tiddler : store.getTiddler(title));
      var cb = createTiddlyCheckbox(place, label.format([tag,title]), theTiddler && theTiddler.isTagged(tag), function(e) {
        if (!store.tiddlerExists(title)) {
          if (config.macros.toggleTag.createIfRequired) {
            var content = store.getTiddlerText(title); // just in case it's a shadow
            store.saveTiddler(title,title,content?content:"",config.options.txtUserName,new Date(),null);
          }
          else
            return false;
        }
        if ((touchMod != "" || config.toggleTagAlwaysTouchModDate) && theTiddler)
            theTiddler.modified = new Date();
        store.setTiddlerTag(title,this.checked,tag);
        return true;
      });
    }
  }
});

//}}}

/***
Description: Contains the stuff you need to use Tiddlyspot
Note, you also need UploadPlugin, PasswordOptionPlugin and LoadRemoteFileThroughProxy
from http://tiddlywiki.bidix.info for a complete working Tiddlyspot site.
***/
//{{{

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

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

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

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

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

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

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

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

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

});
//}}}
| !date | !user | !location | !storeUrl | !uploadDir | !toFilename | !backupdir | !origin |
| 05/09/2013 21:18:34 | RayStorey | [[/|http://rayspot01.tiddlyspot.com/]] | [[store.cgi|http://rayspot01.tiddlyspot.com/store.cgi]] | . | [[index.html | http://rayspot01.tiddlyspot.com/index.html]] | . | ok |
| 05/09/2013 21:30:29 | RayStorey | [[/|http://rayspot01.tiddlyspot.com/]] | [[store.cgi|http://rayspot01.tiddlyspot.com/store.cgi]] | . | [[index.html | http://rayspot01.tiddlyspot.com/index.html]] | . | ok |
| 05/09/2013 22:19:17 | RayStorey | [[/|http://rayspot01.tiddlyspot.com/]] | [[store.cgi|http://rayspot01.tiddlyspot.com/store.cgi]] | . | [[index.html | http://rayspot01.tiddlyspot.com/index.html]] | . | ok |
| 05/09/2013 22:31:14 | RayStorey | [[/|http://rayspot01.tiddlyspot.com/]] | [[store.cgi|http://rayspot01.tiddlyspot.com/store.cgi]] | . | [[index.html | http://rayspot01.tiddlyspot.com/index.html]] | . |
| 06/09/2013 10:44:29 | RayStorey | [[/|http://rayspot01.tiddlyspot.com/]] | [[store.cgi|http://rayspot01.tiddlyspot.com/store.cgi]] | . | [[index.html | http://rayspot01.tiddlyspot.com/index.html]] | . |
| 06/09/2013 11:06:14 | RayStorey | [[/|http://rayspot01.tiddlyspot.com/]] | [[store.cgi|http://rayspot01.tiddlyspot.com/store.cgi]] | . | [[index.html | http://rayspot01.tiddlyspot.com/index.html]] | . |
| 06/09/2013 16:39:48 | RayStorey | [[/|http://rayspot01.tiddlyspot.com/]] | [[store.cgi|http://rayspot01.tiddlyspot.com/store.cgi]] | . | [[index.html | http://rayspot01.tiddlyspot.com/index.html]] | . |
| 16/11/2013 18:26:06 | RayStorey | [[/|http://rayspot01.tiddlyspot.com/]] | [[store.cgi|http://rayspot01.tiddlyspot.com/store.cgi]] | . | [[index.html | http://rayspot01.tiddlyspot.com/index.html]] | . | failed |
| 16/11/2013 18:26:49 | RayStorey | [[/|http://rayspot01.tiddlyspot.com/]] | [[store.cgi|http://rayspot01.tiddlyspot.com/store.cgi]] | . | [[index.html | http://rayspot01.tiddlyspot.com/index.html]] | . | failed |
| 16/11/2013 18:27:26 | RayStorey | [[/|http://rayspot01.tiddlyspot.com/]] | [[store.cgi|http://rayspot01.tiddlyspot.com/store.cgi]] | . | [[index.html | http://rayspot01.tiddlyspot.com/index.html]] | . |
/***
|''Name:''|UploadPlugin|
|''Description:''|Save to web a TiddlyWiki|
|''Version:''|4.1.3|
|''Date:''|Feb 24, 2008|
|''Source:''|http://tiddlywiki.bidix.info/#UploadPlugin|
|''Documentation:''|http://tiddlywiki.bidix.info/#UploadPluginDoc|
|''Author:''|BidiX (BidiX (at) bidix (dot) info)|
|''License:''|[[BSD open source license|http://tiddlywiki.bidix.info/#%5B%5BBSD%20open%20source%20license%5D%5D ]]|
|''~CoreVersion:''|2.2.0|
|''Requires:''|PasswordOptionPlugin|
***/
//{{{
version.extensions.UploadPlugin = {
	major: 4, minor: 1, revision: 3,
	date: new Date("Feb 24, 2008"),
	source: 'http://tiddlywiki.bidix.info/#UploadPlugin',
	author: 'BidiX (BidiX (at) bidix (dot) info',
	coreVersion: '2.2.0'
};

//
// Environment
//

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

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

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

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

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

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

//
// uploadOptions Macro
//

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

//
// upload functions
//

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

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

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

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

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

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

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

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

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

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

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

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

//
// Utilities
// 

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

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

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

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

//
// Initializations
//

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

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

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

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


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


//}}}

<!--{{{-->
<div class='toolbar' macro='toolbar [[ToolbarCommands::ViewToolbar]]'></div>
<div class='title' macro='view title'></div>
<div class='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>
<!--}}}-->
This document is a ~TiddlyWiki from tiddlyspot.com.  A ~TiddlyWiki is an electronic notebook that is great for managing todo lists, personal information, and all sorts of things.

@@font-weight:bold;font-size:1.3em;color:#444; //What now?// &nbsp;&nbsp;@@ Before you can save any changes, you need to enter your password in the form below.  Then configure privacy and other site settings at your [[control panel|http://rayspot01.tiddlyspot.com/controlpanel]] (your control panel username is //rayspot01//).
<<tiddler TspotControls>>
See also GettingStarted.

@@font-weight:bold;font-size:1.3em;color:#444; //Working online// &nbsp;&nbsp;@@ You can edit this ~TiddlyWiki right now, and save your changes using the "save to web" button in the column on the right.

@@font-weight:bold;font-size:1.3em;color:#444; //Working offline// &nbsp;&nbsp;@@ A fully functioning copy of this ~TiddlyWiki can be saved onto your hard drive or USB stick.  You can make changes and save them locally without being connected to the Internet.  When you're ready to sync up again, just click "upload" and your ~TiddlyWiki will be saved back to tiddlyspot.com.

@@font-weight:bold;font-size:1.3em;color:#444; //Help!// &nbsp;&nbsp;@@ Find out more about ~TiddlyWiki at [[TiddlyWiki.com|http://tiddlywiki.com]].  Also visit [[TiddlyWiki.org|http://tiddlywiki.org]] for documentation on learning and using ~TiddlyWiki. New users are especially welcome on the [[TiddlyWiki mailing list|http://groups.google.com/group/TiddlyWiki]], which is an excellent place to ask questions and get help.  If you have a tiddlyspot related problem email [[tiddlyspot support|mailto:support@tiddlyspot.com]].

@@font-weight:bold;font-size:1.3em;color:#444; //Enjoy :)// &nbsp;&nbsp;@@ We hope you like using your tiddlyspot.com site.  Please email [[feedback@tiddlyspot.com|mailto:feedback@tiddlyspot.com]] with any comments or suggestions.
// rightsidebar management
config.options.chkShowRightSidebar=true;
config.options.txtToggleRightSideBarLabelShow="Show Sidebar ◄";
config.options.txtToggleRightSideBarLabelHide="Hide Sidebar ►";

<<formTiddler NewArticleTemplatex>>