<!--{{{-->
<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>>
Cryptomx@P8yKK1jNIP1MpC3aSzBc91_ybdPTJEu1EbwsE6nJ45PjRz73WB"FVoYJ1Ws_ wHGt9uLy5B4ZZMR9k"OO9iL4CWKxz6V4bUA4p2KOFCY9Tg"yVRQzF3Nul0Z1 jhECC8D2j6CjFWwEk_jSkUFX5sgOMcuA_CEE8N9XQLRIFB_e6Lhw"3KIaR1b OZ"g_GJXV2ELhcTVSgqI25i0mEBAFMYXP8"lbvan0lLlkTUJy9M59IO_tcOs KvM93mG1ljyeNMlkJs"mXOfJYTQsAGs6lp5WcOjo"BPFiLZ6KaWlos1A3DON DeLsiwUIx"E9kqWH"TzV9H4CrcsCRuaAePJujkUJNdBR0mVw4DKZKwZRXpZ0 VDodIa4EdfT7zYd4Oupe28xaIj"Irb8fRFQOIFZZURE5ei8I"xf6FpSow2qk 4S4l8418g3uS7V3FEtBbE_QoeNctEm5LdbRWWgbdFFdmDsCH1sv61oUP6ymQ 0tR"eQgP2tXbwAQDpPoOhoSWAqXdtkguhV6AS3zlm46MLMHrTbnWGQEYSsIa 5v69TiguRJYECSR9WfojNPeYUIyJohzYVAOZrmFtcTf_1YktOiOU1XA2Zc9y SF1dOqj_h6xeWGv50LDGSsYYBqTrD"bluFJ_nKwyPo91E16YliDmHrXO3JTx YHxfi"3xciIieatJ6rcY1tmWf7VD9sd_uVX52urvm1UdBKGf2vAT4Od61nYY "ORfzY0uxDnoTtF6hGcte279g""vaiRHHN6hweOP1lsAWDoesShonpp8W64y SgWwvKPWQcQShyt6fguN3rddH7Ee"xu0e42VjvcSonPOoUZSV8C7rk_okME" HuSlHPPxCX0_jFambpvPxhQLt8p"TTkbx1eSMQ"LYTYNpI0Mg1Zm0Se3EISJ KtPY0f_KjKGAxh3ZVM7jf9xxdJxAmMCXBzsBnsEQYyVTOykQh1CkQsjWTFF1 T5_f20sALNLhw6ZMJfh1hDlYlhNQGiipoa6VsG0lnyC2JQVKt7792Zo8yeFv Vwi2qBo5_A8GLE95SN1hhZ1OFxRVJhI7XE8xxKEiPF8W5ZBLZ9cDlEeUD1ct r94OLAYING2UHy6nYjBaIEl0Et6fzbFA9ZCCP_zpNggHqt6YvPmSwRYRKAT0 gJWXkwr"v0vO4Tq3GRS7LDIEXyfcoh0L1AOKLOiMD"uFmZaVr0ILzqx55BGx J6DYmGel1RM1YjEQG0_nTt0drZBxt3d8A"7xuRjBZiumhMBG3jlxJ8Yk8f35 jd3mhGC_v6Gu7GdvWkirCbUdW3i5GY9veGc6HATdsFSc0bNY70"hhNrrAfDm MV5MwP_e2lSabXHbZTDj2vUHJE6l"tQq62Tgn99ftmP6kySJqjW7GIBCegB7 o6uK514sM2HNUbUWvBslERoResiooueWtXlKn"YZ
/***
|''Name:''|EncryptedVaultPlugin|
|''Description:''|Adds RC4 encryption and password protection to tiddywiki.|
|''Version:''|1.0.1|
|''Date:''|Dec 21,2007|
|''Source:''|http://visualtw.ouvaton.org/VisualTW.html|
|''Author:''|Pascal Collin|
|''License:''|[[BSD open source license|License]]|
|''~CoreVersion:''|2.2.0|
|''Browser:''|Firefox 2.0; InternetExplorer 6.0, others|
!Description
*Create an ''encrypted vault'' where all tiddlers are ''password protected''. 
*By default, only the system tiddlers aren't encrypted.
*Even shadow tiddlers (MainMenu, SiteTitle, PageTemplate, StyleSheet, ...) ''can be encrypted''. The shadow version is used until unlocking.
!Demo
Use <<unlock>> button on a protected wiki. By example : http://visualtw.ouvaton.org/demo/EncryptedVaultPlugin.html
!Installation
#Import the plugin (tagged as systemConfig)
#Save and reload
#Save once more time to create the encrypted vault
#Reload and set a password
!Usage
*Use <<unlock>><<setPassword>> button (available by default in SideBarOptions)
*Use a blank password to save unencrypted (disable vault usage)
*Use {{{unencrypted}}} tag to avoid encryption for some tiddler
*Use {{{forceEncryption}}} tag to force some shadow tiddler to be encrypted
!Configuration
The following macros are available :
*{{{<<unlock ButtonTitle ButtonTooltip OpenTiddlersWhenUnlock CloseTiddlersWhenUnlock>>}}} creates a button to unlock the encrypted vault (all parameters are optionnal)
*{{{<<setPassword ButtonTitle ButtonTooltip>>}}} if unlocked, creates a button to set the current password (all parameters are optionnal)
*{{{<<purge ButtonTitle ButtonTooltip>>}}} if locked, creates a button to purge a locked vault, useful for lost password (encrypted content is the deleted)
*{{{<<ifLocked tiddlyText>>}}} displays tiddlyText (wikified) if the vault is locked
*{{{<<ifUnlocked tiddlyText>>}}} displays tiddlyText (wikified) if the vault is unlocked
<<ifLocked "!!!!Lost password ?">><<ifLocked "Click on">> <<purge>><<ifLocked "to delete any content locked in the encrypted vault.">>
***/
//{{{

config.messages.vaultCreationInfo = "The encrypted vault has been created";
config.messages.purgeConfirm = "Purge the encrypted vault ?\n\nAll unlocked content will be lost.";
config.messages.vaultPurgedInfo = "All contents have been purged from encrypted vault.\nPassword has been blanked.\nYou must save once to apply this changes.";
config.messages.vaultEncryptedInfo = "Saving with encryption";
config.messages.vaultUnchangedInfo = "No changes in Encrypted vault";
config.messages.noLockedVaultWarning = "Unable to proceed. No locked encrypted vault.";
config.messages.emptyVaultInfo = "Saving without encryption";
config.messages.saveWithLockedVaultConfirm = "Encrypted vault is locked. No changes will apply inside.\n\nAre you sure ?";
config.messages.confirmOverload = "This following tiddler already exists in system store. Overload ?\nOK : the encrypted version will replace the system store version\nCancel : the system store version will replace the encrypted version";

SaverBase.systemStore="unencrypted";
SaverBase.vault="forceEncryption";

var startSaveVaultArea = '<div id="' + 'vaultArea">'; // Split up into two so that indexOf() of this source doesn't find it
var endSaveVaultArea = '</d' + 'iv>';

config.shadowTiddlers.SideBarOptions = config.shadowTiddlers.SideBarOptions.replace(/<<saveChanges>>/,"<<unlock>><<setPassword>><<saveChanges>>");
config.shadowTiddlers.GettingStarted+="\n\n<<ifLocked 'This TiddlyWiki use EncryptedVaultPlugin. To load protected content click on'>><<unlock>><<ifUnlocked 'This TiddlyWiki use EncryptedVaultPlugin. To set or change password click on'>><<setPassword>>"

window.updateOriginal= function(original,posDiv)	// overriding the TW2.2 standard function
{
	var vaultIsUpdatable = (!locateVaultArea(original) || !vault.isLocked() || vault.purge);  // vault is new, unlocked or must be purged
	
	if(!posDiv)
		posDiv = locateStoreArea(original);
	if(!posDiv) {
		alert(config.messages.invalidFileError.format([localPath]));
		return null;
	}
	var revised = original.substr(0,posDiv[0] + startSaveArea.length) + "\n" +
				convertUnicodeToUTF8((vaultIsUpdatable && vault.password) ? store.allUnencryptedTiddlersAsHtml() : store.allTiddlersAsHtml())  + "\n" +
				original.substr(posDiv[1]);
				
	if (vaultIsUpdatable) {
		posVault = locateVaultArea(original)
		if(!posVault) {
			revised=createVault(revised);
			posVault = locateVaultArea(revised);
			if(!posVault) {
				alert(config.messages.invalidFileError.format([localPath]));
				return;
			}
		}
		var revised = revised.substr(0,posVault[0] + startSaveVaultArea.length) +
					convertUnicodeToUTF8(vault.password ? vault.encrypt(store.allEncryptedTiddlersAsHtml()) : "") +
					revised.substr(posVault[1]);
		if (vault.password) displayMessage(config.messages.vaultEncryptedInfo);
		else displayMessage(config.messages.emptyVaultInfo);
	}
	else displayMessage(config.messages.vaultUnchangedInfo);
	
	var newSiteTitle = convertUnicodeToUTF8(getPageTitle()).htmlEncode();
	revised = revised.replaceChunk("<title"+">","</title"+">"," " + newSiteTitle + " ");
	revised = updateLanguageAttribute(revised);
	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;
}

function createVault(original) {
	var revised=original.replace(/<!--POST-SHADOWAREA-->/,'<!--POST-SHADOWAREA-->\n<div id="vaultArea"></div>\n<!--POST-VAULTAREA-->');
	var vaultStyles = '<!--PRE-VAULTSTYLE-START-->\n<style type="text/css">\n#vaultArea {display:none;}\n#vaultArea div {padding:0.5em; margin:1em 0em 0em 0em; border-color:#fff #666 #444 #ddd; border-style:solid; border-width:2px; overflow:auto;}\n</style>\n<!--PRE-VAULTSTYLE-END-->\n';
	if (revised.search("<!--PRE-VAULTSTYLE-START-->")<0) var revised=revised.replace(/<!--POST-HEAD-START-->/,vaultStyles +'<!--POST-HEAD-START-->');
	alert(config.messages.vaultCreationInfo);
	return revised;
}

function locateVaultArea(original)  //cloned from the TW2.2 standard function
{
	// Locate the vaultArea div's. Should be just before the storeArea div
	var posOpeningDiv = original.indexOf(startSaveVaultArea);
	var limitClosingDiv = original.indexOf("<"+"!--POST-VAULTAREA--"+">");
	if(limitClosingDiv == -1)
		limitClosingDiv = original.indexOf("<div id="+'"storeArea"'+">");
	var posClosingDiv = original.lastIndexOf(endSaveVaultArea,limitClosingDiv);
	return (posOpeningDiv != -1 && posClosingDiv != -1) ? [posOpeningDiv,posClosingDiv] : null;
}

TiddlyWiki.prototype.allUnencryptedTiddlersAsHtml = function() {
	return store.getSaver().externalize(store, SaverBase.systemStore);
};

TiddlyWiki.prototype.allEncryptedTiddlersAsHtml = function() {
	return store.getSaver().externalize(store, SaverBase.vault);
};

SaverBase.prototype.externalize = function(store, tiddlerType) // overriding the TW2.2 standard function
{
	var results = [];
	var tiddlers = store.getTiddlers("title");
	for(var t = 0; t < tiddlers.length; t++)
		if (!tiddlerType || (this.getTiddlerType(tiddlers[t]) == tiddlerType))	// this line was changed from standard function
			results.push(this.externalizeTiddler(store,tiddlers[t]));
	return results.join("\n");
};

SaverBase.prototype.getTiddlerType= function(tiddler) {
	if (tiddler.isTagged(SaverBase.vault)) return SaverBase.vault;
	if (store.isShadowTiddler([tiddler.title])) return SaverBase.systemStore;
	if (tiddler.isTagged("systemConfig")||tiddler.isTagged(SaverBase.systemStore)) return SaverBase.systemStore;
	return SaverBase.vault;
};

LoaderBase.prototype.loadTiddler = function(store,node,tiddlers) // overriding the TW2.2 standard function
{
	var title = this.getTitle(store,node);
	if (store.getTiddler(title) && !confirm(config.messages.confirmOverload+"\n\n"+title)) // this line was changed from standard function
		return;	
	if(title) {
		var tiddler = store.createTiddler(title);
		this.internalizeTiddler(store,tiddler,title,node);
		tiddlers.push(tiddler);
	}
};

window.saveChanges_noVault = window.saveChanges;
window.saveChanges= function(onlyIfDirty,tiddlers){
	if (!vault.isLocked() || vault.purge || !vault.exists() || (vault.isLocked() && confirm(config.messages.saveWithLockedVaultConfirm)))
		saveChanges_noVault(onlyIfDirty,tiddlers);
}

vault = {
	load : function(){
		if (!vault.isLocked()) {
			alert(config.messages.vaultAlreadyUnlockedWarning);
			return false;
		}
		else {
			var storeElem = document.getElementById("vaultArea");
			if (storeElem) {
				var src = storeElem.innerHTML;
				var pwd = vault.password ? vault.password : "";
				while ((vault.isEncrypted(src)) && (pwd!=null)) {
					if (pwd) src = vault.decrypt(src, pwd);
					if (vault.isEncrypted(src)) pwd = prompt(vault.prompt,pwd);
				}
				if (pwd!=null) vault.password = pwd;
				if (!vault.isEncrypted(src)) {
					var wasDirty = store.isDirty();
					var e = document.createElement("div");
					e.innerHTML=src;
					if (src) store.getLoader().loadTiddlers(store,e.childNodes);
					vault.loaded = true;
					refreshAll();
					story.refreshAllTiddlers();
					store.setDirty(wasDirty);
					return true;
				}
				else return false;
			}
		}
	},
	decrypt : function(src,pwd){
		var res = Crypto.cryptomx.decrypt(pwd,src.substr(vault.prefix.length));
		return res  ? res : src;
	},
	isEncrypted : function(src) {
		return (src.substr(0,vault.prefix.length) == vault.prefix);
	},
	encrypt : function(src){
		return vault.password ? vault.prefix + Crypto.cryptomx.encrypt(vault.password,src) : src;
	},
	isLocked : function(){
		if (vault.loaded) return false;
		var storeElem = document.getElementById("vaultArea");
		return (!storeElem || (storeElem && vault.isEncrypted(storeElem.innerHTML)));
	},
	exists : function() {
		return (document.getElementById("vaultArea")!=null);
	},
	prefix : "Cryptomx@",
	prompt : "Enter a password",
	loaded : false,
	purge : false
}

config.macros.unlock = {
	handler : function(place,macroName,params,wikifier,paramString,tiddler) {
		var label = params[0] ? params[0] : "unlock vault";
		var tooltip = params[1] ? params[1] : "unlock encrypted vault";
		var openTiddlers = params[2] ? params[2] : "";
		var closeTiddlers = params[3] ? params[3] : "";
		if (vault.isLocked() && vault.exists()) {
			var btn = createTiddlyButton(place,label, tooltip,this.onClick);
			btn.setAttribute("openTiddlers",openTiddlers);
			btn.setAttribute("closeTiddlers",closeTiddlers);
		}
	},
    onClick:function(){
		var openTiddlers = this.getAttribute("openTiddlers");
		var closeTiddlers = this.getAttribute("closeTiddlers");
		if (vault.load()) {
			if (closeTiddlers) {
				var tiddlers = store.filterTiddlers(closeTiddlers);
				for(var t=0; t<tiddlers.length; t++) {
					var elem = document.getElementById(story.idPrefix + tiddlers[t].title);
					if (elem && elem.getAttribute("dirty")!="true")
						story.closeTiddler(tiddlers[t].title);
				}
			}
			if (openTiddlers) {
				var tiddlers = store.filterTiddlers(openTiddlers);
				for(var t=0; t<tiddlers.length; t++)
					story.displayTiddler("bottom",tiddlers[t].title);
			}
		}
		return false;
	}
}

config.macros.setPassword = {
	handler : function(place,macroName,params,wikifier,paramString,tiddler) {
		var label = params[0] ? params[0] : "set password";
		var tooltip = params[1] ? params[1] : "Set password for encrypted vault";
		if (!vault.isLocked()) createTiddlyButton(place, label, tooltip,this.onClick);
	},
    onClick:function(){
		var pwd = prompt(vault.prompt,(vault.password ? vault.password : ""));
		if (pwd != null) vault.password = pwd;
		return false;
	}
}

config.macros.purge = {
	handler : function(place,macroName,params,wikifier,paramString,tiddler) {
		var label = params[0] ? params[0] : "purge vault";
		var tooltip = params[1] ? params[1] : "Delete locked vault";
		if (vault.isLocked() && vault.exists()) createTiddlyButton(place,label, tooltip,this.onClick);
	},
    onClick:function(){
		if (!vault.isLocked())
			alert(config.messages.noLockedVaultWarning);
		else
			if (confirm(config.messages.purgeConfirm)) {
				vault.purge=true;
				alert(config.messages.vaultPurgedInfo);
			}
		return false;
	}
}

config.macros.ifLocked = {
	handler : function(place,macroName,params,wikifier,paramString,tiddler) {
		if (vault.isLocked() && vault.exists()) wikify(params[0],place,null,tiddler);
	}
}

config.macros.ifUnlocked = {
	handler : function(place,macroName,params,wikifier,paramString,tiddler) {
		if (!vault.isLocked()) wikify(params[0],place,null,tiddler);
	}
}

//}}}


/***
Cryptomx code from http://cryptomx.sourceforge.net
***/
//{{{
Crypto.cryptomx = {
	dg :'',
	makeArray: function(n) {
		for (var i=1; i<=n; i++) {
			this[i]=0
		}
		return this
	},
	rc4: function(key, text) {
		var i, x, y, t, x2;
		this.status("rc4")
		s=this.makeArray(0);
		
		for (i=0; i<256; i++) {
			s[i]=i
		}
		y=0
		for (x=0; x<256; x++) {
			y=(key.charCodeAt(x % key.length) + s[x] + y) % 256
			t=s[x]; s[x]=s[y]; s[y]=t
		}
		x=0;  y=0;
		var z=""
		for (x=0; x<text.length; x++) {
			x2=x % 256
			y=( s[x2] + y) % 256
			t=s[x2]; s[x2]=s[y]; s[y]=t
			z+= String.fromCharCode((text.charCodeAt(x) ^ s[(s[x2] + s[y]) % 256]))
		}
		return z
	},
	badd: function(a,b) { // binary add
		var r=''
		var c=0
		while(a || b) {
			c=this.chop(a)+this.chop(b)+c
			a=a.slice(0,-1); b=b.slice(0,-1)
			if(c & 1) {
				r="1"+r
			} else {
				r="0"+r
			}
			c>>=1
		}
		if(c) {r="1"+r}
		return r
	},
	chop:function(a) {
		if(a.length) {
			return parseInt(a.charAt(a.length-1))
		} else {
			return 0
		}
	},
	bsub:function(a,b) { // binary subtract
		var r=''
		var c=0
		while(a) {
			c=this.chop(a)-this.chop(b)-c
			a=a.slice(0,-1); b=b.slice(0,-1)
			if(c==0) {
				r="0"+r
			}
			if(c == 1) {
				r="1"+r
				c=0
			}
			if(c == -1) {
				r="1"+r
				c=1
			}
			if(c==-2) {
				r="0"+r
				c=1
			}
		}
		if(b || c) {return ''}
		return this.bnorm(r)
	},
	bnorm:function(r) { // trim off leading 0s
		var i=r.indexOf('1')
		if(i == -1) {
			return '0'
		} else {
			return r.substr(i)
		}
	},
	bmul:function(a,b) { // binary multiply
		var r=''; var p=''
		while(a) {
			if(this.chop(a) == '1') {
				r=this.badd(r,b+p)
			}
			a=a.slice(0,-1)
			p+='0'
		}
		return r;
	},
	bmod:function(a,m) { // binary modulo
		return this.bdiv(a,m).mod
	},
	bdiv:function(a,m) { // binary divide & modulo
		// this.q = quotient this.mod=remainder
		var lm=m.length, al=a.length
		var p='',d
		this.q=''
		for(n=0; n<al; n++) {
			p=p+a.charAt(n);
			if(p.length<lm || (d=this.bsub(p,m)) == '') {
				this.q+='0'
			} else {
				if(this.q.charAt(0)=='0') {
					this.q='1'
				} else {
					this.q+="1"
				}
				p=d
			}
		}
		this.mod=this.bnorm(p)
		return this
	},
	bmodexp:function(x,y,m) { // binary modular exponentiation
		var r='1'
		this.status("bmodexp "+x+" "+y+" "+m)
		
		while(y) {
			if(this.chop(y) == 1) {
				r=this.bmod(this.bmul(r,x),m)
			}
			y=y.slice(0,y.length-1)
			x=this.bmod(this.bmul(x,x),m)
		}
		return this.bnorm(r)
	},
	modexp:function(x,y,m) { // modular exponentiation
		// convert packed bits (text) into strings of 0s and 1s
		return this.b2t(this.bmodexp(this.t2b(x),this.t2b(y),this.t2b(m)))
	},
	i2b: function(i) { // convert integer to binary
		var r=''
		while(i) {
			if(i & 1) { r="1"+r} else {r="0"+r}
			i>>=1;
		}
		return r? r:'0'
	},
	t2b:function(s) {
		var r=''
		if(s=='') {return '0'}
		while(s.length) {
			var i=s.charCodeAt(0)
			s=s.substr(1)
			for(n=0; n<8; n++) {
				r=((i & 1)? '1':'0') + r
				i>>=1;
			}
		}
		return this.bnorm(r)
	},
	b2t:function(b) {
		var r=''; var v=0; var m=1
		while(b.length) {
			v|=this.chop(b)*m
			b=b.slice(0,-1)
			m<<=1
			if(m==256 || b=='') {
				r+=String.fromCharCode(v)
				v=0; m=1
			}
		}
		return r
	},
	b64s:'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_"',
	textToBase64:function(t) {
		this.status("t 2 b64")
		var r=''; var m=0; var a=0; var tl=t.length-1; var c
		for(n=0; n<=tl; n++) {
			c=t.charCodeAt(n)
			r+=this.b64s.charAt((c << m | a) & 63)
			a = c >> (6-m)
			m+=2
			if(m==6 || n==tl) {
				r+=this.b64s.charAt(a)
				if((n%45)==44) {r+="\n"}
				m=0
				a=0
			}
		}
		return r
	},
	base64ToText:function(t) {
		this.status("b64 2 t")
		var r=''; var m=0; var a=0; var c
		for(n=0; n<t.length; n++) {
			c=this.b64s.indexOf(t.charAt(n))
			if(c >= 0) {
				if(m) {
					r+=String.fromCharCode((c << (8-m))&255 | a)
				}
				a = c >> m
				m+=2
				if(m==8) { m=0 }
			}
		}
		return r
	},

	rand:function(n) {  return Math.floor(Math.random() * n) },
	rstring:function(s,l) {
		var r=""
		var sl=s.length
		while(l>0) {
			l=l-1;
			r+=s.charAt(rand(sl))
		}
		//status("rstring "+r)
		return r
	},
	key2:function(k) {
		var l=k.length
		var kl=l
		var r=''
		while(l--) {
			r+=k.charAt((l*3)%kl)
		}
		return r
	},
	rsaEncrypt:function(keylen,key,mod,text) {
		// I read that rc4 with keys larger than 256 bytes doesn't significantly
		// increase the level of rc4 encryption because it's sbuffer is 256 bytes
		// makes sense to me, but what do i know...

		this.status("encrypt")
		if(text.length >= keylen) {
			var sessionkey=this.rc4(rstring(text,keylen),rstring(text,keylen))

			// session key must be less than mod, so mod it
			sessionkey=this.b2t(bmod(t2b(sessionkey),t2b(mod)))
			alert("sessionkey="+sessionkey)

			// return the rsa encoded key and the encrypted text
			// i'm double encrypting because it would seem to me to
			// lessen known-plaintext attacks, but what do i know
			return this.modexp(sessionkey,key,mod) +
			this.rc4(this.key2(sessionkey),this.rc4(sessionkey,text))
		} else {

			// don't need a session key
			return this.modexp(text,key,mod)
		}
	},
	rsaDecrypt:function(keylen,key,mod,text) {
		this.status("decrypt")
		if(text.length <= keylen) {
			return this.modexp(text,key,mod)
		} else {

			// sessionkey is first keylen bytes
			var sessionkey=text.substr(0,keylen)
			text=text.substr(keylen)

			// un-rsa the session key
			sessionkey=this.modexp(sessionkey,key,mod)
			alert("sessionkey="+sessionkey)

			// double decrypt the text
			return this.rc4(sessionkey,this.rc4(this.key2(sessionkey,text),text))
		}
	},
	trim2:function(d) { return d.substr(0,d.lastIndexOf('1')+1) },
	bgcd:function(u,v) { // return greatest common divisor
		// algorythm from http://algo.inria.fr/banderier/Seminar/Vallee/index.html
		var d, t
		while(1) {
			d=this.bsub(v,u)
			//alert(v+" - "+u+" = "+d)
			if(d=='0') {return u}
			if(d) {
				if(d.substr(-1)=='0') {
					v=d.substr(0,d.lastIndexOf('1')+1) // v=(v-u)/2^val2(v-u)
				} else v=d
			} else {
				t=v; v=u; u=t // swap u and v
			}
		}
	},

	isPrime:function(p) {
		var n,p1,p12,t
		p1=this.bsub(p,'1')
		t=p1.length-p1.lastIndexOf('1')
		p12=this.trim2(p1)
		for(n=0; n<2; n+=this.mrtest(p,p1,p12,t)) {
			if(n<0) return 0
		}
		return 1
	},
	mrtest:function(p,p1,p12,t) {
		// Miller-Rabin test from forum.swathmore.edu/dr.math/
		var n,a,u
		a='1'+this.rstring('01',Math.floor(p.length/2)) // random a
		//alert("mrtest "+p+", "+p1+", "+a+"-"+p12)
		u=this.bmodexp(a,p12,p)
		if(u=='1') {return 1}
		for(n=0;n<t;n++) {
			u=this.bmod(this.bmul(u,u),p)
			//dg+=u+" "
			if(u=='1') return -100
			if(u==p1) return 1
		}
		return -100
	},
	pfactors:'11100011001110101111000110001101',
	// this number is 3*5*7*11*13*17*19*23*29*31*37
	prime:function(bits) {
		// return a prime number of bits length
		var p='1'+this.rstring('001',bits-2)+'1'
		while( ! this.isPrime(p)) {
			p=badd(p,'10'); // add 2
		}
		alert("p is "+p)
		return p
	},
	genkey:function(bits) {
		q=prime(bits)
		do {
			p=q
			q=prime(bits)
		} while(bgcd(p,q)!='1')
		p1q1=this.bmul(this.bsub(p,'1'),this.bsub(q,'1'))
		// now we need a d, e,  and an n so that:
		//  p1q1*n-1=de  -> bmod(bsub(bmul(d,e),'1'),p1q1)='0'
		// or more specifically an n so that d & p1q1 are rel prime and factor e
		n='1'+this.rstring('001',Math.floor(bits/3)+2)
		alert('n is '+n)
		factorMe=this.badd(this.bmul(p1q1,n),'1')
		alert('factor is '+factorMe)
		//e=bgcd(factorMe,p1q1)
		//alert('bgcd='+e)
		e='1'
		// is this always 1?
		//r=bdiv(factorMe,e)
		//alert('r='+r.q+" "+r.mod)
		//if(r.mod != '0') {alert('Mod Error!')}
		//factorMe=r.q
		d=this.bgcd(factorMe,'11100011001110101111000110001101')
		alert('d='+d)
		if(d == '1' && e == '1') {alert('Factoring failed '+factorMe+' p='+p+' q='+q)}
		e=this.bmul(e,d)
		r=this.bdiv(factorMe,d)
		d=r.q
		if(r.mod != '0') {alert('Mod Error 2!')}

		this.mod=this.b2t(bmul(p,q))
		this.pub=this.b2t(e)
		this.priv=this.b2t(d)
	},
	status:function(a) { },//alert(a)}
	encrypt:function(key,text) {
		return this.textToBase64(this.rc4(key,"check:"+text));
	},
	decrypt:function(key,text){
		var uncrypt = this.rc4(key,this.base64ToText(text));
		return (uncrypt.substr(0,6)=="check:") ? uncrypt.substr(6) : null;
	}
}

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

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

bidix.core.loadRemoteFile = loadRemoteFile;
loadRemoteFile = function(url,callback,params)
{
 if ((document.location.toString().substr(0,4) == "http") && (url.substr(0,4) == "http")){ 
 url = store.getTiddlerText("SiteProxy", "/proxy/") + url;
 }
 return bidix.core.loadRemoteFile(url,callback,params);
}
//}}}
/***
|''Name:''|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"
	});
*/
//}}}
/***
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 = 'devoroumov';

// 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 |
| 16/09/2008 15:10:33 | YourName | [[/|http://devoroumov.tiddlyspot.com/]] | [[store.cgi|http://devoroumov.tiddlyspot.com/store.cgi]] | . | [[index.html | http://devoroumov.tiddlyspot.com/index.html]] | . | failed |
| 16/09/2008 15:11:10 | YourName | [[/|http://devoroumov.tiddlyspot.com/]] | [[store.cgi|http://devoroumov.tiddlyspot.com/store.cgi]] | . | [[index.html | http://devoroumov.tiddlyspot.com/index.html]] | . |
| 16/09/2008 15:11:44 | YourName | [[/|http://devoroumov.tiddlyspot.com/]] | [[store.cgi|http://devoroumov.tiddlyspot.com/store.cgi]] | . | [[index.html | http://devoroumov.tiddlyspot.com/index.html]] | . |
| 16/09/2008 15:16:53 | YourName | [[/|http://devoroumov.tiddlyspot.com/]] | [[store.cgi|http://devoroumov.tiddlyspot.com/store.cgi]] | . | [[index.html | http://devoroumov.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");


//}}}

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://devoroumov.tiddlyspot.com/controlpanel]] (your control panel username is //devoroumov//).
<<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.
my name is
hop