<!--{{{-->
<link rel='alternate' type='application/rss+xml' title='RSS' href='index.xml' />
<!--}}}-->
Background: #fff
Foreground: #000
PrimaryPale: #8cf
PrimaryLight: #18f
PrimaryMid: #04b
PrimaryDark: #014
SecondaryPale: #ffc
SecondaryLight: #fe8
SecondaryMid: #db4
SecondaryDark: #841
TertiaryPale: #eee
TertiaryLight: #ccc
TertiaryMid: #999
TertiaryDark: #666
Error: #f88
/*{{{*/
body {background:[[ColorPalette::Background]]; color:[[ColorPalette::Foreground]];}

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

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

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

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

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

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

.wizard {background:[[ColorPalette::PrimaryPale]]; border:1px solid [[ColorPalette::PrimaryMid]];}
.wizard h1 {color:[[ColorPalette::PrimaryDark]]; border:none;}
.wizard h2 {color:[[ColorPalette::Foreground]]; border:none;}
.wizardStep {background:[[ColorPalette::Background]]; color:[[ColorPalette::Foreground]];
	border:1px solid [[ColorPalette::PrimaryMid]];}
.wizardStep.wizardStepDone {background:[[ColorPalette::TertiaryLight]];}
.wizardFooter {background:[[ColorPalette::PrimaryPale]];}
.wizardFooter .status {background:[[ColorPalette::PrimaryDark]]; color:[[ColorPalette::Background]];}
.wizard .button {color:[[ColorPalette::Foreground]]; background:[[ColorPalette::SecondaryLight]]; border: 1px solid;
	border-color:[[ColorPalette::SecondaryPale]] [[ColorPalette::SecondaryDark]] [[ColorPalette::SecondaryDark]] [[ColorPalette::SecondaryPale]];}
.wizard .button:hover {color:[[ColorPalette::Foreground]]; background:[[ColorPalette::Background]];}
.wizard .button:active {color:[[ColorPalette::Background]]; background:[[ColorPalette::Foreground]]; border: 1px solid;
	border-color:[[ColorPalette::PrimaryDark]] [[ColorPalette::PrimaryPale]] [[ColorPalette::PrimaryPale]] [[ColorPalette::PrimaryDark]];}
	
.wizard .notChanged {background:transparent;}
.wizard .changedLocally {background:#80ff80;}
.wizard .changedServer {background:#8080ff;}
.wizard .changedBoth {background:#ff8080;}
.wizard .notFound {background:#ffff80;}
.wizard .putToServer {background:#ff80ff;}
.wizard .gotFromServer {background:#80ffff;}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

hr {height:1px;}

a {text-decoration:none;}

dt {font-weight:bold;}

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

.txtOptionInput {width:11em;}

#contentWrapper .chkOptionInput {border:0;}

.externalLink {text-decoration:underline;}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

.whenBackstage {display:none;}
.backstageVisible .whenBackstage {display:block;}
/*}}}*/
/***
StyleSheet for use when a translation requires any css style changes.
This StyleSheet can be used directly by languages such as Chinese, Japanese and Korean which need larger font sizes.
***/
/*{{{*/
body {font-size:0.8em;}
#sidebarOptions {font-size:1.05em;}
#sidebarOptions a {font-style:normal;}
#sidebarOptions .sliderPanel {font-size:0.95em;}
.subtitle {font-size:0.8em;}
.viewer table.listView {font-size:0.95em;}
/*}}}*/
/*{{{*/
@media print {
#mainMenu, #sidebar, #messageArea, .toolbar, #backstageButton, #backstageArea {display: none ! important;}
#displayArea {margin: 1em 1em 0em 1em;}
/* Fixes a feature in Firefox 1.5.0.2 where print preview displays the noscript content */
noscript {display:none;}
}
/*}}}*/
<!--{{{-->
<div class='header' macro='gradient vert [[ColorPalette::PrimaryLight]] [[ColorPalette::PrimaryMid]]'>
<div class='headerShadow'>
<span class='siteTitle' refresh='content' tiddler='SiteTitle'></span>&nbsp;
<span class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'></span>
</div>
<div class='headerForeground'>
<span class='siteTitle' refresh='content' tiddler='SiteTitle'></span>&nbsp;
<span class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'></span>
</div>
</div>
<div id='mainMenu' refresh='content' tiddler='MainMenu'></div>
<div id='sidebar'>
<div id='sidebarOptions' refresh='content' tiddler='SideBarOptions'></div>
<div id='sidebarTabs' refresh='content' force='true' tiddler='SideBarTabs'></div>
</div>
<div id='displayArea'>
<div id='messageArea'></div>
<div id='tiddlerDisplay'></div>
</div>
<!--}}}-->
<!--{{{-->
<div class='toolbar' macro='toolbar [[ToolbarCommands::ViewToolbar]]'></div>
<div class='title' macro='view title'></div>
<div class='subtitle'><span macro='view modifier link'></span>, <span macro='view modified date'></span> (<span macro='message views.wikified.createdPrompt'></span> <span macro='view created date'></span>)</div>
<div class='tagging' macro='tagging'></div>
<div class='tagged' macro='tags'></div>
<div class='viewer' macro='view text wikified'></div>
<div class='tagClear'></div>
<!--}}}-->
<!--{{{-->
<div class='toolbar' macro='toolbar [[ToolbarCommands::EditToolbar]]'></div>
<div class='title' macro='view title'></div>
<div class='editor' macro='edit title'></div>
<div macro='annotations'></div>
<div class='editor' macro='edit text'></div>
<div class='editor' macro='edit tags'></div><div class='editorFooter'><span macro='message views.editor.tagPrompt'></span><span macro='tagChooser'></span></div>
<!--}}}-->
To get started with this blank TiddlyWiki, you'll need to modify the following tiddlers:
* SiteTitle & SiteSubtitle: The title and subtitle of the site, as shown above (after saving, they will also appear in the browser title bar)
* MainMenu: The menu (usually on the left)
* DefaultTiddlers: Contains the names of the tiddlers that you want to appear when the TiddlyWiki is opened
You'll also need to enter your username for signing your edits: <<option txtUserName>>
These InterfaceOptions for customising TiddlyWiki are saved in your browser

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

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

----
Also see AdvancedOptions
<<importTiddlers>>
1. Doh! A creature of the GM's choice springs forth, hostile and ready to do battle.
2. A small cask of fine ale (2 gallons).
3. A fine meal for 8 in a picnic basket.
4. A carrier pigeon complete with message sleeve. Whispering a person's name to the bird will cause it to seek them and roost on their shoulder if within 100 miles.
5. Pair of war dogs spring forth and loyally protect the bearer for two hours.
6. 10 gold pieces are pulled forth. These are not subject to the 2-hour time limit.
7. A deck of cards and set of poker chips.
8. A coil of fine silken rope, 100' long.
9. A 10' long steel pole of finest quality.
10. A pile of dry firewood, tinder and kindling sufficient to burn for 4 hours.
11. A set of fishing gear appropriate to the nearest body of water, including bait.
12. Four comfortable stools.
13. A lamp with two hours of lamp oil. There is no way to refill the lamp and it vanishes when emptied.
14. A fine sword of the type most useful to the bearer. The weapon is +1 non-magical in quality.
15. A pair of fine silver dice and a backgammon board.
16. A chess set.
17. A fine umbrella.
18. A pot of fine coffee or tea, as appropriate to the bearer.
19. A complete set of warm outerwear, coat, cloak, hat, boots, and gloves, sized for the bearer.
20. Dealer's choice, pick either the most or least useful item for the current situation.


This chart comes from M Thomas's blog [[RPG Dumping Ground|http://rpgdump.blogspot.com/2009/03/bag-of-dagos.html]]
The bar is <<rollon BarType>>, but the <<rollon BarPerson>> is <<rollon BarPersonDescription>>.
;1-6
: Barmaid
;7-8
: Bartender
;9-10
: Owner
1. Cute
2. Smokin' hot
3. a friend of mine
4. my wife's cousin
5. my bookie
6. my ex
7. owes me <<rollon 1d6*10>> bucks.
# Hellhole * 2
# Scary
# Horrendous
# <<rollon justhowbad>> Horrible
# Terrible
# Miserable
# Awful
# Crap
# Poor
# a Dump
# a Dive
# Crap, but the liquor is strong
# Crap, but they know me here
# Homey
# a Faux-homey corporate chain
# an Overpriced &amp; under-serviced
# Overpriced &amp; shiny
# Trend whores
# Bitter old men &amp; other locals
# okay
01 Dulkoff
02 Mingl
03 Turmun
04 Undle
05 Gersatte
06 Cranta
07 Leati
08 Abideli
09 Cyportro
10 Faciree
11 Palimati
12 Sasel
13 Slatter
14 Berepreg
15 Whisteer
16 Thill
17 Claterp
18 Theorta
19 Versi
20 Fingi
21 Pargeba
22 Florex
23 Amettlec
24 Tersu
25 Multo
26 Dymet
27 Sumenth
28 Wilipa
29 Spurch
30 Glyrob
31 Upetar
32 Penfulin
33 Bleng
34 Telin
35 Nurkind
36 Heaphe
37 Enticu
38 Ingswi
39 Nolles
40 Cozymal
41 Fonizan
42 Bionche
43 Finsor
44 Hoome
45 Sters
46 Larassec
47 Squiter
48 Boractu
49 Ophopa
50 Zatteraw
51 Lisess
52 Ponati
53 Whaki
54 Bilab
55 Tesec
56 Spier
57 Dultin
58 Kiven
59 Shizer
60 Ineta
61 Bernall
62 Tenhermi
63 Coutorus
64 Caphotri
65 Abanulum
66 Amystal
67 Hanomite
68 Promero
69 Inxierna
70 Dersa
71 Saustili
72 Repnes
73 Twori
74 Fifien
75 Ratedi
76 Mingui
77 Prenche
78 Rinishim
79 Terrali
80 Resterc
81 Mories
82 Cudic
83 Emica
84 Hedig
85 Bucen
86 Calypti
87 Larti
88 Intenx
89 Rindle
90 Heestero
91 Tryng
92 Dalon
93 Alesin
94 Ornse
95 Kerce
96 Triesa
97 Slint
98 Rophyd
99 Jareson
100 Valesel

This list of character names comes from [[A Rust Monster Ate My Sword|http://rustmonsteratemysword.blogspot.com/2009/02/100-character-names-from-unexpected.html]]  This table is copyright Christopher Brackett. Permission is granted for personal use only
[[Rollon]]
!!Rollon Macro
Usage {{{<<rollon tablename|table:string|dice_expression [times|times:number or dice_expression] [dice:dice_expresssion] [separator:sep_string] [resultName:string] [force:number]>>}}}
!!!Parameters
Parameters may be surrounded by quotes if they are to contain spaces, e.g. table:"My Table"  Any parameter except table may be passed "prompt" in order to cause the macro to prompt you for that value when it's run.
*table - the name of the table to roll on, or a dice expression like 3d6+1.  Required
*times - the number of times to roll, or a dice expression.  Defaults to 1.  Prompt will prompt for a number or dice expression when you click
*dice - dice to use when rolling.  If not provided, rollon will roll a die precisely as large as the list or, for definition lists, as large as the highest number in the final entry in the list
*separator - character to use to separate multiple results if times > 1.  Use {{{<br>}}} for line breaks
*resultName - name of the tiddler to place the result in.  Otherwise will default to the name of the tiddler the macro is in, with " Result (n)" appended, where n is 1 higher than the highest like-named tiddler
*force - force the number rolled to be a particular number.  Primarily used for debugging
!!!Tables
Tables are any Tiddler that contains:
* an unordered list (introduced with {{{*}}})
* an ordered list (introduced with {{{#}}})
* a definition list (introduced with {{{;}}} on the term line and {{{:}}} on the definition line.  Be careful that you alternate definitions and terms... you can tell if it's right by whether the terms are bold and the definitions below and indented)
* a sequence of lines beginning with numbers (and optionally having a {{{.}}} after the number)

If the Tiddler has any prefatory material prior to the start of the first list in the Tiddler, that text is copied into the result.
If the Tiddler has any postscript material after the end of the last list in the Tiddler, that text is ignored.  This is useful for notes and annotations.

Lists don't actually have to be contiguous.  That is, since rollon is using a textual search, it will consider two lists in the same Tiddler as being the same as one.  That's probably a bug, but doesn't seem worth eliminating.  I wouldn't advise counting on that behavior to continue in future versions of Rollon Plugin.
<<rollon "Bag of the Luck God">>

<<rollon "Character Names" times:3>>

<<rollon "Special Events">>

<<rollon "SW Random NPC" times:prompt separator:"<br>">>
To get started with Rollon, you'll need to either import the plugin to your TiddlyWiki, or save a copy of this TiddlyWiki locally.

* Instructions for importing a plugin can be found at [[TiddlyWiki.org|http://tiddlywiki.org/wiki/Importing]]
* You should be able to save this TiddlyWiki by clicking "download" at the right

Once you've done that, you can create your first table, or if you've started with a copy of this TiddlyWiki, look at some of the [[Example Tables]]
Joshua Macy is the author of this plugin.  Contact me at rollon-plugin@googlegroups.com

;1-3
:you possess <<rollon 1d3>> small jewels of known value.
;4-5 
:you possess <<rollon 1d2>> medium jewels of known value.  If your Station is 1 or less you stole them.
;6
:you possess 1 Large Jewel of known value. If your station is 2 or less you stole it.
[img[Creative Commons License|http://i.creativecommons.org/l/by-nc-sa/3.0/us/88x31.png][http://creativecommons.org/licenses/by-nc-sa/3.0/us/]]
This work is licensed under a [[Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License|http://creativecommons.org/licenses/by-nc-sa/3.0/us/]]
/***
|''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);
}
//}}}
[[Rollon]]
[[GettingStarted]]
[[Example Tables]]
[[Documentation]]
[[License]]
* Dog
* Cat
* Hamster
* Godzilla
/***
|''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"
	});
*/
//}}}
<<rollon MyFirstTable>>
Welcome to Rollon!

The goal of Rollon is to make creating and rolling on tables as easy as editing a wiki, or cutting and pasting from a blog or web page.

Rollon is a [[TiddlyWiki|http://tiddlywiki.com]] plugin designed to let you roll randomly on tables, such as you might find in roleplaying games.  When we talk about "tables" in Rollon, we don't mean an HTML {{{<table>}}}, just a list of entries such as a Wandering Monster Table or Treasure Table might have. To Rollon, any tiddler containing a list is potentially a table, whether the list is an unordered list, an ordered list, a dictionary list, or even just text where each line starts with a number.  This gives you a great deal of freedom in designing lists, or cutting and pasting them into your [[TiddlyWiki|http://tiddlywiki.com]] from other sources.


The Rollon Plugin provides a new macro: {{{rollon}}}.  The macro takes the name of a tiddler containing a list as a parameter, and creates a button that lets you roll against that "table."  When you click the button, it creates a new tiddler, and places the results of the roll in there.  Try it a couple times:

<<rollon MyFirstTable>>

MyFirstTable is a tiddler that contains:
<<tiddler MyFirstTable>>

The call to the macro looks like:
{{{<<rollon MyFirstTable>>}}}

Entries in Rollon Tables (lists) can themselves contain calls to the rollon macro.  If they do, then if that entry is selected, that macro will also be called and a random entry from that table will be inserted into the result in place of the macro call, much like a Mad-Lib.  E.g.

<<rollon "Bar Sentence">>

Notice a few things about this example.  If you click through to some of the tiddlers, you'll see that [[Bar Sentence]] isn't even a list.  If the tiddler doesn't appear to contain a list, then rollon just pulls it in verbatim, calling any macros it finds along the way.  Also note that Bar Sentence contains calls to multiple other tables, each of which might have still more calls to sub-tables, depending on the entry.  The tables demonstrate each of the types of list that rollon knows how to deal with: an unordered list, an ordered list, a definition list, and a "list" that just consists of successive lines with numbers (and an optional period).  If you use a definition list, you can have the entries described by a range...in which case the entries are weighted by the size of the range (as if you were rolling a die as large as the highest number in the last range).

Visit the ''Rollon Plugin Group''
[img[Rollon Plugin at Google Groups|http://groups.google.com/groups/img/3nb/groups_bar.gif][http://groups.google.com/group/rollon-plugin]]
/***
|''Name''|RollonPlugin|
|''Description''|A plugin to "Roll" on Tables, creating tiddlers containing random elements of lists, extracted from other tiddlers|
|''Icon''||
|''Author''|Joshua Macy|
|''Contributors''||
|''Version''|1.02|
|''Date''|2009-03-11|
|''Status''|@@beta@@;|
|''Source''|http://rollon.tiddlyspot.com#RollonPlugin|
|''CodeRepository''|http://rollon.tiddlyspot.com|
|''Copyright''|Joshua Macy, 2009|
|''License''|Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License|
|''CoreVersion''|2.4.1|
|''Requires''||
|''Overrides''|Adds String methods for trim, rtrim and ltrim|
|''Feedback''|joshua.macy@gmail.com|
|''Documentation''|http://rollon.tiddlyspot.com|
|''Keywords''|rollon|
!Description
A Plugin to roll on tables (formatted as lists). The plugin provides a rollon macro that has two functions, depending on the context where it's called.
*If the macro is in a tiddler that lacks the rollonResult tag, it creates a text label describing the table and a button to press to roll on that table. Pressing the button creates a new tiddler with the 
rollonResult tag and places the macro in that tiddler
*If the macro is in a tiddler that has a rollonResult tag it looks at the named tiddler as a table and to chooses a random element from that table and places it in the current tiddler
Thus, if you click on the roll button, you get a new tiddler with a random element from the table that you named.
Note that rollon calls can call other rollon calls!  If the entry selected from the table contains another rollon macro, that rollon macro is executed to select a random entry from ''it's'' table, and so on
until it bottoms out with an entry that contains no other rollon macros.  The results of all these calls are placed in order in the tiddler that originated the call, allowing you to build up complete sentences
and paragraphs of results, almost like a Mad-Lib.

You can control many parameters to the rollon call, or allow it to default to (hopefully sensible) values.
!Notes
Doesn't yet support entries that have sub-lists
!Usage
{{{
<<rollon tiddlername times>>
}}}
tiddlername - name of a tiddler containing a list of entries.
times - the number of times to roll.  May be a dice expression like 1d6 or 2d3+2

for more control you can use named parameters:
{{{
<<rollon table:tiddlername times:n separator:sep-char result:prompt>>
}}}

A complete list of parameters:
* table -  the name of the table to roll on.  "prompt" will cause it to prompt the user for a table name.  If the table name doesn't exist but appears to be a dice expression, like 1d6+2, it will evaluate the dice expression and return the value instead
* times - the number of times to roll on the table.  "prompt" will cause it to prompt the user for a number of times.  If the number of times appears to be a dice expression, it will evaluate the expression and roll that number of times.  The results are separated in the tiddler by a character (default is comma). ''Defaults to 1.''
* dice - a dice expression, such as 1d20, 3d6+1, 1d4+1d6, etc.  If no table is provided, the macro will return the result of the roll.  If a table is provided, the macro will roll that dice expression on the table.  ''Defaults to the highest number in the table.''  E.g. a table with 30 entries will have one of them selected at random, as if a 1d30 had been rolled.
* separator - the character used to separate multiple results.  ''Defaults to comma.''  Use {{{<br>}}} to separate results by line breaks
* resultName - the name of the new tiddler to create to hold the results.  ''Defaults to the name of the current tiddler, plus " Result" plus a numeric suffix, such as (1) or (3) to ensure the tiddler name is unique.''
* force - to force the result of the die roll to be a particular number.  Generally this is used for debugging. ''No default.''
* overWrite - make the results overwrite the previous results instead of adding a new tiddler with a numeric suffix

The first two parameters are assumed to be table and times, if named parameters aren't used.  Named parameters are required for all the others, and can be used for table and times for clarity.
If any parameter is set to the string &quot;prompt&quot;, then the user will be prompted for the appropriate value when the roll button is pushed.

Tables are any Tiddler that contains a list (ordered or unordered), or
a series of lines each starting with a number.  If the tiddler has text
prior to the beginning of the list, the text will be copied into the result,
trimmed of leading and trailing spaces.  If you want new lines in the preamble,
use <br> elements. Whitespace between the * or # or number at the beginning of a
line is preserved.
<...>
{{{
!!Examples
<<rollon "Bar Names">>

<<rollon table:"Bar Names" separator:"," times:3d6>>

<<rollon BarNames 3d6 separator:->>

!Configuration Options
None
!Revision History
!!v<1.02> (2009-12-15) bugfix release: fixed definition table to offset for the lowest value if it doesn't start with 1
!!v<1.0rc1> (2009-03-11) release candidate 1
* 
!To Do
add setting and consulting variables
add formatting options (first letter capitalization, gender agreement helpers, etc)
!Code
***/
//{{{
if(!version.extensions.RollonPlugin) { //# ensure that the plugin is only installed once
version.extensions.RollonPlugin = { installed: true };

if(!config.extensions) { config.extensions = {}; } //# obsolete from v2.4.2

config.macros.delTagged = {
	handler: function (place, macroName, params, wikifier, paramString, tiddler) {
        wikify("Deleted Tagged Tiddlers", place);
        btn = createTiddlyButton(place,"delete","Deletes Tiddlers Tagged with VAR", config.macros.delTagged.onClick);
    
    },
	onClick: function(ev) {
		if (!ev) {
			ev = window.event;
		}
        story.forEachTiddler(function(title,element) {
            var t = store.getTiddler(title);
            if (t) {
                if (t.isTagged("VAR")) {
                    alert(title);
                    store.removeTiddler(title);
                    story.closeTiddler(title, true);
                    //autoSaveChanges();
                }
            }
		});
    }
};

config.macros.rollon = {
	suffixText: ' (%0)',
	suffixPattern: / \(([0-9]+)\)$/,
	zeroPad: 0,
	sparse: false,
	diceRE : /(\d+)[dD]([\d]+)([tT])?/g,
	listRE : /^(?:[\*#]|\d+\.?)([^\*#].+)$/gim,
	defRE : /^([:;])(.+)$/gim,
	rangeRE : /^(\d+)(?:-(\d+))?\s*/,
	handler: function (place, macroName, params, wikifier, paramString, tiddler) {
		var t = r = result = btn = preamble = temp = null;
		var html = "";
		var resultList = [];
		var entries = [];
		var low = high = range = rangeEntry = dieRoll = 0;
		var taggedResult = tiddler.isTagged("rollonResult");
		var prms = paramString.parseParams("anon", null, true);
		var table = getParam(prms, "table", null) || params[0];
		var times = getParam(prms, "times") || params[1] || 1;
		var dice = getParam(prms, "dice");
		var sep = getParam(prms, "separator", ",");
		var resultName = getParam(prms, "resultName", tiddler.title + " Result");
        var overWrite = getParam(prms, "overWrite", false);
		var force = getParam(prms, "force", null);
        var set = getParam(prms, "set", null);
		if (taggedResult) {
			if (times === "prompt") {
				times = prompt("Enter number of times to roll", "1");
			}
			if (dice === "prompt") {
				dice = prompt("Enter the dice expression to roll");
			}
			if (table === "prompt") {
				table = prompt("Enter the table name to roll on");
			}
			if (sep === "prompt") {
				sep = prompt("Enter the separator character(s)");
			}
			if (force === "prompt") {
				force = prompt("Force the die to roll the following number");
			}
            if (set === "prompt") {
                set = prompt("Name of the variable to set");
            }
		}
		if (taggedResult) {
			if (times) {
				if (dice && params[1] && params[1].indexOf("dice:") > -1) {
					// dice: was passed as 2nd param, so times needs to be reset
					times = 1
				} else {
					if (/^\d+$/.test(times)) {
						//all digits
						times = parseInt(times);
					} else {
						this.diceRE.lastIndex = 0;
						result = this.diceRE.exec(times);
						if (result) {
							times = this.rollExpr(times);
						}
						else {
							times = 1;
						}
					}					
				}
			} else {
				times = 1;
			}			
			if (table) {
				t = store.getTiddler(table);
				if (t) {
					this.listRE.lastIndex = 0;
					result = this.listRE.exec(t.text);
					if (result) {
						preamble = result.input.substring(0, result.index);
						while (result != null) {
							entries.push(result[1]);
							result = this.listRE.exec(t.text);
						}
						if (preamble) {
                            // don't wikify the preamble until you've dealt with the table, lest the preamble contain a rollon macro that will update
                            // the current tiddler's text when it completes
							html = wikifyStatic(preamble.trim(), null, tiddler);
						}
						for (i = 0; i < times; i ++) {
							if  (!force) {
								if (!dice) {
									r = Math.floor(Math.random() * entries.length);								
								} else {
									r = Math.min(this.rollExpr(dice), entries.length);
									r = r - 1; // entries starts at 0, even though dice start at 1
								}
							} else {
								r = Math.min(force, entries.length);
							}
							temp = wikifyStatic(entries[r], null, tiddler);
							resultList.push(temp);
						}
						html += resultList.join(sep);
						html = html.replace(/<[\/]*span>/igm, '');
						wikify(html, place, null, tiddler);
					} else {
						this.defRE.lastIndex = 0;
						result = this.defRE.exec(t.text);
						if (result) { // definition list
							preamble = result.input.substring(0, result.index);
							while (result != null) {
								if (result[1] === ';') {
									// definition
									temp = result[2];
									this.rangeRE.lastIndex = 0;
									range = this.rangeRE.exec(temp);
									if (range) {
										low = range[1];
										high = null;
										if (result[2]) {
											high = range[2];
										}
										entries.push([low, high]);
									} else {
										wikify("Definition doesn't seem to be a valid range: " + temp, place, null, tiddler);
									}
								} else if (result[1] === ':') {
									// term, prior must have been a definition (we hope)
									// we should now have a series of triples: [low, high, term]
									entries[entries.length-1].push(result[2]);
								}
								result = this.defRE.exec(t.text);
							}
							// find lowest range
							temp = entries[0];
							low = parseInt(temp[0]);
							// find highest range
							temp = entries[entries.length-1];
							if (temp[1]) {
								high = temp[1];
							} else {
								high = temp[0];
							}
							sizeOfRange = high - low;
							if (preamble) {
								html = wikifyStatic(preamble.trim(), null, tiddler);
							}
							for (i = 0; i < times; i ++) {
								if  (!force) {
									// don't require tables to start with number 0
									r = Math.ceil(Math.random() * sizeOfRange);
								} else {
									r = Math.min(force, high);
								}
                                                                r = r + low;
								// find the entry that r falls within
								rangeEntry = "Couldn't find range encompassing value " + r;
								for (var j = 0; j < entries.length; j++) {
									if (r < entries[j][0]) {
										// too high, not going to see anything with the proper range any more
										break;
									}
									rangeEntry = entries[j][2];
									if (entries[j][1] && r <= entries[j][1]) {
										break;
									}
								}
								temp = wikifyStatic(rangeEntry, null, tiddler);
								resultList.push(temp);
							}
							html += resultList.join(sep);
							html = html.replace(/<[\/]*span>/igm, '');
							wikify(html, place, null, tiddler);
						} else {
							if (t.text.trim().length > 0) {
								for (i = 0; i < times; i++) {
									temp = wikifyStatic(t.text, null, tiddler);
									resultList.push(temp);
								}
								html += resultList.join(sep);
								html = html.replace(/<[\/]*span>/igm, '');
								wikify(html, place, null, tiddler);
							} else {
								wikify("Table " + t.title + " appears to be empty", place, null, tiddler);
							}							
						}
					}
                    // by this point html should contain something worthwhile
                    if (set) {
                        this.saveVar(table, set, html);
                    }
				} else {
					// see if dice were defined
					if (!dice) {
						// see if it's a dice string
						result = this.diceRE.test(table);						
						if (!result) {
                            // see if it's a variable
                            t = store.getTiddler("Rollon_" + table);
                            if (t) {
            					wikify(t.text, place, null, tiddler);
                                return;
                            } else {
                                wikify("No Tiddler named " + table + " found", place);
                                return;
                            }
						} else {
							dice = table;
						}
					}
					for (i = 0; i < times; i++) {
						dieRoll = this.rollExpr(table);
						resultList.push(dieRoll);
					}
					dieRoll = resultList.join(sep).toString();
					wikify(dieRoll, place, null, tiddler);
				}
			} else {
				wikify("rollon requires at least one parameter", place);
			}
		} else {
			if (table) {				
				wikify("roll on [[" + table + "]]", place);
				btn = createTiddlyButton(place,"roll","<<rollon " + paramString + ">>", config.macros.rollon.onClick);
				btn.resultName = resultName;
				btn.suffixText = this.suffixText;
				btn.suffixPattern = this.suffixPattern;
				btn.zeroPad = this.zeroPad;
				btn.sparse = this.sparse;
                btn.overWrite = overWrite;
			} else {
				wikify("rollon macro requires at least one parameter", place);			
			}
		}
	},
    substVariables : function (expr) {
        var variableRE = /{([^}]+)}/g;
        var text = "";
        var t = null;
        var replaceVariable = function(match, name) {
            if (name.substr(0, 2) !== "*#") {
                t = store.getTiddler(name);
            } else {
                // try to find a match
                var varNameRE = new RegExp("#" + name.substr(2) + "$");
                var variableTiddlers = store.filterTiddlers("[tag[rollonVar]]");
                for (var i = 0; i < variableTiddlers.length; i++) {
                    if (varNameRE.test(variableTiddlers[i].title) ) {
                        alert("Found match=" + variableTiddlers[i].title)
                        t = variableTiddlers[i];
                        break;
                    }
                }
            }
            if (t) {
                text = t.text;
            }
            return text;
        };
        expr = expr.replace(variableRE, replaceVariable);
        return expr;
    },
	rollExpr: function (expr) {
        expr = this.substVariables(expr);
		this.diceRE.lastIndex = 0;
		var match = this.diceRE.exec(expr);
		var diceExpr, result;
		if (match && match[3]) {
			this.diceRE.lastIndex = 0;
			diceExpr = expr.replace(this.diceRE, "this.rollSpecial($1, $2, '$3')");
		} else {
			this.diceRE.lastIndex = 0;
			diceExpr = expr.replace(this.diceRE, "this.roll($1, $2)");
		}
		result = 0;
		result = eval(diceExpr);
		return result;
	},
	roll: function(dice, sides) {
		var result = 0, i = 0;
		for (i = 0; i < dice; i++) {
			result += Math.ceil(Math.random() * sides);
		}
		return result;
	},
	rollSpecial: function(dice, sides, option) {
		var result = 0;
		if (option.toLowerCase() === 't') {
			return this.rollTT(dice, sides);
		}
		return result;
	},
	rollTT: function(dice, sides) {
		// Tunnels & Trolls: doubles or triples add and roll over
		var result = 0, die = 0, i = 0;
		var allSame = true;
		var previous;
		if (dice === 2 || dice === 3) {
			while (allSame === true) {
				previous = 0;
				for (i = 0; i < dice; i++ ) {
					die = Math.ceil(Math.random() * sides);
					result += die;
					if (die !== previous && previous !== 0) {
						allSame = false;
					}
					previous = die;
				}
			}
		} else {
			return this.roll(dice, sides);
		}
		return result;
	},
    saveVar: function(namespace, name, value) {
        var nameSpaceRE = /^([^#]+)#/;
        var title;
        if (nameSpaceRE.test(name)) {
            // provided namespace
            title = name;
        } else {
            title = namespace + "#" + name; // default namespace
        }
        var tags=["rollonVar", "excludeLists"];
        var fields={}; // an empty object
        var who="Rollon"; // current username
        var when=new Date(); // current timestamp
        var tid=store.getTiddler(title);
        if (tid) { fields=tid.fields; }
        store.saveTiddler(title,title,value,who,when,tags,fields);
    },
	onClick: function(ev) {
		if (!ev) {
			ev = window.event;
		}
		var button = this;
        var t;
		var macroText = button.title;
        var newTitle;
		var resultName = button.resultName || "Default Roll Result";
		if (button.resultName === "prompt") {
			resultName = prompt("Name for Result?");
		}
        if (button.overWrite === false) {
            var root=resultName.replace(this.suffixPattern,''); // title without suffix..unlikely to have it at this point, but let's be safe
            // find last matching title
            var last=root;
            if (this.sparse) { // don't fill-in holes... really find LAST matching title
                var tids=store.getTiddlers('title','excludeLists');
                for (t=0; t<tids.length; t++) if (tids[t].title.startsWith(root)) last=tids[t].title;
            }
            // get next number (increment from last matching title)
            var n=1; var match=this.suffixPattern.exec(last); if (match) n=parseInt(match[1])+1;
            newTitle=root+this.suffixText.format([String.zeroPad(n,this.zeroPad)]);
            // if not sparse mode, find the next hole to fill in...
            while (store.tiddlerExists(newTitle)||document.getElementById(story.idPrefix+newTitle))
                { n++; newTitle=root+this.suffixText.format([String.zeroPad(n,this.zeroPad)]); }

        } else {
            newTitle = resultName;
            store.removeTiddler(newTitle);
            story.closeTiddler(newTitle, true);
        }
		//t = store.getTiddler(newTitle);
		t = store.createTiddler(newTitle);
		t.set(newTitle, macroText);
		t.tags = ["rollonResult"];
		t.modifier = "Rollon";
		story.displayTiddler(null, newTitle);
		var tiddlerHTML = story.getTiddler(newTitle).innerHTML;
		var viewerClass = '<div class="viewer">';
		var viewerPos = tiddlerHTML.indexOf(viewerClass);
		if (viewerPos > -1) {
			var endDivPos =  tiddlerHTML.indexOf("</div>", viewerPos);
			var displayedText = tiddlerHTML.substring(viewerPos + viewerClass.length, endDivPos);
			displayedText.replace(/<[\/]*span>/igm, '');
			t.set(null,displayedText);			
		}		
		ev.returnValue = false;
		
	}
	
};

String.prototype.trim = function() {
	return this.replace(/^\s+|\s+$/g,"");
}
String.prototype.ltrim = function(){
	return this.replace(/^\s+/, "");
}
String.prototype.rtrim = function(){
	return this.replace(/\s+$/, "");
}

} //# end of "install only once"


//}}}
<<rollon "Character Names">>: <<rollon SWClass>> Level <<rollon SWLevel>> <<rollon SWSex>> Age: <<rollon SWAge>>  <<rollon SWAlignment>> Aligned <<rollon SWFeatures>>, <<rollon SWNature>> /% From Grim's SW Random NPC charts at http://www.swordsandwizardry.com/grimnpcgenerator.pdf Copyright James Cone 2009 -- this is in a comment so that it doesn't appear after every NPC %/
;1
:<<rollon 1d20+10>>
;2-3
:<<rollon 1d10+31>>
;4-5
:<<rollon 1d8+41>>
;6
:<<rollon 1d10+50>>
* Chaos
* Neutral
* Good
# <<rollon SWElfOrNecro>>
# Cleric
# Fighter
# Dwarf
# Halfling
# <<rollon SWMageOrPaladin>>
* Elf
* Necromancer
1       Twitchy
2       Lazy Eye
3       Stutterer
4       Gap Toothed
5       Limps
6       Tattooed
7       Earrings
8       Sunken Eyed
9       Thin Lipped
10      Big Eared
11      Pointy Nosed
12      Square Jawed
;1-5
:1
;6-7
:2
;8-9
:3
;10
:4
* Magic User
* Paladin
1       Smiling
2       Sullen
3       Affable
4       Excitable
5       Squeamish
6       Rude
7       Oblivious
8       Cowardly
9       Helpful
10      Lazy
11      Trustworthy
12      Shady
13      Scurrilous
14      Adept
15      Intuitive
16      Curious
17      Bored
18      Energetic
19      Clumsy
20      Nervous
* Male
* Female
a plugin for rolling randomly on tables
Rollon Plugin
;1–20 
:None
;21–28 
:Increase your Current Ability in one characteristic by <<rollon 1d6>>
;29–32
:Increase your Current Ability in two characteristics by 1d6+2 or in one characteristics by 1d10+2.
;33 
:Special Attribute
;34–36 
:Increase any Current Abilities by a total of <<rollon 2d10>>. The total may not exceed the number rolled.
;37 
:Your face bears pox scars from an old disease. Reduce Appearance 50% rounded down.
;38 
:You have a pronounced limp from an old wound. Reduce Agility by 20% rounded down.
;39 
:You recently escaped from a prison in a neighboring nation. You are a wanted felon in the land of the Referee’s choice.
;40-41 
:You escaped from a prison in the nation that the adventure is starting in within the last <<rollon 1d6>> days, and are a wanted felon.
;42 
:You are under a powerful Geas, the referee will set all parameters of its effect.
;43 
:You were raised among the Faerry. In addition to normal human Knowledge, you speak the tongue of the Faerry Sidh with an EL of 60.
;44 
:Special Attribute [Roll on a second table of bonus magical powers]
;45–47 
:Past luck garners you <<rollon 1d100>> SC.
;48 
:Past luck garners you <<rollon 2d10+10>> GC.
;49 
:Past luck garners you <<rollon 1d3>> bars of Silver.
;50-51 
:You possess <<rollon 1d3>> Small Jewels of unknown value. If your Station is zero, you stole them.
;52 
:You have <<rollon 1d2>> Medium Jewels of unknown value. If your Station is 1 or less, you stole them.
;53 
:You possess 1 Large Jewel of unknown value. If your Station is 2 or less you stole it.
;54–56 
:<<rollon KnownJewels>>
;57 
:Increase any Native Abilities by a total of <<rollon 1d6>>. (Increase Maximum Abilities as appropriate afterwards).
;58 
:You have a piece of Jewelry. You have no idea where you got it or what it is worth. You have had it since birth. The Referee will determine the type of jewelry.
;59–62 
:Take any 3 items from the Equipment List with a combined value under 40GC and an individual value of at least 5GC.
;63 
:Take any 1 item from the Equipment list with a value between 10 and 100GC
;64 
:If your Station is 4 or higher, you are a prosperous land owner in your homeland.  You control <<rollon "1d10*1d10">> hundreds of acres. (Your income from this is 1SC per acre per year). If your Station is 3 or less you control <<rollon "1d10*1d10">> acres as a personal freehold. (Income from this land is 3CC per acre per year). All income figures are gross values.
;65 
:You have a random Magic Amulet.
;66 
:Special Attribute. [Roll on a second table of bonus magical powers]
;67–70 
:Training with a Skilled Master raises your Expertise with all weapons in a weapon type of your choice to the maximum EL currently possible for your Character. No Expertise Cost is assessed for this training.
;71 
:You have a random magic weapon.
;72 
:You have a random type of magic armor.
;73 
:You have an authentic map to a large treasure. Referee will roll 1d6+14 on the Map Table for it’s value.
;74 
:You possess <<rollon 1d6>> doses of a random Potion or Elixir.
;75 
:You possess <<rollon 1d6>> doses of a random Natural Magic material.
;76 
:You have <<rollon 1d6>> doses of a random Powder.
;77 
:Special Attribute. [Roll on a second table of bonus magical powers]
;78–81 
:You have a Pet. It is a normally wild animal. The Referee will determine its species and full parameters.
;82 
:You have a Magic Item. The Referee will determine what it is.
;83-84 
:Apprentice in the Magic Path of your choice if your Native Intelligence is 15 or higher. If not, as for 82.
;85-86 
:You have a powerful enemy. Gain <<rollon 1d10*10>> Experience Points and D100 SC. The Referee will determine the enemy based on your actual gain, i.e. the more gained, the more powerful the enemy. The enemy will seek revenge whenever possible.
;87 
:Raise your Native Ability in any Mental Attribute by <<rollon 1d3>>. (Raise Maximum Ability as appropriate afterwards).
;88 
:Special Attribute. [Roll on a second table of bonus magical powers]
;89–91 
:You have a Personal Contact among your people. The Referee will determine his or her parameters.
;92-93 
:You have a Personal Contact, who must reside in the area that the party is starting in.
;94 
:Raise your Native Ability in any Physical Attribute, including Constitution and Appearance.
;95–96 
:You have a friend. You are accompanied by a Character Class NPC. The Referee will determine the attachment and all parameters of the friend. The CEL of the friend is <<rollon 1d6+4>>. He may not be a magic-user. He will defend his friend to the death.
;97 
:You were raised among the Elves. In addition to Human Knowledge, you speak the tongue of the Elf Sidh with an EL of 60.
;98 
:An old friend, who once saved your life, is lost in a hostile land. You are aware of his whereabouts. He holds the key to a great treasure that both of you were searching for.
;99 
:You are the master of a Firesnake.
;100 
:You have come under extraordinary influences. The referee will determine something exceptionally good or bad. If he does not wish to do so, roll three times on this table or twice on the Special Attribute table. 

This table comes from Powers & Perils, and was recently posted at [[Jeff's Gameblog|http://jrients.blogspot.com/2009/03/master-of-firesnake.html]]
<<rollon dice:4d6 times:24 table:"WORLD TYPE TABLE" separator:'<br>'
overWrite:true>>
TiddlyWiki is a single html file which has all the characteristics of a wiki - including all of the content, the functionality (including editing, saving, tagging and searching) and the style sheet. Because it's a single file, it's very portable - you can email it, put it on a web server or share it via a USB stick.

For more information about TiddlyWiki and how to use it visit [[TiddlyWiki.com|http://tiddlywiki.com]] and [[TiddlyWiki.org|http://tiddlywiki.org]]
/***
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 = 'rollon';

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

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

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

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

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

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

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

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

});
//}}}
| !date | !user | !location | !storeUrl | !uploadDir | !toFilename | !backupdir | !origin |
| 13/03/2009 00:45:04 | JoshuaMacy | [[/|http://rollon.tiddlyspot.com/]] | [[store.cgi|http://rollon.tiddlyspot.com/store.cgi]] | . | [[index.html | http://rollon.tiddlyspot.com/index.html]] | . | ok |
| 13/03/2009 00:49:25 | JoshuaMacy | [[/|http://rollon.tiddlyspot.com/]] | [[store.cgi|http://rollon.tiddlyspot.com/store.cgi]] | . | [[index.html | http://rollon.tiddlyspot.com/index.html]] | . | ok |
| 13/03/2009 01:21:52 | JoshuaMacy | [[/|http://rollon.tiddlyspot.com/]] | [[store.cgi|http://rollon.tiddlyspot.com/store.cgi]] | . | [[index.html | http://rollon.tiddlyspot.com/index.html]] | . | ok |
| 13/03/2009 01:22:16 | JoshuaMacy | [[/|http://rollon.tiddlyspot.com/]] | [[store.cgi|http://rollon.tiddlyspot.com/store.cgi]] | . | [[index.html | http://rollon.tiddlyspot.com/index.html]] | . |
| 15/12/2009 22:49:58 | JoshuaMacy | [[Rollon.html|file:///C:/Users/Joshua/Documents/Rollon/Rollon.html]] | [[store.cgi|http://rollon.tiddlyspot.com/store.cgi]] | . | [[index.html | http://rollon.tiddlyspot.com/index.html]] | . | ok |
| 15/12/2009 22:52:51 | JoshuaMacy | [[Rollon.html|file:///C:/Users/Joshua/Documents/Rollon/Rollon.html]] | [[store.cgi|http://rollon.tiddlyspot.com/store.cgi]] | . | [[index.html | http://rollon.tiddlyspot.com/index.html]] | . |
| 06/07/2012 14:01:32 | JoshuaMacy | [[/|http://rollon.tiddlyspot.com/]] | [[store.cgi|http://rollon.tiddlyspot.com/store.cgi]] | . | [[index.html | http://rollon.tiddlyspot.com/index.html]] | . | failed |
| 06/07/2012 14:01:47 | rollon | [[/|http://rollon.tiddlyspot.com/]] | [[store.cgi|http://rollon.tiddlyspot.com/store.cgi]] | . | [[index.html | http://rollon.tiddlyspot.com/index.html]] | . |
| 06/07/2012 14:01:48 | rollon | [[/|http://rollon.tiddlyspot.com/]] | [[store.cgi|http://rollon.tiddlyspot.com/store.cgi]] | . | [[index.html | http://rollon.tiddlyspot.com/index.html]] | . | failed | failed |
| 06/07/2012 14:02:06 | rollon | [[/|http://rollon.tiddlyspot.com/]] | [[store.cgi|http://rollon.tiddlyspot.com/store.cgi]] | . | [[index.html | http://rollon.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");


//}}}

;4-7
:Asteroid Belt
;8-9
:Barren
;10
:Desert (Rock)
;11-12
:Garden (Very Thin atmosphere)
;13-14
:Garden (Thin atmosphere)
;15-16
:Garden (Standard atmosphere)
;17-18
:Garden (Dense atmosphere)
;19-21
:Hostile
;22-24
:Garden (Very Dense atmosphere)
;4-7
:Asteroid Belt
;8-9
:Barren
;10
:Desert (Rock)
;11-12
:Garden (Very Thin atmosphere)
;13-14
:Garden (Thin atmosphere)
;15-16
:Garden (Standard atmosphere)
;17-18
:Garden (Dense atmosphere)
;19-21
:Hostile
;22-24
:Garden (Very Dense atmosphere)
# truly
# deeply
# mildly
# slightly
# mostly