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

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

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

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

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

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

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

.wizard {background:[[ColorPalette::PrimaryPale]]; border:1px solid [[ColorPalette::PrimaryMid]];}
.wizard h1 {color:[[ColorPalette::PrimaryDark]]; border:none;}
.wizard h2 {color:[[ColorPalette::Foreground]]; border:none;}
.wizardStep {background:[[ColorPalette::Background]]; color:[[ColorPalette::Foreground]];
	border:1px solid [[ColorPalette::PrimaryMid]];}
.wizardStep.wizardStepDone {background:[[ColorPalette::TertiaryLight]];}
.wizardFooter {background:[[ColorPalette::PrimaryPale]];}
.wizardFooter .status {background:[[ColorPalette::PrimaryDark]]; color:[[ColorPalette::Background]];}
.wizard .button {color:[[ColorPalette::Foreground]]; background:[[ColorPalette::SecondaryLight]]; border: 1px solid;
	border-color:[[ColorPalette::SecondaryPale]] [[ColorPalette::SecondaryDark]] [[ColorPalette::SecondaryDark]] [[ColorPalette::SecondaryPale]];}
.wizard .button:hover {color:[[ColorPalette::Foreground]]; background:[[ColorPalette::Background]];}
.wizard .button:active {color:[[ColorPalette::Background]]; background:[[ColorPalette::Foreground]]; border: 1px solid;
	border-color:[[ColorPalette::PrimaryDark]] [[ColorPalette::PrimaryPale]] [[ColorPalette::PrimaryPale]] [[ColorPalette::PrimaryDark]];}

.wizard .notChanged {background:transparent;}
.wizard .changedLocally {background:#80ff80;}
.wizard .changedServer {background:#8080ff;}
.wizard .changedBoth {background:#ff8080;}
.wizard .notFound {background:#ffff80;}
.wizard .putToServer {background:#ff80ff;}
.wizard .gotFromServer {background:#80ffff;}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

hr {height:1px;}

a {text-decoration:none;}

dt {font-weight:bold;}

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

.txtOptionInput {width:11em;}

#contentWrapper .chkOptionInput {border:0;}

.externalLink {text-decoration:underline;}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

----
Also see [[AdvancedOptions]]
<<importTiddlers>>
A filter is a tool for selecting some set of tiddlers from a collection of tiddlers.

As originally designed, they are to be used in [[recipes|recipe]] alongside [[bag]] listings to select //some// tiddlers from the bag. The filter syntax is used to select tiddlers by tag, modified time, arbitrary fields, title as well as to sort or limit on various qualities.

''Note:'' As of TiddlyWeb version 0.9.31 the filter syntax has changed in a non-backwards compatible fashion. This change was made before version 1, to avoid including multiple styles of filtering in the system. The reasons for the new style are answered in [[What are the reasons for the new style of filters?]] See also [[How do I upgrade to the new filter style?]]

A filter can show up paired with a bag in a recipe, or in any URL that produces a list of tiddlers. A filter looks like a URL query string. Here's an example that selects all tiddlers that are tagged both {{{published}}} and {{{blog}}} and have been modified since the start of 2009; sorts those tiddlers by created time, newest to oldest; and limits the results to the first 10:
{{{
    select=tag:published;select=tag:blog;select=modified:>2009;sort=-created;limit=10
}}}
//Note that in this example ';' is used to separate query parameters. This is equivalent to the often seen '&' but is better because it requires no HTML escaping when used in HTML documents.//

Filters are processed in order: the tiddler results of the first filter are processed by the second which has its results passed to the third. This means that selections are intersections or boolean {{{AND}}}. By default there is no way to do an {{{OR}}} in a single filter string. Either multiple queries to the same URL or tiddler collection must be made or the [[mselect]] plugin may be used.

The filter syntax has a straightforward core which may be extended. See [[How do I extend the filter syntax?]]

The built in syntax is divided into three filter types:
# [[select]]: pick some tiddlers out of a larger collection by an attribute and value
# [[sort]]: sort the tiddlers by an attribute
# [[limit]]: take a slice of the tiddlers, either a count from the start of the list, or from an index
In the case of select and sort, the attribute may be:
# an attribute on the tiddler object
# an extended field on the tiddler object
# a //virtual// attribute wherein a function may be defined to return some value from the tiddler or to canonicalize a value for sorting

In general a filter query string will consist of one or more select statements followed by zero or more sort and limit statements.

!Examples
;Select all the tiddlers from bag monkey that have the field {{{tail}}} set to true
:{{{/bags/monkey/tiddlers?select=tail:true}}}
;Select all the tiddlers from bag monkey that have the field {{{tail}}} //not// set to true
:{{{/bags/monkey/tiddlers?select=tail:!true}}}

!See also
* [[What are the reasons for the new style of filters?]]
* [[How do I extend the filter syntax?]]
* [[How do I use only some tiddlers from a bag when making a recipe?]]
* [[How do I request only some tiddlers from a URL?]]
[[TiddlyWeb]] is an [[open source|Open Source]] web-based storage system with a robust [[HTTP API]], making each record a directly addressable [[unit of micro-content|tiddler]]. It operates, amongst other things, as a [[server side]] for TiddlyWiki.

Data collections can be accessed via [[recipes|recipe]] which combine [[bags|bag]], which in turn are collections of [[tiddlers|tiddler]] ([[diagram|Tidders, Bags and Recipes]]).

There's a [[video of a lightning talk|http://europython09.blip.tv/file/2351416]] from EuroPython explaining the basic proposition in five minutes.

If you are eager to try things out, see [[TiddlyWeb for the Impatient]].

This wiki is evolving to become a site for [[Reference Documentation]]. Additional wikis will be put together for how to documentation, tutorials, and the like.

<<tiddler [[Navigation]]>>

TiddlyWeb has a [[philosophy|Philosophy]] and opinions about how it does stuff. 
!Step-by-Step Instructions
Yang Li has posted detailed [[step-by-step instructions for setting up TiddlyWeb in a Windows  client-server environment|http://groups.google.com/group/tiddlyweb/browse_thread/thread/97133daa3303c98]].
!Using Cygwin
[[Cygwin|http://www.cygwin.com]] can be used to install Python, then [[easy_install]] is [[available|http://pypi.python.org/pypi/setuptools#cygwin-mac-os-x-linux-other]] to install the [[tiddlyweb|TiddlyWeb]] and/or [[tiddlywebwiki|TiddlyWebWiki]] packages.

''Do not use easy_install if you intend to use tiddywebplugins. Use [[pip]] instead.''

!Portable Setup
These instructions are for installing [[TiddlyWebWiki]].
* create a directory {{{C:\Portable\TiddlyWeb}}}
* install [[Portable Python|http://portablepython.com]] (version 2.5 recommended) to {{{C:\Portable\TiddlyWeb\App\Python\}}}
* download {{{install.bat}}} and {{{launch.bat}}} from [[this repository|http://gist.github.com/235101]] (via the //raw// link) to {{{C:\Portable\TiddlyWeb}}}
* execute {{{install.bat}}}, which is a one-time operation for the basic setup and [[instance]]
* optionally [[configure|tiddlywebconfig.py]] instance as desired
* execute {{{launch.bat}}}, which will open TiddlyWeb at http://localhost:8080 in the browser
!Configuring Proxy
If required (e.g. for //easy_install// to work from behind a corporate firewall), a proxy can be set up with the following command:
{{{
set http_proxy="http://proxy.mycorp.com:8080"
}}}
A policy is the TiddlyWeb method for controlling access to resources on the system. That is: it is the mechanism by which [[authorization]] is managed.

There are policies associated with each [[bag]] and each [[recipe]].
Each policy has a list of [[constraint]]s and a list of arguments to the constraint.
It also has an {{{owner}}} key and value (string), representing the person who created the policy (but otherwise not yet used).

The policy constraints arguments are either user identification strings (such as a username or [[OpenID]]), or [[roles|role]] prepended by {{{R:}}}.

Policies are checked throughout the code, primarily in the web handlers. The current user and their roles (in the form of [[tiddlyweb.usersign]] are compared against the constraint being queried. If there is no match the system raises a permissions error which is usually returned to the user as an HTTP error.

If a policy requires a user, but the current user is {{{GUEST}}}, TiddlyWeb will attempt to call the [[challenger]] system to get a user.

Policies are edited by editing the [[recipe]] or [[bag]] to which they are associated. See the [[API]] and [[twanager]].

!Processing Model
Policies are engaged in six different scenarios:
# Listing recipes: [[/recipes]].
# Listing bags: [[/bags]].
# Requesting an existing [[recipe]]: [[/recipes/{recipe_name}]].
# Requesting an existing [[bag]]: [[/bags/{bag_name}]].
# Requesting all or one of the tiddlers produced by a recipe: [[/recipes/{recipe_name}/tiddlers]].
# Requesting all or one of the tiddlers produced by a bag: [[/bags/{bag_name}/tiddlers]].

For a bag or recipe to be included in a list, the current user must pass the {{{read}}} constraint on the entity.

To view or edit an existing bag, the current user must pass the {{{manage}}} constraint.

To view an existing recipe, the current must pass the {{{read}}} constraint (this may change to be consistent with bags). To edit, the {{{manage}}} constraint is checked.

{{{delete}}}, {{{read}}}, {{{write}}} and {{{create}}} are used in the "obvious" fashion when addressing tiddlers in a bag.

When editing a tiddler via a recipe URL, the policy on the bag of its eventual destination is checked for {{{write}}}, {{{create}}} or {{{accept}}}. The policy on the recipe does not control edits of tiddlers.

When reading a tiddler via a recipe URL, the current user must have {{{read}}} on the recipe policy //and// {{{read}}} in the policy of the bag in which the tiddler is located. In fact the user must have {{{read}}} in the policies of all bags used in the recipes. This is because a recipe must be read to determine which bags are being used in the recipe, and then the bags must be read to find the "right" tiddler.

Conceptually, the policy on a recipe is specifically for controlling //reading// and //managing// the recipe itself, whereas the policy on a bag does the job of controlling management of the bag's policy and //reading// and //editing// (including deleting) of the tiddlers. For another perspective on this distinction see [[this google group message|http://groups.google.com/group/tiddlyweb/msg/e0b3709851565dbe]].

When creating a recipe or bag, the [[recipe_create_policy]] and [[bag_create_policy]] [[config]] items are checked, respectively.

A policy constraint can contain any combination of three different types of entries:

* A string representing a username or usersign. The term usersign is used because what indicates a user is entirely up to the [[challenger]] and [[credentials extractor]] system or systems being used.
* A string representing a [[role]]. A role is indicates by prepending the role name with {{{R:}}}. By convention roles are uppercased.
* A string representing one of these built in meanings:
** {{{GUEST}}}: The default unauthenticated user.
** {{{NONE}}}: No user, GUEST or authenticated may pass this constraint.
** {{{ANY}}}: Any authenticated (not GUEST) user.

[[Policy Examples]]
!! not using an installer

Many experienced Python developers are not fans of [[easy_install]] because it and {{{setuptools}}} do lots of unexpected things on the target system. If you don't like easy_install or [[pip]] you can get the latest tarball from http://tiddlyweb.peermore.com/dist (or http://pypi.python.org/pypi/tiddlyweb and http://pypi.python.org/pypi/tiddlywebwiki) and process setup.py in whatever way you deem reasonable.

!! install or run from source
TiddlyWeb can be run directly from a checkout of its code from the [[source repository]]:

{{{
    git clone git://github.com/tiddlyweb/tiddlyweb.git
    cd tiddlyweb
}}}

(or a clone of your own fork, if you work that way)

Read the {{{README}}} file you will find there to see the other modules you need to install.

!! install using pip
TiddlyWeb can be installed with [[pip]], which is a replacement for {{{easy_install}}}. One advantage of pip is that it works with [[virtualenv|http://pypi.python.org/pypi/virtualenv]] and with [[bundles|Installing from a Bundle]]. Since late 2009 {{{pip}}} is the preferred way to install TiddlyWeb and associated tools.

!! install on a shared server
[[Ben Gillies]] has written some information on [[installing and running TiddlyWeb on a shared server|http://bengillies.net/.a/#%5B%5BRunning%20on%20TiddlyWeb%2C%20Part%20One%5D%5D]].

Once you have TiddlyWeb installed you can carry on to [[Using TiddlyWeb]].
A bag is a container of uniquely named [[tiddler]]s. A bag can have rules for who can edit, delete or read the tiddlers in the bag, defined in a [[policy]].

A bag may also have a description field, containing text that may describe the purpose of the bag or the meaning of the tiddlers contained within.

The combination of a bag's name and a tiddler's name creates the unique distinguishing name for a tiddler on a server.

You can create and manage bags through the [[HTTP API]] or with [[twanager]].

See also [[What is a bag for?]].

!Attributes
; name
: The name of the bag.
; desc
: The description of the bag.
; policy
: The [[policy]] associated with the bag. The default policy allows anyone to do anything with the bag.

!Notes
The internal object representation of a bag in TiddlyWeb has a few different flavors. Each of these flavors are there to control some behaviors in different situations. The flavors are:
; default
: When a tiddler is added to a bag the {{{bag}}} attribute is set to the name of the bag to which the tiddler is being added. The uniqueness identifier for the tiddler is the name of the tiddler.
; tmpbag
: When a tiddler is added to a tmpbag, the bag attribute on the tiddler is not changed, 
; revbag
: When a bag is a revbag, it will be serialized differently from a default bag: revision information will be shown.
; searchbag
: When a bag is a searchbag, it will be serialized with different title information.

Knowing these differences is useful if you are writing extensions that use bags.
This guide explains how to set up [[TiddlyWeb]] using [[Apache|TiddlyWeb and Apache]] on a fresh [[CentOS|http://www.centos.org]] 5 install behind a corporate firewall.
!System Setup
(this assumes root access; commands might have to be wrapped in {{{su -c '...'}}})
* set up HTTP proxy: {{{export http_proxy="http://proxy.mycorp.com:8080"}}}
* [[install EPEL repository|http://fedoraproject.org/wiki/EPEL/FAQ#Using_EPEL]] using proxy:
** {{{wget http://download.fedora.redhat.com/pub/epel/5/i386/epel-release-5-3.noarch.rpm}}}
** {{{rpm -Uvh epel-release-5-3.noarch.rpm}}}
** {{{rm epel-release-5-3.noarch.rpm}}}
* install [[mod_wsgi|Using Mod WSGI]]: {{{yum install mod_wsgi}}}
* install and upgrade Python setup tools:
** {{{yum install python-setuptools}}}
** {{{easy_install -U setuptools pip}}}
!TiddlyWeb Setup
* install TiddlyWeb: {{{pip install -U tiddlywebwiki}}}
* create instances directory: {{{mkdir /srv/tiddlyweb && cd /srv/tiddlyweb}}}
* create instance "sandbox": {{{twinstance sandbox && cd sandbox}}}
* download TiddlyWeb's Apache module: {{{wget http://github.com/tiddlyweb/tiddlyweb/raw/master/apache.py}}}
* configure TiddlyWeb and Apache by editing {{{/srv/tiddlyweb/sandbox/tiddlywebconfig.py}}} and {{{/etc/httpd/conf/httpd.conf}}}, respectively (see //Sample Configuration// below)
* set correct permissions on Apache's logs directory: {{{chmod 755 /var/log/httpd}}}
* restart Apache: {{{httpd -k restart}}}
!Sample Configuration
(using instance "sandbox" at http://0.0.0.0:80/wiki/ under UNIX user //tiddlyweb//; if available, a hostname should be used instead of the IP)
* {{{/srv/tiddlyweb/sandbox/tiddlywebconfig.py}}}
{{{
config = {
    'secret': '<hash>',
    'server_host': {
        'scheme': 'http',
        'host': '0.0.0.0',
        'port': '80'
    },
    'server_prefix': '/wiki'
}
}}}
* {{{/etc/httpd/conf/httpd.conf}}}
{{{
<VirtualHost *:80>
    DocumentRoot /srv/tiddlyweb/sandbox/public
    ServerName 0.0.0.0
    RedirectMatch ^/$ /wiki/
    WSGIDaemonProcess sandbox_wiki user=tiddlyweb processes=2 threads=15
    WSGIProcessGroup sandbox_wiki
    WSGIScriptAlias /wiki /srv/tiddlyweb/sandbox/apache.py
</VirtualHost>
}}}
TiddlyWeb is packaged as a collection of [[Python]] packages. As such there are a variety of ways to install it. The most straightforward way to install, if you are connected to the internet, is described here. There are other [[Installation Options]] which may be better suited to your situation. Also have a look at [[TiddlyWeb for the Impatient]].

!! Requirements

# You need an operating system that has [[Python]] installed. TiddlyWeb has been tested on various versions of Linux, Mac OS X, Windows, Solaris (and various other Unix-like systems) with Python 2.4, 2.5 and 2.6. Read [[download information for Python|http://www.python.org/download/]] if your system doesn't have Python installed.
# You need the Python tool called [[pip]]. Your system may already have it installed. If it does not, follow the links at [[pip]] for more information.
# Once you have {{{pip}}}, open a comand prompt and:
{{{
    $ sudo pip install -U tiddlywebwiki
}}}
If your system does not use {{{sudo}}}, leave that out. The above will install the tiddlyweb package into Python's default location for libraries. It will also install a command line scripts called [[twanager]] and [[twinstance]].

If this installation process will not work for you, see the platform instructions below and [[Installation Options]].

Once TiddlyWeb is installed you can start [[using it|Using TiddlyWeb]].

!Instructions by Platform
* [[Installing on Ubuntu]]
* [[Installing on OS X]]
* [[Installing on Windows]]
* [[Installing on iPhone]]
!Instructions by Scenario
* [[Using CGI]] (without root access)
* [[Installing on CentOS Behind a Corporate Firewall]]
* [[Installing from a Bundle]]
TiddlyWeb, the name, was chosen by ChrisDent. Originally the concept that became TiddlyWeb was named "möass": Mother of All Server Sides. That didn't seem like it fit in the Tiddly* universe all that well. Because TiddlyWeb tries to be very good about how it follows web standards and practices, TiddlyWeb seemed like a good name.

http://tiddlyweb.com/ provides a starting page for all things TiddlyWeb.

In [[TiddlyWeb]], an instance is a single collection of data, the [[store]], with a (potentially empty) configuration. There can be any number of instances on any machine.

In most cases an instance is manifest in the filesystem as a directory containing the [[store]], [[tiddlywebconfig.py]] and any [[plugins]] used in the instance.

In order to create a new instance, make or change to the directory where you plan to have the instance and do any of the following:
* Run {{{twanager server}}} to start the server on the default port of 8080 or configure your [[server|Mount a Server]] and run it.
* Run any [[twanager]] command which uses the store (e.g. {{{adduser}}}, {{{bag}}}).
* Edit [[tiddlywebconfig.py]] to set some settings, and do either of the above.

Note that the above only creates a very basic TiddlyWeb instance.
The //twinstance// command can be used to spawn a preconfigured [[TiddlyWebWiki]] instance:
{{{
$ twinstance myInstanceDirectory
}}}
This site is hosted on TiddlyWeb (of course) [[mounted|mount]] on [[mod_wsgi|Using Mod WSGI]] under Apache 2. It uses the [[cachinghoster]], [[caching-store]], [[atomplugin|atom]], [[mselect]], [[pathinfohack]], [[formeditor]], [[tiddlyeditor]], [[sqlstore]] and [[tiddlywebplugins.status]] server-side [[plugins|plugin]] and [[ServerSideSavingPlugin]], [[TiddlyWebAdaptor]] and [[CommentsPlugin]] on the client side. This is an example of a TiddlyWeb as a [[server side]] for TiddlyWiki.

A more detailed [[How is this server put together?]] document will be made available.

Many thanks to [[FND]] for cooking up the improved style for this TiddlyWiki.

Work on TiddlyWeb development is supported by:
* [[Peermore Limited|http://peermore.com/]]
* [[Osmosoft|http://www.osmosoft.com/]]
* [[Unamesa|http://www.unamesa.org/]]
It may be useful to think of TiddlyWeb as a collection of pieces of Lego. Like Lego, there are types of pieces, some skinny, some fat, some curved, some straight, with different numbers of holes. And they all come in different colors. Similarly, in TiddlyWeb there are a small number of types of things, each of which comes in somewhat different forms. For most of these types it is possible for the administrator of a TiddlyWeb [[instance]] to add additional forms through configuration or [[plugins|plugin]].

In TiddlyWeb the types are:
* [[store]]
* [[serializer]]
* [[handler]]
* [[challenger]]
* [[extractor|credentials extractor]]
* [[validator]]
* [[filter]]
* [[middleware]]
* [[renderer]]
* [[twanager]] commands

Each of these parts can be extended to modify TiddlyWeb in ways simple or complicated. The individual pieces have simple behaviors, simple inputs and simple (as in easily described) outputs, but they can combine for complex behaviors. Much like a big box of black and white 2x6 Lego blocks, in the right hands, becomes an artistic masterpiece.
When used as a TiddlyWiki [[server side]], TiddlyWeb lets you:
# Store your [[tiddlers|tiddler]] and similar chunks of content on the web.
# Display and edit your tiddlers in more than one TiddlyWiki.
# Have more than one person working on the same TiddlyWiki at the same time.
# Create dynamic [[TiddlyWiki]]s based on rules you define.
# Create new and interesting server-based TiddlyWiki applications.

TiddlyWeb can also be used as simple framework for storing and presenting tiddler-like chunks of content.

TiddlyWeb is made up of a few things:
# A web server. See [[Mount a Server]].
# A data [[store]].
# A configuration. See [[tiddlywebconfig.py]].
# A command line tool. See [[twanager]].

Together these things are your [[lego|Lego Pieces Model]] to make lots of great stuff.

!! Or to Put it another Way

TiddlyWeb is a collection of [[Python]] code providing several services:
# It acts as a [[server side]] for TiddlyWiki, providing (optionally) [[authenticated|authentication]] storage of any content, including TiddlyWiki content and dynamic generation of custom wikis.
# It presents a robust HTTP API for manipulating resources in the store and an extensible system for presenting those resources in multiple [[representations|representation]].
# It provides a [[library of routines|Python API]] and a framework for creating web-based applications based on TiddlyWeb and (optionally) TiddlyWiki.
# It can act as a database for any content you wish to store on the web.
# It is extensible, pluggable, customizable on many dimensions.
# It is a reference [[HTTP API]] for other servers that wish to interact efficiently with the TiddlyWiki Adaptor mechanism.
In TiddlyWeb, [[authentication]] and [[authorization]] is modeled around [[users|user]], [[bags|bag]], [[policies|policy]], [[challengers|challenger]] and [[credentials extractors|credentials extractor]].

At this point, managing users is done with server side code. Users, passwords, challengers and credentials extractors and configuration are managed either from the command line using [[twanager]] or in [[plugin]] code.

There is no [[HTTP API]] exposure of the [[User]] datastore entities in the core code. Two experimental plugins are in progress. One adds {{{/user}}} style ~URLs, another manipulates the bag structure to present a single bag as containing all the users. The code for these can be found at:
* http://github.com/tiddlyweb/tiddlyweb-plugins/tree/master/userbag
* http://github.com/tiddlyweb/tiddlyweb-plugins/tree/master/users

Here are a list of facts about [[users|user]] and [[Users|User]] (follow the links to see the difference):
* If a request is [[authenticated|authentication]] using [[OpenID]] or some other external service, there is no requirement for a [[User]], the OpenID will be placed in [[tiddlyweb.usersign]].
* If you want to create a user in the store from the command line, setting a password, roles, or both, you can use the [[twanager]] command [[adduser]]. See also [[addrole]] and [[userpass]].
* In TiddlyWeb [[plugin]] code it is possible to create a user by instantiating a new [[User]] object. See [[How do I create or update a User object in code?]]
* [[Users|User]] can have [[roles|role]]. If you want a user to have a role you can set it when creating a user using [[adduser]] or use [[addrole]] on an existing user. If you are using [[OpenID]], and want to use roles, you can create a user in the store with an id corresponding to the OpenID and an empty password.
* Access to content is controlled by [[policies|policy]]: there are policies on both [[bags|bag]] and [[recipes|recipe]].
* If a policy does not allow an action, and the requested action involves a {{{GET}}} request, the request will be redirected to the [[challenger]] system. If the requested action is a write operation they will get an HTTP 403 (the current user can't do that) or 401 (we have no user and need one). This is to allow an interactive user to have a reasonable experience (when loading a page they need to be authenticated for, they will get the chance to authenticate).
* Once a request successfully passes through a challenger it is redirected back to the original page requested. When the page is requested again (in fact when any request is made) the [[credentials extractor]] system looks at the incoming request. This determines the current user and then carries on with the request.
* When we get back to the previous point where the policy constraint was not met, we now have a user and assuming there is a match, the code carries on.

TiddlyWeb tries to make it so challenges happen before a user enters into the TiddlyWiki space. That is, if we know there is going to be a need for a user, they get challenged outside of TiddlyWiki. However this is not at all required. A TiddlyWiki plugin could use XHR to make posts to the existing challenger forms and deal with the results (i.e. accept the cookie or other magic the challenger provides). Figuring out how to use the forms is as simple as looking at them.

Challengers are by design triggered only when unauthorized content is accessed but can be explicitly triggered by going to the {{{/challenge}}} URL on your installation.

There already exists some sort of code that does tiddlywiki side use of the cookie_form:

> http://svn.tiddlywiki.org/Trunk/association/serversides/tiddlyweb/client/plugins/TiddlyWebLoginPlugin.js

This is of unknown quality. It's been a long time since it was tested, and is based on some ccTiddly code so has a lot of references that may not make sense in the TiddlyWeb context.

TiddlyWeb goes to great lengths to make very few assumptions about who or what is talking to it. If you want to auth with javascript, curl, python, a browser, carrier pigeons, as long as you are sending HTTP to the server, you've got a chance of getting it right.
TiddlyWeb has straightforward support for including additional functionality through [[plugins]]. This page lists some available plugins. Some of these are formally plugins (in that they use the {{{init(config)}}} signature), while others provide plugin-like functionality through different means.

Plugins which have reached some level of maturity can be found [[by searching at PyPI|http://pypi.python.org/pypi?%3Aaction=search&term=tiddlywebplugins&submit=search]]. Some plugins are described here:

<<list filter [tag[plugin]]>>

Mature plugins may be installed from PyPI directly using [[pip]]. {{{pip}}} is preferred over other choices as it handles some of the special packaging tricks used in plugins more effectively.

Plugins that are as yet not packaged for release from PyPI are installed as follows:
* Get the *.py file (or files) from the source location of the plugin.
* Put those files in the [[instance]] directory (alongside your [[tiddlywebconfig.py]]).

One a plugin is installed it must be "turned on" for your [[instance]]:

* Add the name of the plugin (either the full name of the installed package (e.g. tiddlywebplugins.status) or the name of the file minus .py) to one or both of [[system_plugins]] or [[twanager_plugins]] in [[tiddlywebconfig.py]] depending on the information in the plugin itself.
* Add any additional configuration suggested by the plugin documentation.
* Restart your server to get the configuration and plugin reread.

Even more plugins can be found at http://github.com/tiddlyweb/tiddlyweb-plugins/tree/master

Looking at the plugin code is a great way to understand how the guts of TiddlyWeb work and the possibilities for things you can do with it.
The TiddlyWeb HTTP API provides access to resources hosted by the TiddlyWeb [[store]]. The API strives to adhere to the principles of [[REST]] where possible and reasonable; using reasonable caching headers, only using the default HTTP verbs, providing multiple representations through pseudo-[[content negotiation]], [...]

The HTTP API works through a collection of default ~URLs defined by a [[urls.map]]. The map can be modified or extended with [[plugins]]. The HTTP API is found at [[server_prefix]], which by default is the empty string, therefore for {{{root}}} below the full URL would be {{{/}}}. If server_prefix is {{{/wiki}}} then {{{bags}}} would be {{{/wiki/bags}}}.

''Note that in TiddlyWeb there are no resources that end with "/"''.

The HTTP API provides access to resources, these are listed below, follow the links for descriptions, ~URLs, available representations and other information:

* [[root|/]]
* [[bags|/bags]]
* [[recipes|/recipes]]
* [[bag|/bags/{bag_name}]]
* [[recipe|/recipes/{recipe_name}]]
* [[tiddlers in bag|/bags/{bag_name}/tiddlers]]
* [[tiddlers in recipe|/recipes/{recipe_name}/tiddlers]]
* [[tiddler in bag|/bags/{bag_name}/tiddlers/{tiddler_title}]]
* [[tiddler in recipe|/recipes/{recipe_name}/tiddlers/{tiddler_title}]]
* [[tiddler revisions|/bags/{bag_name}/tiddlers/{tiddler_title}/revisions]]
* [[tiddler revision|/bags/{bag_name}/tiddlers/{tiddler_title}/revisions/{revision}]]
* [[search|/search]]

* [[HTTP API by method]]
* [[HTTP API by representation]]

There are also ~URLs associated with the [[challenger]] system, but these are not directly a part of the HTTP API (nor are they standard).

Each resource supports some default representations, plus what ever representations are provided by additional [[serializers|serializer]] that are installed via [[plugins]].
<div id="adsense" style="display:none">
<!-- <div id="twitter_div">
<h2 style="display: none;" >Twitter Updates</h2>
<ul id="twitter_update_list"></ul>
<a href="http://twitter.com/tiddlyweb" id="twitter-link" style="display:block;text-align:right;">follow on Twitter</a>
</div>
<script type="text/javascript" src="http://twitter.com/javascripts/blogger.js"></script>
<script type="text/javascript" src="http://twitter.com/statuses/user_timeline/tiddlyweb.json?callback=twitterCallback2&count=1"></script
--!>
</div>
''Do not use easy_install if you intend to use tiddywebplugins. Use [[pip]] instead.''

If you are attempting to use {{{easy_install}}} and things are not working out, you may wish to use [[pip]] instead.

!! Required version of setuptools not available

Sometimes you may see an error like this:

> The required version of setuptools (>=0.6c8) is not available, and can't be installed while this script is running. Please install a more recent version first, using {{{easy_install -U setuptools}}}.

But then, when you do what it says, the second time around you get the same error. If this happens check to see if you have two copies of [[easy_install]] on your system. You may have one in {{{/usr/bin}}} and another in {{{/usr/local/bin}}}. You need to use whichever is newer (most likely the one in {{{/usr/local/bin/}}}):

{{{
    sudo /usr/local/bin/easy_install -U tiddlyweb
}}}

!! Setuptools installed but easy_install not found

If you have installed setuptools to get [[easy_install]] but your system still complains about it not being found there are two likely scenarios:

* It was installed to somewhere like {{{/usr/local/bin}}} and that directory is not in your {{{PATH}}}.
* It was installed to somewhere weird like {{{/Library/Python/2.5/site-packages/bin}}}. When you install setuptools it will indicate in the output where it has installed [[easy_install]].

!! Problems Installing Prerequisites

The most significant benefit of using [[easy_install]] for installing TiddlyWeb is that it will attempt to automatically install the Python parts of the [[TiddlyWeb Requirements]]. Sometimes, however, this process will fail and [[easy_install]] will not report these problems with much clarity. If your TiddlyWeb [[instance]] fails to start because of a missing dependency, you can try to use easy_install to install just that one package. Any failure will be a bit easier to extract from the output.

If you are unable to resolve that failure, try [[Getting Help]]

!! Unable to Get Source Files

Sometimes easy_install doesn't do the job, because of network issues either local to the running easy_install or at the source of the packages being installed (some packages are hosted on http://pypi.python.org/ some are hosted on their own sites). So sometimes when trying easy_install it will hang while trying to fetch something. The way to resolve this is to manually download the respective dependency's tarball and install it (which is what easy_install would do anyway), but using a tarball located elsewhere. Here's an example, getting the resolver package:
* google for "python resolver tar" - which led to a reliable source, the pypi repo itself
* grab it {{{http://pypi.python.org/packages/source/r/resolver/resolver-0.2.1.tar.gz#md5=3a74a03ac19ec05f1f33d4fe34dd1d3f}}}
* extract it {{{tar zxvf resolver-0.2.1.tar.gz#md5\=3a74a03ac19ec05f1f33d4fe34dd1d3f}}}
* install it {{{cd resolver-0.2.1 ; python setup.py install}}}
Then can go back and run {{{easy_install -u tiddlyweb}}} again and it will proceed to the next step. 
> //These instructions via [[Mahemoff]]//.
In [[TiddlyWeb]], a serializer is a class that implements the [[SerializationInterface]] for the [[serialization]] of [[tiddler]] data.
Serialization formats are accessible as extensions to the respective URI.

By default, TiddlyWeb provides the following formats:
* {{{txt}}}: plain text
* {{{json}}}: [[JSON]]
* {{{html}}}: [[HTML]]
* {{{wiki}}}: [[TiddlyWiki]]
Additional serializers can be added by using [[plugins]] and adjusting [[tiddlywebconfig.py]].

The job of a serializer is twofold:
# Take an object representing a TiddlyWeb resource and turn it into a string of some form (e.g. [[JSON]]).
# Take a string of some form and use that string to //fill in// an object representing a TiddlyWeb resource.

In web requests a serializer is used to turn an object or collection of objects to a string when there is a {{{GET}}} request and a string to an object when there is a {{{PUT}}} request.

In {{{text}}} [[store]] that comes with TiddlyWeb, the {{{text}}} serializer is used when reading and writing some entities to from and to disk.

''A serializer is never called directly by TiddlyWeb or plugin code.'' Instead a serializer is produced by a factory class called {{{Serializer}}} in [[tiddlyweb/serializer.py|http://github.com/tiddlyweb/tiddlyweb/raw/master/tiddlyweb/serializer.py]].

See also:
* [[How do I use a serializer from plugin code?]]
* [[How do I write a custom serializer?]]

!Resource
The starting point of the [[HTTP API]].

!Representations
; {{{text/html}}}
: By default root returns a very simple HTML page linking to [[recipes|/recipes]] and [[bags|/bags]]. It does not do [[content negotiation]].

!Methods
!!{{{GET}}}
Get the resource, as HTML.

!Notes
The resource is commonly overridden by [[plugins]].

!Example
There is no example for this resource as it is overridden on this server by the [[cachinghoster]] [[plugin]].
!Resource
A list of [[tiddlers|tiddler]] contained by the named [[bag]].  The [[current user]] must pass the read [[constraint]] to see the tiddlers.

!Representations
; {{{text/plain}}}
: A linefeed separated list of tiddlers.
; {{{text/html}}}
: An HTML presentation of the description of the bag and a link to its list of tiddlers.
; {{{application/json}}}
: [[JSON]] representation of the tiddlers in the bag. See [[JSON tiddler]]. By default the included tiddlers are skinny. You [[can make them fat|How can I GET many tiddlers at once?]].
; {{{text/x-tiddlywiki}}}
: A TiddlyWiki representation of the tiddlers contained in this bag. [[tiddlywebwiki]] is required.

!Methods
!! {{{GET}}}
Get the list of tiddlers.

!Notes
These tiddlers may be [[filtered|filter]].

!Example
http://tiddlyweb.peermore.com/wiki/bags/docs/tiddlers
This server is (as far as the authors know) one of the more complicated TiddlyWeb (and TiddlyWebWiki) servers extant. While it's primary purpose is to be a storehouse for [[TiddlyWeb Documentation]], it is also a testbed for [[plugins]] and techniques for achieving a satisfying TiddlyWeb experience.

This content is generated from one of several TiddlyWeb [[instances|instance]] [[mounted|mount a server]] via [[mod_wsgi]] on a Xen virtual host. Mod WSGI daemon mode is used so that the TiddlyWeb is run under its own independent user.

Content is stored in SQLite, using the [[sqlstore]]. Performance is enhanced using the [[cachinghoster]] and [[caching-store]] plugins. These perform two very different but complementary function:

* caching-store, where possible, caches the TiddlyWeb entities which are persisted to the [[store]] in [[memcached]]. After a first request for an entity for the store, as long as the entity does not change, subsequent requests come from memcached. Under certain conditions this can save time as the time to get data from memcached can be faster than getting it from the persistent store. (//N.B: Under fairly light use conditions (like this server) the difference in time is negligible. In fact sometimes going to memcached can be ''slower''. We use it here for the sake of testing.//)
* cachinghoster caches the HTML file that is the wiki that is generated from a specific [[recipe]] and presents that wiki at the base url of the TiddlyWeb server. It performs a variety of heuristics to determine if it should:
** Tell the user-agent to continue using the copy it has in cache.
** Send the user-agent the static copy it has stored in its disk cache.
** Create the wiki anew by going to the store to get the required tiddlers (rewriting the cache in the process).

Because of weirdness with the way Apache handles '/' in the PATH_INFO part of urls, the [[pathinfohack]] plugin is used to make sure that [[tiddlers|tiddler]] with '/' in their titles can be loaded and saved.

The [[atom]] plugin provides Atom syndication feeds of any collection of tiddlers, including just one tiddler.

In addition to the editing (editing is available to [[authorized|authorization]] users) capability provided by the wiki [[serialization]], editing is also provided by the [[formeditor]] and [[tiddlyeditor]] plugins. These are accessible from the HTML representation of a single tiddler. Formeditor presents a simple {{{<textarea>}}} style form that allows the text of the tiddler to be edited. Tidddyeditor generates a TiddlyWiki containing the current tiddler plus those TiddlyWiki plugins required to do editing.

The [[hwiki]] plugin is used to provide a non-javascript representation of this wiki to provide enhanced accessibility and an entry point for search engines.

Within the generated TiddlyWiki, the MainMenu, PageTemplate, ViewTemplate and StyleSheet have all been updated to give a preferred look and feel. The TiddlyWiki plugins include with TiddlyWebWiki provide the required editing and saving functionality. The CommentsPlugin provides support for comments. [[twLink]] and [[FancyMissingPlugin]] are quick hacks to add a serverlink to the command bar and order the missing tiddlers list by number of references, respectively.
@@
''N.B.:'' This has been superseded by the [[devstore]].
@@

StorageInterface intended to ease client-side plugin development
* no revisions
* uses {{{.tid}}} files for non-JavaScript content
* supports JavaScript ({{{.js}}}) files 
!Setup Instructions
''N.B.:''
There is a [[script|http://svn.tiddlywiki.org/Trunk/contributors/FND/TiddlyWeb/plugins/devinstance.sh]] which automates the process described below.
It is called with an argument specifying the directory in which the new instance should be created (e.g. {{{./devinstance.sh /tmp/TiddlyWeb}}} creates {{{/tmp/TiddlyWeb/dev}}}).

* change to desired root directory
{{{
$ cd ~/tiddlyweb/
}}}
* download dev store plugin
{{{
$ wget http://svn.tiddlywiki.org/Trunk/contributors/FND/TiddlyWeb/plugins/devtext.py
}}}
* create TiddlyWeb configuration file
{{{
$ cat > tiddlywebconfig.py
config = {
	"server_store": ["devtext", { "store_root": "store" }]
}
<CTRL+D>
}}}
* create instance
{{{
$ twanager instance dev
$ cd dev/
}}}
* set up instance to use dev store plugin
{{{
$ mv ../devtext.py ./
$ mv ../tiddlywebconfig.py ./
}}}
''N.B.:'' Ideally, {{{tiddlywebconfig.py}}} should be merged with the existing configuration file.
* create plugins bag
{{{
$ twanager bag plugins
<CTRL+D>
}}}
* create plugin file
{{{
$ cat > store/plugins/helloworld.js
alert("Hello world!");
<CTRL+D>
}}}
* create content bag
{{{
$ twanager bag content
<CTRL+D>
}}}
* create content tiddler
{{{
$ twanager tiddler lipsum content
modifier: test user
tags: test tmp

lorem ipsum dolor sit amet
<CTRL+D>
}}}
* create recipe
{{{
$ twanager recipe test
desc:
policy: { "read": [], "create": [], "manage": [], "write": [], "owner": null, "delete": [] }

/bags/system/tiddlers
/bags/plugins/tiddlers
/bags/content/tiddlers
<CTRL+D>
}}}
* start server
{{{
$ twanager server
}}}
* visit http://0.0.0.0:8080/recipes/test/tiddlers.wiki

''N.B.:'' Instead of creating dedicated files within the respective bags, symlinks could be used to make a TiddlyWeb instance use existing directories (e.g. from a local Subversion checkout) as bags.
!Resource
A single [[bag]] on the system for which the [[current user]] passes the manage [[constraint]].

!Representations
; {{{text/html}}}
: An HTML presentation of the description of the bag and a link to its list of tiddlers.
; {{{application/json}}}
: [[JSON]] representation of the bag. See [[JSON bag]].

!Methods
!! {{{GET}}}
Get the bag.
!! {{{PUT}}}
Create or edit a named bag. See [[JSON bag]] and [[How do I create or update a bag over HTTP?]]
!! {{{DELETE}}}
Irrevocably remove the bag and its [[tiddler]] contents.

!Notes

!Example
http://tiddlyweb.peermore.com/wiki/bags/common
As TiddlyWeb has developed, it has become increasingly difficult to give a concise description of what TiddlyWeb is and does and can do for you. It is far easier to list what it //has// rather than what it //does//. Part of the reason for this is that TiddlyWeb is [[lego|Lego Pieces Model]], a toolkit for getting stuff done. When you buy a screwdriver it doesn't say anything about what you're going to connect, just that you can. So here, in vaguely chronological order of development, is a list of TiddlyWeb features:

* [[HTTP API]] for manipulating [[tiddlers|tiddler]], [[bags|bag]] and [[recipes|recipe]].
* [[filter]] tiddlers with an pluggable/extensible syntax.
* Pluggable/extensible system for serializing and deserializing those entities to and from various formats using [[serializers|serializer]]. Associate the HTTP API with the serialization system via content negotiation.
* Pluggable/extensible system for [[storing|store]] entities to persistent storage.
* [[Mount|mount]] TiddlyWeb using a built in server or any WSGI capable web server.
* Pluggable/extensible [[WSGI]] middleware stack for [[server_request_filters]] and [[server_response_filters]].
* Unicode on the inside, ~UTF-8 on the outside.
* Tiddlers may be stored with revisions and edit conflict detection.
* Constraint based [[authorization]] system using [[policies|policy]] on bags and recipes.
* Pluggable/extensible [[authentication]] system using [[challengers|challenger]] and [[credentials extractors|credentials extractor]].
* A simple architecture for [[plugins|plugin]] that supports all this pluggability and extensibility.
* Any kind of content (any MIME type) may be stored in a tiddler, not just wikitext.
* Input (i.e. [[PUT|method:put]]) [[validation/sanitation|validator]].
* Server side rendering of wikitext to HTML.
* Pluggable/extensible [[rendering|wikitext renderer]] of different wikitext syntaxes.
* Generating dynamic TiddlyWiki files with a [[recipe cascade]].
* Import an existing TiddlyWiki into the system from the [[command line|twanager]] or a [[POST|method:post]] to [[a bag|/bags/{bag_name}]].



See [[plugins]] for exampls for ways in which the pluggable/extensible things have been plugged and extended.
One way to use TiddlyWeb with [[Apache|TiddlyWeb and Apache]] is to [[mount]] it using the mod_python module. [[mod_wsgi|Using Mod WSGI]] is a better choice, but if you have to use mod_python you can set it up as follows:
# Install mod_python for your apache server if it is not already there. Instructions on how to do this are out of scope for TiddlyWeb. See http://www.modpython.org/ for more information
# If you don't have it, get and install the [[ModPythonGateway|http://www.aminus.net/wiki/ModPythonGateway]] according to the instructions on that page.
# Get [[apache.py]] and put it in your [[instance]] directory. That file includes information in the comments on how to modify your apache configuration and your [[tiddlywebconfig.py]].

!! Common Problems
* Make sure your apache is configured to support mod_python.
* Make sure any files paths you create or edit in the apache config are correct.
* If you are using the default text [[store]] make sure the {{{store}}} directory and all the files and directories within and [[tiddlyweb.log]] are writable by the user or group by which the web server is running. See [[Group Writable Text Store]].
* Make sure you have set [[server_prefix]] and [[server_host]] correctly in [[tiddlywebconfig.py]].
''Note'': The following only applies to the new filter syntax introduced in TiddlyWeb v0.9.31.

Filters can be extended in two ways:
* adding new filter types
* adding new attributes, or handling existing attributes differently

!Type
There are three default filter types: [[select]], [[sort]] and [[limit]]. The {{{FILTER_PARSERS}}} dictionary in the {{{tiddlyweb.filters}}} package associates a filter string parameter key (e.g. select, sort, limit) with a function that will parse the value of that parameter into a suitable filter function. (e.g. {{{select}}} is handled by {{{select_parse}}} which is part of the {{{tiddlyweb.filters.select}}} module).

A plugin may extend {{{FILTER_PARSERS}}} defining a suitable key and parsing function. The [[mselect]] plugin is an example that does this. Reviewing [[the code|http://github.com/tiddlyweb/tiddlyweb-plugins/blob/master/mselect/mselect.py]] shows how to override {{{FILTER_PARSERS}}}.

!Select Attributes
Extending attributes is similar. Attributes are used in both [[select]] and [[sort]] type filters. With select, the syntax is {{{some_attribute:some_value}}}. {{{some_attribute}}} is looked up in the {{{ATTRIBUTE_SELECTOR}}} dictionary in the {{{tiddlyweb.filters.select}}} module. The value is a function with a signature of {{{tiddler, attribute, value}}} that returns {{{True}}} or {{{False}}}. For the basic case this is simply a lookup of the attribute on the tiddler to see if the attribute is equal to value. If it is, that tiddler is selected.

The selector function may do whatever calculating is necessary to establish the attribute being queried. Here is a simple example which makes it possible to {{{select=year:2007}}} to get tiddlers which have been modified in the year 2007:
{{{
from tiddlyweb.filters.select import ATTRIBUTE_SELECTOR

def has_year(tiddler, attribute, value):
    return tiddler.modified.startswith(value)

ATTRIBUTE_SELECTOR['year'] = has_year
}}}

!Sort Attributes
Extending sorting is similar. When sorting, the {{{ATTRIBUTE_SORT_KEY}}} from the {{{tiddlyweb.filters.sort}}} module is consulted for a function which generates a value for the named attribute for the given tiddler. The default function turns the value of the attribute into a lowercase string. The attribute must correspond to either an attribute on the tiddler object or an extended field. //Do not be surprised if sometime in the future sorting also works with the virtual attributes used with select.//

In the following example the {{{count}}} extended field is turned into an integer so numeric sorting will be used.
{{{
from tiddlyweb.filters.sort import ATTRIBUTE_SORT_KEY

ATTRIBUTE_SORT_KEY['count'] = int
}}}
!Resource
A list of [[revisions|revision]] associated with the named  [[tiddler]] contained by the named [[bag]].  The [[current user]] must pass the read [[constraint]] to see the revisions.

!Representations
; {{{text/plain}}}
: A linefeed separated list of tiddlers.
; {{{text/html}}}
: An HTML list of the revisions.
; {{{application/json}}}
: [[JSON]] representation of the tiddler revisions. See [[JSON tiddler]]. By default the included tiddlers are skinny, with a {{{revision}}} field. You [[can make them fat|How can I GET many tiddlers at once?]].
; {{{text/x-tiddlywiki}}}
: A [[TiddlyWiki]] representation of the revisions of this tiddler. At the moment this is not very useful because TiddlyWiki can only display one tiddler with the same title, and at the moment the tiddler it chooses to display is the one that is oldest. This will eventually be fixed. [[tiddlywebwiki]] is required.

!Methods
!! {{{GET}}}
Get the list of tiddler revisions.
!! {{{POST}}}
Import a [[JSON]] list of a fat tiddlers, as part of the rename process.

!Notes

!Example
http://tiddlyweb.peermore.com/wiki/bags/docs/tiddlers/HTTP%20API/revisions
A recipe is an ordered list of [[bags|bag]] and [[filters|filter]] that generates a list of tiddlers.

They are used to create collections of [[tiddlers|tiddler]] with a set of date and content customized for a particular use case.

If processing a recipe finds more than one instance of a tiddler with the same name, the tiddler from the most recent [[bag]] is the one used. This process is called the [[recipe cascade]].

The exact storage or serialization format of a recipe is dependent on the [[store]] or [[serialization]] being used. Tools working with recipes that wish to be flexible should not rely on any format, but instead, where possible, work with recipe objects.

[[twanager]] provides a command line tool for creating recipes. As a special case, this tool uses the text serialization of a recipe as the input. That format looks like this:
{{{
    /bags/system/tiddlers?select=tag:systemConfig;sort=-modified
    /bags/common/tiddlers
}}}
That is: one line per bag/filter pair, with the optional filter represented as a URL query string. There is no upper limit on the number of bags that may be present in a recipe, but at some point it is likely to get slow.

As a special case, the bag name in a recipe may be {{{ {{ user }} }}}. When the recipe is processed this will be changed to the name of the [[current user]].

Recipes may be created and updated over the [[HTTP API]] at [[/recipes/{recipe_name}]].
For some plugins, it can be useful to automatically modify or extend the TiddlyWeb configuration. This can be achieved using an {{{init}}} function within the plugin module, which is passed the {{{config}}} variable.

For example, the following code automatically inserts the necesary configuration for the [[CSS serializer|http://svn.tiddlywiki.org/Trunk/contributors/FND/TiddlyWeb/plugins/css.py]]:
{{{
def init(config):
    # automatically extend configuration
    content_type = "text/css"
    config["extension_types"]["css"] = content_type
    config["serializers"][content_type] = [__name__, "text/css; charset=UTF-8"] })
}}}
(Note the use of {{{__name__}}} to refer to the plugin module itself.)
!Resource
A list of [[bags|bag]] on the system for which the [[current user]] passes the read [[constraint]].

!Representations
; {{{text/plain}}}
: A linefeed separated list of bag names.
; {{{text/html}}}
: An unordered list of bag names, linking to each [[/bag]] resource.
; {{{application/json}}}
: A [[JSON]] list of bag names.

!Methods
!! {{{GET}}}
Get the list of bags.

!Notes
If the [[current user]] can read no bags, this may be an empty list.

!Example
http://tiddlyweb.peermore.com/wiki/bags
The atom [[plugin]] provides an Atom format feed of any collection of [[tiddlers|tiddler]] including one tiddler. It does this by providing an additional [[serializer]].

The plugin is available from PyPI as [[tiddlywebplugins.atom|http://pypi.python.org/pypi/tiddlywebplugins.atom]].

This installation is using the atom plugin. [[Here is Atom URL|http://tiddlyweb.peermore.com/wiki/recipes/editor/tiddlers/atom.atom]] for this tiddler.

The plugin does //not// provide support for the Atom Publishing Protocol.
These are notes about things it would be nice to do to the code to make it easier for developers to either understand or work with. It's also a place to put things worth remembering related to development, but otherwise difficult to categorize. See also: [[Known Issues]] and [[Warts]].

!!!HTMLPresenter

Despite my ([[cdent]]) [[hopes|http://cdent.tumblr.com/post/47954625/wsgi-down-your-pipe]], HTMLPresenter is just kind of messy and awkward. Not necessarily in concept but in implementation. The code is hard to test and fiddly to extend. However since it is middleware, it should be easy to fix.

!!!tiddlyweb.web.handler.tiddler

Is too long and has methods that are too long.

!!!tiddlyweb.web.handler

The root page is too static and too lame.

!!!duplication in recipe and bag handling

A lot of the code for handling web requests for recipes and bags (themselves, not the tiddlers) is very similar.

!!!tiddlyweb.config

It //might// make sense for config to be a class, not a dict.

!!!wsgiref.validate

TiddlyWeb does not pass wsgiref.validate, because it prefers for applications to return an iterator that has a close() method on it. Generators have these, but lists do not. TiddlyWeb currently returns lists. Switching to generators as much as possible would be wise but may not be wise prior to 1.0
TiddlyWeb has two ~APIs. One, the [[HTTP API]], is used for remote access to TiddlyWeb resources. The other, the [[Python API]], is used when writing [[plugins]] and other server-side extensions TiddlyWeb.
A list of known problems present in TiddlyWeb. These may be bugs, misfeatures, missing features, or designed in behaviors that are unexpected. Bugs and features requests are being tracked on the [[TiddlyWiki Trac|http://trac.tiddlywiki.org/query?status=assigned&status=new&status=reopened&component=tiddlyweb&order=priority&col=id&col=summary&col=status&col=type&col=priority&col=milestone&col=component]].

* When using some web servers you may not use '/' in the name of a [[tiddler]]. It works with some. For those where it does not work the [[pathinfohack]] may help.
* When using '/' at the start of a tiddler title, links in the [[HTML representation|HTML tiddler]] may not work.
* Policy management is just too hard. There need to be tools to get people over the hump. At the moment, for novices understanding how to adjust a policy for  desired result is too complex, and then once understanding of what's desired is achieved, implementing it is additionally complex.

See also [[Warts]] and DevWishes.
[[Ben Gillies]] has written some information on [[installing and running TiddlyWeb on a shared server|http://bengillies.net/.a/recipes/sitecontent/tiddlers/CGI%20Install%20Update]] using CGI. This does not require root privileges.

While using CGI will work just fine, it is unlikely to be particularly performant as the entire TiddlyWeb codebase needs to be compiled for each request.

If you are on DreamHost or a similar hosting service the information at [[TiddlyWeb DreamHost Experiments|http://cdent.tumblr.com/post/266789592/tiddlyweb-dreamhost-experiments]] for an installation guide.
In code that is called via web request you can use code like the below to retrieve a [[tiddler]] from the [[store]]. The [[Server Request Model]] establishes a store reference named {{{tiddlyweb.store}}} in the [[environ]].
{{{
from tiddlyweb.model.tiddler import Tiddler

store = environ['tiddlyweb.store']

tiddler = Tiddler(title, bag)
tiddler.revision = revision # N.B.: revision 0 is HEAD
tiddler = store.get(tiddler)
}}}

When the code is not initiated by a web request, the caller must establish the store.
{{{
from tiddlyweb.store import Store
from tiddlyweb.config import config

store = Store(config['server_store'][0], config['server_store'][1], environ={})
}}}

!Retrieving Tiddlers From Bag or Recipe
{{{
from tiddlyweb.model.bag import Bag
from tiddlyweb.model.recipe import Recipe
from tiddlyweb.store import Store
from tiddlyweb import control
from tiddlyweb.config import config


# set up environment
env = { 'tiddlyweb.config': config }
store = Store(config['server_store'][0], env)

# retrieve tiddlers from bag
bag_name = 'foo'
bag = Bag(bag_name)
bag = store.get(bag)
tiddlers = control.get_tiddlers_from_bag(bag)

# retrieve tiddlers from recipe
recipe_name = 'bar'
recipe = Recipe(recipe_name)
recipe = store.get(recipe)
tiddlers = control.get_tiddlers_from_recipe(recipe, env)
}}}
!Resource
A list of [[tiddlers|tiddler]] contained by the named [[recipe]].  The [[current user]] must pass the read [[constraint]] on the recipe as well as the read constraint on each of the [[bags|bag]] in the recipe.

!Representations
; {{{text/plain}}}
: A linefeed separated list of tiddlers.
; {{{text/html}}}
: An HTML presentation of the description of the bag and a link to its list of tiddlers.
; {{{application/json}}}
: [[JSON]] list representation of the tiddlers in the recipe. See [[JSON tiddler]] for a description of each individual item in the list. By default the included tiddlers are skinny. You [[can make them fat|How can I GET many tiddlers at once?]].
;  {{{text/x-tiddlywiki}}}
: A TiddlyWiki representation of the tiddlers produced by this recipe. This is the canonical way to get TiddlyWeb to produce a TiddlyWiki. [[tiddlywebwiki]] is required.

!Methods
!! {{{GET}}}
Get the list of tiddlers.

!Notes
These tiddlers may be [[filtered|filter]].

!Example
http://tiddlyweb.peermore.com/wiki/recipes/docs/tiddlers
!Resource
A single of [[tiddler]] contained by the named [[bag]].  The [[current user]] must pass the read [[constraint]] on the bag to see the tiddler, edit to edit, create to create and delete to delete.

!Representations
; {{{text/plain}}}
: A text representation of the tiddler. See [[text tiddler]].
; {{{text/html}}}
: An HTML representation of the tiddler. See [[HTML tiddler]]. 
; {{{application/json}}}
: [[JSON]] representation of the tiddler. See [[JSON tiddler]].

!Methods
!! {{{GET}}}
Get the tiddler.
!! {{{PUT}}}
Create or edit the named tiddler use the [[text|text tiddler]] or [[JSON|JSON tiddler]] representations. The tiddler will be stored in the named bag.
!! {{{DELETE}}}
Delete the tiddler.

!Notes

!Example
http://tiddlyweb.peermore.com/wiki/bags/docs/tiddlers/HTTP%20API
!Resource
A list of revisions associated with the named  [[tiddler]] produced by the named [[recipe]].  The [[current user]] must pass the read [[constraint]] in all the bags in the recipe to see the revisions.

!Representations
; {{{text/plain}}}
: A linefeed separated list of tiddlers.
; {{{text/html}}}
: An HTML list of the revisions.
; {{{application/json}}}
: [[JSON]] representation of the tiddler revisions. See [[JSON tiddler]]. By default the included tiddlers are skinny, with a {{{revision}}} field. You [[can make them fat|How can I GET many tiddlers at once?]].
; {{{text/x-tiddlywiki}}}
: A [[TiddlyWiki]] representation of the revisions of this tiddler. At the moment this is not very useful because TiddlyWiki can only display one tiddler with the same title, and at the moment the tiddler it chooses to display is the one that is oldest. This will eventually be fixed.

!Methods
!! {{{GET}}}
Get the list of tiddler revisions.

!Notes
Making regular use of this URL is not recommended as it can be a bit unpredictable if the [[recipe]] changes. A more predictable URL is [[/bags/{bag_name}/tiddlers/{tiddler_title}/revisions]].

!Example
http://tiddlyweb.peermore.com/wiki/recipes/docs/tiddlers/HTTP%20API/revisions
Warts are things that would be done differently if we were to do it all over again.

* The StorageInterface {{{tiddler_written}}} method is too useful to be left hanging as something to be overridden by monkey patching. It would be better to be able to register a tiddler written function. (//Might be worth "fixing" this rather than calling it a wart.//)
* HTMLPresenter is crufty and awkward. A header and footer function registration system would be useful.
* Bag architecture and performance appears to be incorrect for how bags are actually being used. However the bag architecture is an explicit choice, an intentional constraint. The mismatch between expectations and design is a combination of bags being used in unexpected ways and poor documentation of bag concepts. There is probably middle ground that could be found where expectations and design and constraints are more aligned.
* if a tiddler title ends with ".//ext//" and //ext// is registered as a [[serialization]] extension, the individual tiddler can only be accessed in that particular representation (e.g. "index.html" as HTML)

See also DevWishes.
!Installation
* Quick Start: [[TiddlyWeb for the Impatient]].
* More Details: [[Installing TiddlyWeb]].

!API
<<tiddler [[API]]>>
If you are working with TiddlyWeb and have questions or suggestions you can post in the [[TiddlyWeb|http://groups.google.com/group/tiddlyweb]] google group or visit the [[#tiddlyweb|irc://irc.freenode.net/tiddlyweb]] IRC channel.

Please also search this wiki for help. If you can't find what you are looking for, or some information is incomplete, please leave a comment so we can improve the content.

If you discover a bug, please raise a ticket on [[Trac|http://trac.tiddlywiki.org]], making sure you select //tiddlyweb// as the component.
Once you have TiddlyWeb [[installed|Installing TiddlyWeb]], you can use it. To do so you must create an [[instance]], mount that instance in/on a server, and work with that content through the HTTP API, the command line or the Python API:
* [[Create an Instance]]
* [[Mount a Server]]
* [[HTTP API]]
* [[Using Twanager]]
* [[Python API]]
//twanager// is the command-line tool included with [[TiddlyWeb]].
With it you can manipulate the [[store]], adding content and users. Some of the powers of twanager are also available via the [[HTTP API]] and vice versa. Which you choose depends on your environment.

//twanager// is [[extensible|Customizing TiddlyWeb]].

When run without any arguments, it will default to {{{usage}}}, listing the available commands along with a brief description. What commands are listed depends on the [[twanager_plugins]] in use.

See also:
<<list filter [tag[twanager]]>>
A configuration item that can be in [[tiddlywebconfig.py]]. It serves two purposes:
* It is used to start up the included server, if used, on a chosen host and port.
* It is used to properly create fully qualified ~URLs even when operating behind a proxy or on a private IP.

It is a {{{dict}}} with the following structure:

{{{
    'server_host': {
        'scheme': 'http', # or https
        'host': 'tiddlyweb.peermore.com', # or an IP number
        'port': '80', # or some other port. You must put port even if 80 or 443. This needs to be a string.
    }
}}}

The defaults are {{{http}}}, {{{'0.0.0.0'}}} and {{{'8080'}}}. If you are planning to access your TiddlyWeb server from machines other than the one the server is running on, you will need to update the host portion so it refers to an externally addressable hostname of IP.
//This is about developing with the TiddlyWeb core. If you are interested in [[plugins]] start with [[Customizing TiddlyWeb]].//

<<tiddler [[Where is the TiddlyWeb code?]]>>

!Code Structure
TiddlyWeb code base has two important directories:
* [[tiddlyweb|http://github.com/tiddlyweb/tiddlyweb/tree/master/tiddlyweb]]: The actual TiddlyWeb code.
* [[test|http://github.com/tiddlyweb/tiddlyweb/tree/master/test]]: A suite of test files for the code.

The code tries to comply with [[pep8|http://www.python.org/dev/peps/pep-0008/]] and is run through [[pylint|http://www.logilab.org/857]] every now and again to see where things could do with some help. If you are submitting a patch we like four spaces //not// tabs. We likes patches.

Dependencies are listed in the {{{README}}} and {{{setup.py}}} files. The {{{Makefile}}} is used to automate the distribution process.

!Testing
* The TiddlyWeb tests are in a form that works well with [[py.test]], chosen because it is has low overhead. From the base directory run {{{py.test}}} to run all the tests. See [[the tiddler|py.test]] for more options.
* Running all the tests requires [[YAML]], [[wsgi_intercept]] and [[httplib2]].

From the base directory of the code, you can run all the tests with {{{py.test}}}, {{{py.test test}}} or {{{make test}}}. You can run one or more tests by naming them on the command line: {{{py.test test/test_filter.py test/test_bag.py}}}.

''You must run the tests from the base directory of the TiddlyWeb code.''

By default py.test will run every test it sees until it gets to the end, regardless of errors. If you would like it to quit on the first failure give {{{-x}}} as an argument. By default py.test also captures output from the tests. If you don't want this give {{{-s}}} as an argument.

When a test run by py.test fails to pass, figuring out what went wrong can be quite challenging. You'll need to dig through the scrollback of your terminal window to see what's going on, and then likely need to stick some prints in your tests and do some {{{-s}}} stuff on the command line. This may seem like a big hassle, but surprisingly, after some time it works well.

!External Resources
* [[TiddlyWeb Plugins|http://cdent.tumblr.com/post/55167654/tiddlyweb-plugins]]
* [[TiddlyWeb Plugin Tutorial|http://cdent.tumblr.com/post/76922695/1-tiddlyweb-tutorial]]
* [[Example TiddlyWeb Plugins|http://cdent.tumblr.com/post/75863777/example-tiddlyweb-plugins]]
!Resource
A list of [[recipes|recipe]] on the system for which the [[current user]] passes the read constraint.

!Representations
; {{{text/plain}}}
: A linefeed separated list of recipe names.
; {{{text/html}}}
: An unordered list of recipe names, linking to each [[recipe|HTTP recipe]] resource.
; {{{application/json}}}
: A [[JSON]] list of recipe names.

!Methods
!!{{{GET}}}
Get the list of recipes.

!Notes
If the [[current user]] can read no recipes, this may be an empty list.

!Example
http://tiddlyweb.peermore.com/wiki/recipes
When TiddlyWeb first starts up as a web server, either using the internal server or whatever server is using to [[mount]] the service, it goes through several steps to configure itself and establish how it will [[respond to requests|Server Request Model]].

* tiddlyweb.config and [[tiddlywebconfig.py]] are read to establish configuration settings.
** [[server_host]], [[server_prefix]]
** [[server_request_filters]], [[server_response_filters]]
** [[serializers|serializer]], [[server_store]]
** [[auth_systems]], [[extractors]]
** [[urls_map]]
** [[base_tiddlywiki]]
** [[system_plugins]]
* If there are any system plugins, they are imported and processed. These may modify other configuration settings.
* The stack of [[WSGI]] applications is configured (see [[WSGI Middleware Illustration]]).
* The bottom of that stack, [[selector]], is configured with the {{{urls_map}}}.
* The entire WSGI application is provided to the handling server and the server now waits for requests.

See [[Server Request Model]].
Something that implements the SerializationInterface is a [[serializer]]. The interface is described in a (mostly) abstract class in [[tiddlyweb/serializations/__init__.py|http://github.com/tiddlyweb/tiddlyweb/raw/master/tiddlyweb/serializations/__init__.py]].

The interface has the following methods. If you choose not to implement one, if calling code tries to use that method a {{{NoSerialzationError}}} will be raised. //This is okay,// some serializations will not need to serialize some entities.

{{{
    def recipe_as(self, recipe):
    def as_recipe(self, recipe, input_string):
    def bag_as(self, bag):
    def as_bag(self, bag, input_string):
    def tiddler_as(self, tiddler):
    def as_tiddler(self, tiddler, input_string):
    def list_tiddlers(self, bag):
    def list_recipes(self, recipes):
    def list_bags(self, bags):
}}}

For more information try {{{pydoc tiddlyweb.serializations}}} from your terminal.

See also:
* [[How do I write a custom serializer?]]
* Python 2.4, 2.5 or 2.6
* [[selector|http://lukearno.com/projects/selector/]]
* [[simplejson|http://undefined.org/python/#simplejson]]
* [[html5lib|http://code.google.com/p/html5lib/]]
* [[wsgiref|http://pypi.python.org/pypi/wsgiref]] for Python versions prior to 2.5
* [[Beautiful Soup|http://www.crummy.com/software/BeautifulSoup/]] (required for importing [[TiddlyWiki]] documents)
* [[WikklyText|http://wikklytext.com/wiki/InstallPythonPackage.html]] for server-side conversion of wiki markup to HTML

You may add a [[User]] to the TiddlyWeb [[datastore]] from the command line using the [[twanager]] [[adduser]] command. See [[User]] and [[Auth Model]] for information on why you may want to. To create the user {{{barney}}} with password {{{dinosaur}}} and no roles:
{{{
twanager adduser barney dinosaur
}}}

See also:
* [[How do I give a user a role?]]
* [[How do I create or update a User object in code?]]
If you have created a TiddlyWeb [[vertical]] there's a high chance you would like to be able to work on its development, deploy it to installations and allow others to install it themselves in as effective way as possible.

This tiddler explores the options available.

The most direct answer is that we don't yet know what the best practices are because:
* There are not yet enough verticals being developed and deployed to identify any generic patterns.
* There have been insufficient reports of and questions about existing projects to gather data.

//You// can help. Please comment with your questions and experiences. The more data available, the more it will be possible to automate.

That said it is possible to describe the tools and practices that are available which may be combined to make the development, deployment and installation process more automated. As with any software service, performing customization with TiddlyWeb can never be a fully automated process. Even with something as flexible as TiddlyWiki customizations you still need to do some work to gather the requisite plugin or plugins, get them into your TiddlyWiki and perhaps configure them. This is the routine with any system or framework: you have to find the stuff, get the stuff, install the stuff, configure the stuff.

Therefore, for deployment and installation you want to assemble the tools that make it possible to automate those parts of the system which are repeatable. Much of this is sysadmin 101 and in the open source development world there is little distinction between sysadmin and developer, nor should there be. In the Unix (and Unix-like) world these tools include (but are not limited to) make, Bourne shell, wget or curl, rsync, tar, source control tools (e.g. svn, git etc.) and symlinks.

In the information below we assume that a TiddlyWeb vertical involves TiddlyWiki in some way. This will often be the case, but is by no means required.

A TiddlyWeb vertical uses or includes:
* TiddlyWeb itself.
* The [[tiddlywebplugins.utils]] package, if required.
* Any required TiddlyWeb [[plugins|plugin]].
* Any required auxiliary files for the plugin (such as template files).
* Possibly a [[tiddlywebconfig.py]].
* Any required TiddlyWiki plugins.
* Any required TiddlyWiki tiddler content.
* Any required web server configuration.
* [[apache.py]] if you are using [[mod_python|Using Mod Python]] or [[mod_wsgi|Using Mod WSGI]].
* [[index.cgi]] if you are [[Using CGI]].

Options for dealing with these:
* TiddlyWeb itself should not be installed or deployed as part of the vertical installation process. TiddlyWeb is something the vertical //uses// or depends on. TiddlyWeb should either already be installed on the machine in question, or be installed as a dependency of the vertical. See [[Installing TiddlyWeb]]. Keep in mind that there only needs to be one copy of TiddlyWeb on any given machine, regardless of how many [[instances|instance]] are present.
* That same is true for the [[tiddlywebplugins.utils]] package. It only needs to be installed once and should be installed as a Python package, in the usual Python ways.
* The current routine for getting TiddlyWeb plugins and tiddlywebconfig.py is to use wget to get the files from their canonical place on the web. This getting can be scripted and if any local customizations are required this can be scripted too.
* If your plugin uses multiple files then you may wish to consider:
** Making it into a Python package so it is easy to install and update.
** Making a script to automate (on the development side) the creation of a tarball or similar archive package which is easy to retrieve.
** Making a script to automate using git or svn to check your plugin out of the repo.
** Making a script to use rsnc to get your plugin from where it is being developed to where it is deployed. 
* For TiddlyWiki content (tiddlers and plugins) there are several useful tools:
** The [[twanager]] [[twimport]] command provides a clean mechanism for retrieving content into a TiddlyWeb [[bag]]. {{{twimport}}} can read TiddlyWiki cook style recipe files. If, development-side, you maintain a recipe file with your required tiddlers you get two things:
*** An easy way to build a TiddlyWiki to experiment with your plugins.
*** An easy way to retrieve those plugins into a TiddlyWeb.
** If you need to create specific bags, recipes or tiddlers [[twanager]] has commands for that. twanager can be called from scripts.
** The config item [[instance_tiddlers]] can be used with the [[twanager]] [[update]] command to:
*** Install required tiddlers.
*** Update those tiddlers as required.
** The [[twanager]] [[imwiki]] command may be used to import all the tiddlers in an existing TiddlyWiki file. A TiddlyWiki file may also be {{{POST}}}ed into a TiddlyWeb using the [[HTTP API]].

None of the above is a magic silver bullet, but combined they provide a powerful suite of tools that allow //you// to make at least a stainless steel bullet that works for //you//.

There's more to come here, please comment to shape things as you require.

See also:
* [[devstore]]
These instructions are based on a [[blog posting|http://cdent.tumblr.com/post/94180697/tiddlyweb-for-the-impatient]]. They assume that you are working in a POSIX-like environment (some form of Unix, e.g. Linux, OS X, FreeBSD, etc). If these instructions do not work for you see [[Installing TiddlyWeb]]. Note that these instructions use [[easy_install]] which is no longer the preferred way to install TiddlyWeb. [[pip]] is now preferred.

N.B: These instructions don't go into detail on how things work or why. If you need that information please follow the more detailed information at [[Installing TiddlyWeb]].

* {{{sudo easy_install -U tiddlywebwiki}}}
* {{{twinstance myname}}}
* {{{cd myname}}}
* {{{twanager server}}}

Then {{{open http://0.0.0.0:8080/recipes/default/tiddlers.wiki}}} or {{{xdg-open http://0.0.0.0:8080/recipes/default/tiddlers.wiki}}}. If you don’t have one of those commands open your browser to the shown URL. In your browser you will now see a TiddlyWiki hosted on TiddlyWeb. When you make edits and additions they will be saved to the server.

For this to work you need a fairly modern system with Python and Python’s setuptools installed.

Some people have reported that the second step fails reporting an ImportError. When this happens it means the first step did not fully install all the tiddlyweb dependencies, and you’ll have to install them separately using easy_install. The ImportError will report what is missing. See [[Troubleshooting easy_install]].

''Note'' that {{{easy_install}}} is not the preferred package install tool for TiddlyWeb, [[pip]] is. {{{easy_install}}} is used here because it is more likely to be available.
* [[Scrumptious|http://scrumptious.tv]]
* [[Cork|http://gist.github.com/121370]] (work in progress)
* [[TiddlyWebConfigurator|http://github.com/jayfresh/TiddlyWebConfigurator]] (work in progress)
* [[TiddlyRecon|http://github.com/FND/TiddlyRecon]] ([[demo|http://collab.tiddlywiki.org/TiddlyRecon/]])
* [[TiddlyDocs|http://tiddlydocs.com]] (currently being ported to TiddlyWeb)
Modern macs come with Python and [[easy_install]] so installing TiddlyWeb is straightforward:

{{{
    sudo easy_install -U pip
    sudo pip install -U tiddlywebwiki
}}}

[[pip]] is used to install TiddlyWeb as it is most reliable and flexible when later using [[plugins]]. Once the install is done go to [[Using TiddlyWeb]].
If you wish to run TiddlyWeb with [[Apache|TiddlyWeb and Apache]] it is best [[mounted|mount]] with the mod_wsgi module. To do so:
# Install mod_wsgi for your apache server if it not already there. Instructions on how to do this are out of scope for TiddlyWeb. See http://code.google.com/p/modwsgi/ for more information.
# Get [[apache.py]] and put it in your [[instance]] directory. That file includes information in the comments on how to modify your apache configuration and your [[tiddlywebconfig.py]].

!! Comparing to [[mod_python|Using Mod Python]]
* mod_wsgi is faster and lighter than mod_python
* mod_wsgi can run in its own daemon process that can run as a user you specify, which can avoid lots of file permission confusion

!! Common Problems
* Make sure any files paths you create or edit in the apache config are correct.
* Make sure you have set [[server_prefix]] and [[server_host]] correctly in [[tiddlywebconfig.py]].
* If you wish to use the {{{http_basic}}} extractor with mod_wsgi you must configure {{{    WSGIPassAuthorization On}}} in your apache config where you have configured other WSGI settings.
You need to choose a location for your [[instance]]. If you are using the default text [[store]] that comes with TiddlyWeb this will be a directory on the filesystem. This location is entirely up to you. 

<<tiddler [[instance]]>>
!Description
{{{twstatic}}} is a plugin that adds support for delivering static files through TiddlyWeb, such as static HTML files, images, CSS files.

It is incomplete at this time, but does the job. The major issue is that there is no support for caching related headers such as last-modified and etag.

The twstatic plugin is most useful when using the built in webserver. When [[using Apache|TiddlyWeb and Apache]] it makes more sense to have Apache host the static content.

The plugin is available from PyPI as [[tiddlywebplugins.static|http://pypi.python.org/pypi/tiddlywebplugins.static]].
From the start TiddlyWeb has been designed to be lightweight and fairly low on features, but still flexible enough to do cool stuff. To make cool stuff possible, TiddlyWeb is highly extensible on a variety of dimensions:

* There are [[plugins|Plugin List]] that can add new ~URLs, new [[twanager]] commands and generally any new functionality you can think of.
* You can add additional [[serializations|serialization]] or use a different [[store]].
* You can add add more or replace the existing wikitext [[renderer]] (e.g. adding support for Markdown or Wikicreole).
* You can extend the [[filter]] syntax.
* You can build and use different [[challengers|challenger]] or [[credentials extractors|credentials extractor]].
* You can modify, remove or extend the [[WSGI]] [[middleware]] applications used to transform the web requests and responses.
{{{urls.map}}} is a collection of patterns against which incoming HTTP requests are matched to dispatch those requests to the correct code. If you are familiar with Ruby on Rails it is similar to the routes file.

TiddlyWeb includes a default urls.map that has extensive comments explaining each mapping. You can see [[that file|http://github.com/tiddlyweb/tiddlyweb/raw/master/tiddlyweb/urls.map]].

You may replace the entire urls.map with a different one by setting [[urls_map]] in [[tiddlywebconfig.py]].

You may add to the urls.map or change how an existing mapping is handled with [[plugins]].
Challengers are a subsystem of TiddlyWeb used for [[user]] [[authentication]]. 

TiddlyWeb currently includes support for [[OpenID]] and [[cookie]]-based authentication.

Adding more challengers is straightforward. There is an example of using google auth in the TiddlyWeb for [[googleappengine]] code.

An [[instance]] of TiddlyWeb may be configured to use one or multiple challengers. A {{{GET}}} web request will automatically redirect to the challenger system when a constraint in a [[policy]] is not met.

Challengers are by design triggered only when unauthorized content is accessed but can be explicitly triggered by going to the {{{/challenge}}} URL on your installation.

See [[Auth Model]] for more information.
''Do not use easy_install if you intend to use tiddywebplugins. Use [[pip]] instead.''

* See [[EasyInstall PyPI page|http://pypi.python.org/pypi/setuptools]] for information about installating and using {{{easy_install}}}.

These days (late 2009 on), using [[pip]] to install TiddlyWeb is preferred.
@@merge with [[Serializing and Deserializing]]?@@

The following examples may be instructive. These examples assume the correct modules have been imported.

If you want to serialize a Tiddler object to [[JSON]] the code will look something like this, assuming {{{tiddler}}} is fully populated [[tiddler]] object:
{{{
serializer = Serializer('json')
serializer.object = tiddler
json_string = serializer.to_string()
}}}

If you want to use a JSON string to populate a Tiddler object, you must first create an empty object and then fill it via the serializer:
{{{
serializer = Serializer('json')
tiddler = Tiddler(title)
serializer.object = tiddler
serializer.from_string(json_string)
}}}

The situation is similar for other entities.

Note that the string argument that is passed to the {{{Serializer}}} class identifies a Python module. First the {{{tiddlyweb.serializations}}} package is searched for a matching module, and then {{{sys.path}}}. For non-core serializations, this means that the input to {{{Serializer}}} may be a dotted module identifier, such as {{{tiddlywebwiki.serialization}}}.

See also:
* [[serializer]]
* [[SerializationInterface]]
TiddlyWeb is distributed with a copy of a multi-threaded, pure-Python, WSGI compliant web server from the [[CherryPy]] project. It is small, light and generally fast enough for up to medium use. It requires no additional installation and configuration beyond [[Installing TiddlyWeb]].

Once an [[instance]] has been created, you can mount that instance in cherrypy quite simply:
* cd to the instance directory
* run {{{twanager server}}}

By default this will start a server running at http://0.0.0.0:8080/. If you need to use a different host or port (//if you want to access  the server remotely you will//) you need to set [[server_host]] in [[tiddlywebconfig.py]].

On some operating systems, such as Windows when using Cygwin, 0.0.0.0 will not work and you will need to use 127.0.0.1 instead, which you can achieve by running {{{twanager server 127.0.0.1 8080}}}.

The cherrypy server is part of what enables [[TiddlyWeb for the Impatient]].
The tiddlyeditor [[plugin]] provides a quick solution for editing a single [[tiddler]] when you visit the HTML representation of that tiddler. It adds an {{{Edit}}} link to the page, which points to a special {{{tiddlyeditor}}} URL. That URL responds with a custom TiddlyWiki generated to allow you to edit //just// that tiddler.

The plugin is installed on this server, see the [[HTML representation of this tiddler|http://tiddlyweb.peermore.com/wiki/recipes/docs/tiddlers/tiddlyeditor]] to see the Edit link. ''Note:'' If you follow this particular Edit link you will be presented with a [[challenger]] that will not let you pass.

The code can be found at [[github|http://github.com/tiddlyweb/tiddlyweb-plugins]].
!Resource
A single [[recipe]] on the system.

!Representations
; {{{text/html}}}
: An HTML presentation of the description of the recipes, a list of the bags and filters which make up the recipe, and a link to its list of tiddlers.
; {{{application/json}}}
: [[JSON]] representation of the recipe. See [[JSON recipe]].

!Methods
!! {{{GET}}}
Get the recipe. The [[current user]] must pass the read [[constraint]].
!! {{{PUT}}}
Create or edit a named recipe. The create a new recipe, the current user must pass the [[recipe_create_policy]] config setting. To edit and existing recipe, the current must pass the manage constraint.
!! {{{DELETE}}}
Remove the recipe. Tiddlers are not affected. To delete a recipe the current must pass the manage constraint. When deleting a recipe, what "delete" means is dependent on the current [[store]]. In the text store, for example, it means the recipe is gone, forever. In other stores it may mean that the recipe is flagged as deleted, and could be administratively undeleted in the future.

!Notes

!Example
http://tiddlyweb.peermore.com/wiki/recipes/default
The JSON form of a [[tiddler]] when a tiddler is {{{GET}}} or {{{PUT}}}. When getting a list of tiddlers a list of dictionaries is returned. When getting just one, a single dictionary is returned.

The form of the dictionary is quite variable, as a tiddler is really just a dictionary of key/value pairs, available at a known URL. The JSON serialization is that dictionary serialized.

When getting a tiddler as JSON you can expect at least the following form:
{{{
{
    "text": "the text of the tiddler",
    "created": "YYYYMMDDHHMMSS",
    "modified": "YYYYMMDDHHMMSS",
    "modifier": "name of most recent editor",
    "tags": ["list","of","tags"],
    "fields": {
        "customfield": "arbitrary string",
        "lowercase": "..."
    }
}
}}}

When putting a tiddler as JSON, all fields are optional.

!See Also
* [[How can I use curl to create stuff in TiddlyWeb?]]
!Resource
A single of [[tiddler]] produced by the named [[recipe]].  The [[current user]] must pass the read [[constraint]] on the recipe to see the tiddler as well as the read constrain on the [[bags|bag]] in the recipe.

!Representations
; {{{text/plain}}}
: A text representation of the tiddler. See [[text tiddler]].
; {{{text/html}}}
: An HTML representation of the tiddler. See [[HTML tiddler]]. 
; {{{application/json}}}
: [[JSON]] representation of the tiddler. See [[JSON tiddler]].

!Methods
!! {{{GET}}}
Get the tiddler.
!! {{{PUT}}}
Create or edit the named tiddler use the [[text|text tiddler]] or [[JSON|JSON tiddler]] representations. Which bag the tiddlers is stored into is determined by the [[recipe cascade]].
!! {{{DELETE}}}
Delete the tiddler.

!Notes

!Example
http://tiddlyweb.peermore.com/wiki/recipes/docs/tiddlers/HTTP%20API
!Resource
A single revision of [[tiddler]] contained by the named [[bag]].  The [[current user]] must pass the read [[constraint]] on the bag to see the tiddler.

!Representations
; {{{text/plain}}}
: A text representation of the tiddler. See [[text tiddler]].
; {{{text/html}}}
: An HTML representation of the tiddler. See [[HTML tiddler]]. 
; {{{application/json}}}
: [[JSON]] representation of the tiddler. See [[JSON tiddler]].

!Methods
!! {{{GET}}}
Get the tiddler revision.

!Notes

!Example
http://tiddlyweb.peermore.com/wiki/bags/docs/tiddlers/HTTP%20API/revisions/19
''Do not use easy_install if you intend to use tiddywebplugins. Use [[pip]] instead.''

This requires a jailbroken iPhone.
!Initial Setup
* install Python via Cydia
* install Setup Tools via Cydia
* install Subversion via Cydia
* install adv-cmds via Cydia
* upgrade Setup Tools: {{{$ easy_install -U setuptools}}}
* install TiddlyWeb: {{{$ easy_install tiddlywebwiki}}}
* create instances directory: {{{mkdir /private/var/mobile/TiddlyWeb}}}
!Instance Setup
{{{
$ cd /private/var/mobile/TiddlyWeb/
$ twinstance myInstance
$ cd myInstance
$ nohup twanager server localhost 8080 &> tweb.log &
}}}
!Accessing Instance
In Safari, open http://localhost:8080 or directly http://localhost:8080/recipes/default/tiddlers.wiki.
!Terminating Instance
{{{
$ ps aux | grep twanager | cut -d " " -f 2-8 # returns PID
$ kill <PID>
}}}
!Related Links
* [[original thread|http://groups.google.com/group/tiddlyweb/browse_thread/thread/8f07292b301a9713/23c1730317c6d258?#23c1730317c6d258]]
Some plugins are meant to be both server and twanager extensions.

If the plugin initialization needs to distinguish between these cases, the following check can be used:
{{{
def init(config):
    if 'selector' in config:
        # server
    else:
        # twanager
}}}
!!Description
Return the list of tiddlers which are the result of processing the provided [[recipe]]. If more than one tiddler of the same name is pulled from different bags, the [[tiddler]] from the [[bag]] processed later is the one that is kept. See also [[recipe cascade]].

!!Parameters
* [[recipe]]
* //[[environ]]=None//

!!Returns
* list of [[tiddlers|tiddler]]

If there are no tiddlers, an empty list is returned.

!!Example
{{{
    recipe = Recipe('foobar')
    recipe = store.get(recipe)
    tiddlers = control.get_tiddlers_from_recipe(recipe)
}}}

!!Notes
This is the canonical way of getting the tiddlers from a recipe. If the {{{store}}} attribute is set on the provided recipe, the bags listed in the recipe will be read from the store to get their lists of tiddlers and then filter them according to the filters in the recipe.

If an {{{environ}}} parameter is provided this is assumed to be a {{{dict}}} which is the [[WSGI]] [[environ]]. It is used to process the {{{_recipe_template}}} (see the [[source|source repository]] for details).
tiddlywebplugins.utils is a Python package with useful functions for creating plugins. It can be found in two locations:
* [[On pypi|http://pypi.python.org/pypi/tiddlywebplugins.utils]] so you can install it with [[pip]].
* [[In github|http://github.com/tiddlyweb/tiddlywebplugins.utils]].
On modern Ubuntu systems the installation process is cleanly straightforward:

{{{
    sudo apt-get install python-pip python-dev
    sudo pip install -U pip
    sudo pip install -U tiddlywebwiki
}}}

On less new Ubuntu systems, [[pip]] will not be available as a package. In that situation, setuptools will first need to be installed:

{{{
    sudo apt-get install python-setuptools
    sudo easy_install -U pip
    sudo pip install -U tiddlywebwiki
}}}
There are several ways to run TiddlyWeb under [[Apache|http://httpd.apache.org/]]:

* run it as a [[CGI|Using CGI]] (not recommended, unless you have no alternatives)
* run it under [[mod_python|Using Mod Python]] (not recommended)
* run it under [[mod_wsgi|Using Mod WSGI]] (recommended)
* run it under [[Fast CGI|Using Fast CGI]] (untested)

While TiddlyWeb should work with 1.3.x versions of Apache, it is probably best to use 2.x versions.
//This information is only relevant to installations on filesystems that support unix style permissions and are using the built in text store.//

Sometimes you might like a group of users on a system to be able to edit the files in a [[store]], but not as only one user. To do this you can put all those users in the same group, make the store writable for that group, and cause the server to write files in a way that makes sure they are group writable. If these concepts are alien to you, this is probably not for you.

* change the group of the files in the store:
** {{{chgrp -R <group> store}}}
* make the store group writable:
** {{{chmod -R g+w store}}}
* make all the directories in the store setgid so files that are created in there belong to the right group
** {{{find store -type d | xargs chmod g+s}}}
* set the umask of the serving process by editing [[apache.py]] to include, near the top but below {{{import os}}}:
** {{{os.umask(0002)}}}
<<tiddler twanager>>
The TiddlyWeb Python API is the collection of public classes, functions and methods made available by the modules which make up the TiddlyWeb code base. Each module has its own documentation which is the authoritative source. Running the following command will give you the top level of the documentation, and a list of other modules:
{{{
pydoc tiddlyweb
}}}

The following list is incomplete. Where parameters are listed, if they are in //italics// they are optional.

<<list filter [tag[pyapi]]>>
Much like in TiddlyWiki, TiddlyWeb can use plugins to extend the functionality of the system. Plugins can add functionality to the web server, to [[twanager]] or both.

A plugin can be distributed for use with other TiddlyWeb installations. For a list of of plugins, see [[Plugin List]].

Plugins are included in a TiddlyWeb [[instance]] by editing [[tiddlywebconfig.py]] to add [[system_plugins]] and/or [[twanager_plugins]] information.

There is Python package called [[tiddlywebplugins.utils]] that includes useful functions for creating plugins.

A [[tiddlywebplugins]] namespace has been reserved for those plugins which have reached a level of stability where it makes sense for them to be distributed from [[PyPI]].

The best way to learn how to create plugins is to look at [[existing examples|Plugin List]].
//This is a stub.//

To work with lots of users and bags in TiddlyWeb you need to understand [[bags|bag]], [[policies|policy]], [[users|user]] and [[user roles|role]].

The fundamental concern in this situation is creating a structure that is easy to understand and easy to maintain. While the first thought might be to create bag policies that list lots of users, this is not ideal. Adding a username in potentially many policies is cumbersome, prone to error and the policy files may become large enough that they are expensive to process.

A better solution is to use [[roles|role]]. Role names are put in [[policy]] statements. When users are created, they are given the required roles. In the future when a user's level of access changes, they simply need to have their roles changed or their account deleted: there's no need to go digging around in policies.

See also:
* [[How do I add a user?]]
* [[How do I give a user a role?]]
* [[How do I set or edit a bag policy?]]
A credentials extractor is a system in TiddlyWeb, part of the [[Auth Model]] that looks at in incoming web request and //extracts//, where possible, user information from the request and validates it. If the information is valid it is put into [[tiddlyweb.usersign]] for later use. If no information is found, the user is {{{GUEST}}}.

Multiple extractors are managed by [[UserExtract]] and configured by the [[extractors]] configuration item.

TiddlyWeb comes pre-packaged with two extractors:
* ''http_basic'': Checks the request for HTTP Basic Authorization credentials and verifies them against the TiddlyWeb [[User]] datastore. //Note//: there is no [[challenger]] for HTTP Basic. It is assumed that if someone wants to use HTTP Basic they will just put the necessary information in the headers of their request.
* ''simple_cookie'': Checks the request for a cookie named {{{tiddlyweb_user}}} with a hashed value. Both the {{{openid}}} and {{{cookie_form}}} [[challengers|challenger]] will set this cookie to the provided username if the challenger passes.

While there is no requirement that an extractor do so, both of these mentioned above will query the [[User]] datastore with the discovered username to look for [[roles|role]]. If any are found they are added to [[tiddlyweb.usersign]].

Additional extractors can be added to the system by adding module names to the {{{extractors}}} list in [[tiddlywebconfig.py]]. The modules should contain a class called {{{Extractor}}} that implements the [[ExtractorInterface]].
The googleappengine code provides necessary extensions and adjustments to TiddlyWeb to make it work on [[Google App Engine]]. This is a quite exciting but rather advanced collection of code (compared to some of the other plugins) that requires a fair amount of work for someone to use. The included {{{README}}} file may help.

The code can be found at [[github|http://github.com/tiddlyweb/tiddlyweb-plugins]].

A running version of this code can be found at http://tiddlyweb.appspot.com/ and http://tiddlywebwiki.appspot.com/

A blog post [[describes how to set it up|http://cdent.tumblr.com/post/278948050/smooth-tiddlyweb-on-app-engine]].
Sometimes you may wish to create or update a [[tiddler]], [[bag]] or [[recipe]] from the command line and [[twanager]] won't work for you for some reason. Maybe you are using [[Google App Engine]] or your are accessing a remote server. In these instances you can use [[curl]] or [[wget]] to make requests to the TiddlyWeb server.

Below are some examples. In each of these the argument to the -d switch is a JSON string, so the use of {{{'}}} and {{{"}}} matter.

!!Create or Update a Bag
{{{
      curl -X PUT -H 'Content-Type: application/json' -d '{"policy":{}}' http://0.0.0.0:8080/bags/foobar
}}}

!!Create or Update a Recipe
{{{
    curl -X PUT -H 'Content-Type: application/json' -d '{"recipe":[["system",""],["common",""]]}' \
        http://0.0.0.0:8080/recipes/default
}}}

!!Create or Update a Tiddler
{{{
    curl -X PUT -H 'Content-Type: application/json' -d '{"text":"hello"}' \
        http://0.0.0.0:8080/bags/foobar/tiddlers/monkey
}}}

If you wish to {{{PUT}}} a [[binary tiddler]] you can do the following, assuming the source file is named {{{monkey.png}}}:
{{{
    curl -X PUT -H 'Content-Type: image/png' --data-binary @monkey.png \
        http://0.0.0.0:8080/bags/foobar/tiddlers/monkey
}}}

See also:

* [[tiddlywebweb]]
* [[HTTP API]]
//POST//ed data can arrive in two forms:
* as form content ({{{Content-Type: application/x-www-form-urlencoded}}}), in which case it is accessible via {{{environ["tiddlyweb.query"]}}}
* as "raw" request, which has to be read from {{{stdin}}}:
{{{
length = int(environ["CONTENT_LENGTH"])
content = environ["wsgi.input"].read(length)
}}}
In the TiddlyWeb context, a constraint is one of several actions or permissions described in a [[policy]].
The constraint describes which [[user]] or [[role]] may perform the respective action:
|!Constraint|!Bag                                  |!Recipe|h
|''read''   |view bag's tiddlers                   |view bag-filter pairs constituting the recipe|
|''write''  |modify bag's tiddlers                 |//unused//                                   |
|''create'' |add tiddlers to bag                   |//unused//                                   |
|''delete'' |remove tiddlers from bag              |//unused//                                   |
|''manage'' |delete bag, view and modify its policy|delete recipe, view and modify its policy    |
|''accept'' |skip validation for tiddlers          |//unused//                                   |
cf. http://groups.google.com/group/tiddlyweb/msg/e0b3709851565dbe

An empty constraint list means there is no constraint; any user can perform the action.
{{{NONE}}} and {{{ANY}}} are special: {{{NONE}}} means the action may not be done, by anyone, {{{ANY}}} means any [[authenticated|authentication]] user (i.e. not {{{GUEST}}}) may perform the action.
When a [[bag]] is GET or PUT as [[JSON]] the following form is used:
{{{
{
    "desc": "decription of the bag (may be be an empty string or absent)",
    "policy": {
        "read": [], 
        "write": [],
        "create": [],
        "delete": [],
        "manage": [],
        "owner": ''
    }
}
}}}

The policy may be an empty dict but the key must be present. The desc is optional.

See: [[How can I use curl to create stuff in TiddlyWeb?]]
//Note: This is an experimental feature, the details of which may change.//

A validator is a function called when a [[recipe]], [[bag]] or [[tiddler]] is [[PUT|method:put]] to the server. Based on configuration, [[plugins|plugin]] and [[policies|policy]] zero to many validators may be called when an entity is PUT. How things work depends on the type of entity:

!Bags and Recipes
By default the description attribute of a bag or recipe is sanitized for dangerous HTML. That function may be turned off or other validators added by adjusting the list of functions in {{{tiddlyweb.web.validator.BAG_VALIDATORS}}} or {{{tiddlyweb.web.validator.RECIPE_VALIDATORS}}}. See below for more about the functions.

!Tiddlers
Tiddlers are sent through the validator process based on the {{{accept}}} constraint in the [[policy]] of the bag to which the tiddler is being {{{PUT}}}. If the accept constraint is empty no validation is done. If there is a user, some users, a role or the special policy words {{{ANY}}} or {{{NONE}}} listed then the tiddler is passed to the functions in {{{tiddlyweb.web.validator.TIDDLER_VALIDATORS}}} for every user that //does not// match the constraint (that is, the content is accepted without validation for the people listed in the constraints).

In the current code distribution there are no ~TIDDLER_VALIDATORS, they may be added via [[plugins|plugin]].

!Validator Functions
A validator function has a simple signature: {{{entity, environ}}} where entity is a bag, recipe or tiddler. The validator either //changes// the provided entity, or raises an exception indicating that it can't be valid. The exceptions are {{{InvalidTiddlerError}}}, {{{InvalidBagError}}}, {{{InvalidRecipeError}}}.

!Examples
A simple example validator can be found at http://github.com/tiddlyweb/tiddlyweb-plugins/tree/master/validate-modifier

[[Ben Gillies]] has [[written|http://bengillies.net/#%5B%5BValidating%20TiddlyWeb%5D%5D]] validators for sanitizing [[HTML|http://github.com/bengillies/TiddlyWeb-Plugins/blob/master/validators/html_validator.py]] and [[TiddlyWiki|http://github.com/bengillies/TiddlyWeb-Plugins/blob/master/validators/tiddlywiki_validator.py]] inputs.
* caching (e.g. via [[cachinghoster]] and/or [[caching-store]]) can be used to reduce expensive computations
* indexing (e.g. with the [[tiddlywebplugins.whoosher]] plugin) can help with searches across all tiddlers
* a customized store implementation might be used for efficient [[data mapping|http://github.com/tiddlyweb/tiddlyweb-plugins/tree/master/mappingsqlstore/]]

* having lots of bags is //far// better than having bags with lots of tiddlers in them
* when filtering a bag, TiddlyWeb looks at every single tiddler in the bag
> <cdent> if you know that you are always going to be doing a particular filter, that might be sign that you actually want to have a bag that indicates that state, rather than a field
The following instructions assume the use of TiddlyWebWiki.
!Setting Up an Instance with the ~DevStore
* install the [[devstore]] plugin
* use the included //twinstance_dev// script to create a preconfigured dev instance
** alternatively, download {{{tiddlywebconfig.py}}} from [[this repository|http://gist.github.com/280191]] (via the //raw// link) to a temporary directory and, from the same directory, run //twinstance// to create a new [[instance]]
* in the new instance directory, modify or extend {{{tiddlywebconfig.py}}}'s {{{local_instance_tiddlers}}} entry to point to the desired tiddlers on the local hard drive
* changes to the specified tiddlers will be reflected on a simple page reload in the browser
!Modifying an Existing Plugin
TiddlyWebWiki uses [[Cook-style recipes|http://svn.tiddlywiki.org/Trunk/verticals/TiddlyWebWiki/index.recipe]] to indicate the default set of tiddlers in the //system// bag.

If the path in the instance's {{{local_instance_tiddlers}}} is set up properly, the local plugin files can be modified directly.
!Adding a New Plugin
* create a {{{.js}}} file along with a {{{.meta}}} file ([[example|http://svn.tiddlywiki.org/Trunk/association/plugins/TiddlyWebConfig.js.meta]])
* extend {{{local_instance_tiddlers}}} with the path to the {{{.js}}} file:
{{{
'local_instance_tiddlers': {
    'system': [
        '../../../TiddlyWiki/svn.tiddlywiki.org/Trunk/verticals/TiddlyWebWiki/index.recipe',
        '/path/to/foo.js'
    ]
}
}}}
Chris Dent is the original author of TiddlyWeb. See [[Credits]] for more about that.

* [[blog|http://cdent.tumblr.com/]]
* [[personal website|http://www.burningchrome.com/]]
* [[company website|http://peermore.com/]]
The TiddlyWeb code is in the [[source repository]]. If you are planning to do some [[TiddlyWeb development|Developing With TiddlyWeb]] you'll want to check that out. If you are only wanting to install TiddlyWeb, see [[Installing TiddlyWeb]].
Sometimes you might want to edit a tiddler directly on the filesystem in the data store. If you do this you may find that the changes do not show up the next time you load the Tiddler from a browser.

When TiddlyWeb presents content to a browser it sends it with an Etag. This Etag is then used by the browser to validate future requests to see if it can use what's in its cache. The Etags are calculated from the metadata of the tiddlers (title, modified time, revision number), which don't get changed when you edit them in place in the store.

To force the Etag to change you need to do one or two things, depending on how you are accessing the Tiddler or Tiddlers:

* If you are most concerned with forcing the wiki that is generated to update, change the modified field on the tiddler
* If you want to make sure that the individual tiddler will reload in the browser, save your changes as a new revision (i.e. if you loaded 1, write it as 2).

In most cases it is the first thing that will matter.

See [[the original trac ticket|http://trac.tiddlywiki.org/ticket/943]].
[[Wikipedia|http://wikipedia.org]] says that [[content negotiation|http://en.wikipedia.org/wiki/Content_negotiation]]

> is a mechanism defined in the HTTP specification that makes it possible to serve different versions of a document (or more generally, a resource) at the same URI, so that user agents can specify which version fit their capabilities the best.

TiddlyWeb uses content negotiation to allow a user agent to declare which [[representation]] of a [[resource]] it prefers. Using the {{{Accept}}} header the user agent can declare that it wants a {{{text/plain}}}, {{{text/html}}}, {{{application/json}}} or {{{text/x-tiddlywiki}}} version of a resource (if available).

A user agent (often a person using a web browser) may also adjust the request URL to add an extension to simulate setting the {{{Accept}}} header. For example to get the plain text representation of a bag resource one might request:
{{{
GET /bags/mybag.txt
}}}
The default available extensions are:
* html to get {{{text/html}}}
* txt to get {{{text/plain}}}
* json to get {{{application/json}}}
* wiki to get {{{text/x-tiddlywiki}}}
Not all resources provide all representations. See the [[HTTP API]] for details.

Supported extensions can be extended by creating and configuration another [[serialization]].
A Tiddlyweb [[instance]] needs to be [[mounted|mount]] somewhere accessible over the web in order to be useful as a service. This means that some HTTP server needs to be configured to provide the bridge between incoming HTTP requests and TiddlyWeb code. There are a variety of ways to do this:

* [[Using CherryPy]]
* [[TiddlyWeb and Apache]]
* [[Using spawning]]
* Other WSGI servers

If you have mounted TiddlyWeb in some way not documented here, please provide the information so others can benefit from what you've learned.
If you are using the TiddlyWebWiki configuration of TiddlyWeb, you can keep the required TiddlyWiki plugins up to date by using [[twanager]]'s {{{update}}} command.

This will request ServerSideSavingPlugin, TiddlyWebAdaptor and TiddlyWebConfig from the latest install of tiddlywebwiki and install them in the system bag (as determined by [[instance_tiddlers]]).
{{{server_request_filters}}} is a configuration item that controls which [[WSGI]] applications a request is processed //through// before being handled by the core of the TiddlyWeb code. The {{{server_request_filters}}} are used to either establish information that will be needed later in the request process or extract information from the request required later in the process.

Any [[instance]] may add or remove filters, but in practice this has proven rare. [[methodhack]] and [[pathinfohack]] are two plugins that add request filters.

The default request filters, in chronological order of use, are:
# [[Query]]
# [[StoreSet]]
# [[UserExtract]]
# [[Negotiate]]

Also included in the server request stack are two required WSGI applications:
* [[Configurator]]
* [[Environator]]
A serialization is the representation of a data structure in a particular format.

In the context of [[TiddlyWeb]], this means exposing [[tiddlers|tiddler]] in a variety of ways using [[serializers|serializer]].
A [[recipe]] is made up of a list of [[bags|bag]] and [[filters|filter]]. If no filter is used, all the tiddlers in the bag are included when processing the recipe. If a filter is used, only those tiddlers which match the filter are included from the bag.

Therefore, the way to use only some tiddlers from a bag is to provide a filter with the bag in the recipe definition.

!Examples
''Note'': These examples only work with the new syntax provided in TiddlyWeb v0.9.31 and beyond.

All the tiddlers with tag {{{blog}}} and tag {{{published}}} from bag {{{foo}}}:
{{{
    /bags/foo/tiddlers?select=tag:blog;select=tag:published
}}}

The ten most recently modified tiddlers from bag {{{bar}}}:
{{{
    /bags/bar/tiddlers?sort=-modified;limit=10
}}}
[[TiddlyWiki]]s that are generated by TiddlyWeb start from a base tiddlywiki included in the distribution. The file is a copy of the most recent public empty.html kept at http://tiddlywiki.com/.

The html file is not directly accessible to users and developers. If you want to use a different file as your [[base_tiddlywiki]] you can point to it in [[tiddlywebconfig.py]] as follows:

{{{
    config = {
        'base_tiddlywiki': '/path/to/tiddlywiki.html'
    }
}}}

The path can be absolute or relative to the [[instance]] directory.
{{{from_svn}}} is [[twanager]] command that can retrieve content from an http or file URL and put that content into a bag named in the arguments. The name of the command comes from the type of content it handles: it retrieves {{{.tiddler}}}, {{{.js}}} and {{{.recipe}}} files in the format used in the TiddlyWiki [[subversion repository]]. However, the content does not need to be located in the TiddlyWiki repo, it can be anywhere an http, https, or file url can reach.

If a recipe file is retrieved, it will traverse the recipe and retrieve the tiddlers and javascript named therein.

{{{from_svn}}} is a very useful way to populate a TiddlyWeb installation with existing TiddlyWiki content.
In [[Python's|Python]] [[WSGI]] specification, a WSGI application is a //callable// that has a specific signature. The first parameter is a dictionary, usually called {{{environ}}}, that contains all sorts of information related to the current web request. This includes common {{{CGI}}} environment variables, information about the WSGI server, and any pieces of information that upstream WSGI applications have added to {{{environ}}}.

Pretty much anything can be added to environ but whatever is added only lasts from the point of its introduction into the environment until the end of the current web request.

A common trick in a WSGI stack of applications is to modify the incoming request to make it appear like a different type of request. This is especially useful in TiddlyWeb as a way of reusing existing code.
StoreSet is a WSGI application in the [[server_request_filters]] stack that sets {{{tiddlyweb.store}}} in [[environ]] to an instantiated [[store]]. This is done so that any single request only needs to "open" the store once per request.

Some stores will choose to use persistent database handles, manage by the implementor of the [[StorageInterface]].

In code that is part of the web handlers the store kep in {{{tiddlyweb.store}}} should be used, as follow:

{{{
tiddler = Tiddler('foo', 'bar')
store = environ['tiddlyweb.store']
tiddler = store.get(tiddler)
}}}
[[TiddlyWeb]] assumes that all input and output is ~UTF-8 encoded. Internally strings are managed as unicode.

Conversion between the two formats should be limited to entry and exit points and is managed as:
{{{
    unicode = str.decode('UTF-8')
    string = unicode.encode('UTF-8')
}}}
Several ~URLs in the TiddlyWeb [[HTTP API]] produce a result set which is a list or collection of tiddlers. Any of these may be [[filtered|filter]] to return a subset of that collection. To filter a tiddler collection URL a filter string is appended to the url as a query string.

The default collection ~URLs include:
* [[/recipes/{recipe_name}/tiddlers]]
* [[/bags/{bag_name}/tiddlers]]
* [[/search]]

!Examples

''20 most recently modified blog postings from recipe blogs:''
{{{
    /recipes/blogs/tiddlers?select=tag:blog;select=tag:published;sort=-modified;limit=20
}}}
!Resource
A single revision of [[tiddler]] produced by the named [[recipe]].  The [[current user]] must pass the read [[constraint]] on the bag to see the tiddler.

!Representations
; {{{text/plain}}}
: A text representation of the tiddler. See [[text tiddler]].
; {{{text/html}}}
: An HTML representation of the tiddler. See [[HTML tiddler]]. 
; {{{application/json}}}
: [[JSON]] representation of the tiddler. See [[JSON tiddler]].

!Methods
!! {{{GET}}}
Get the tiddler revision.

!Notes
[[/bags/{bag_name}/tiddlers/{tiddler_title}/revisions/{revision}]] is preferred as it always leads to the same revision.

!Example
http://tiddlyweb.peermore.com/wiki/recipes/docs/tiddlers/HTTP%20API/revisions/19
!Resource
A list of [[tiddlers|tiddler]] that match the provided query string.  The results are only those tiddlers which are from bags on which the [[current user]] passes the read [[constraint]].

!Representations
; {{{text/plain}}}
: A linefeed separated list of tiddlers.
; {{{text/html}}}
: An HTML presentation of the description of the bag and a link to its list of tiddlers.
; {{{application/json}}}
: [[JSON]] representation of the tiddlers in the bag. See [[JSON tiddler]]. By default the included tiddlers are skinny. You [[can make them fat|How can I GET many tiddlers at once?]].

!Methods
!! {{{GET}}}
Get the tiddlers that match the query.

!Notes
The query is provide in a {{{q=<query>}}} parameter on the URL. The query is used is entirely up to the [[store]] being used or any [[plugin]] changes. The default search does simple check for the text in query anywhere in the tiddler.
These tiddlers may be [[filtered|filter]].

!Example
http://tiddlyweb.peermore.com/wiki/search?q=search
The caching-store is a [[plugin]] which provides a [[store]] that will query a [[memcached]] server on a get. If the entity is not found in memcache, then the {{{cached-store}}} is queried. The cached-store is any other store, e.g. the text store, where the content is persisted.

This is a highly experimental plugin. It is in use on the server hosting this content but is not having much impact because use of this server is insufficiently concurrent to require it. It is likely the plugin would have a positive impact in a very high volume situation where individual tiddlers are being requested often. If you have an application like this, please let us know because that would be fun to help optimize.

The code and configuration information can be found at the [[tiddlyweb plugins github|http://github.com/tiddlyweb/tiddlyweb-plugins/tree/master/caching-store]]. As it says in the {{{README}}} you'll need to do some fiddling to make it go.
The [[policy]] of a [[bag]] is set or edited when editing a bag either via [[twanager]] or using the [[HTTP API]].

The {{{bag}}} command of twanager takes a bag name as an argument and an optional JSON string representing a [[policy]]:
{{{
twanager bag foobar
{"policy": {"read":["someusername"]}}
^D
}}}

PUT to [[/bags/{bag_name}]] is much the same: the JSON representation must include a policy element.

In either case, if the bag already exists, the bag's current policy is clobbered by the new one provided.
migrate is a plugin that enables migrating the content of one [[store]] to another. For the purposes of backup, mirroring, or migrating to a new store format (e.g text to sql) etc.

It simply traverses the source store, getting each entity, and then putting it to the other store.

It may be installed from PyPI as [[tiddlywebplugins.migrate|http://pypi.python.org/pypi/tiddlywebplugins.migrate]].
Every tiddler has revisions. Every time a tiddler is changed, a new revision is created. Revisions are identified by an integer ID.

However, not all stores support revisions, so when a tiddler is changed, the existing single revision is replaced by the new one.

A list of revisions can be access at [[/bags/{bag_name}/tiddlers/{tiddler_title}/revisions]] and an individual revision at [[/bags/{bag_name}/tiddlers/{tiddler_title}/revisions/{revision}]]. Individual revisions are immutable.

In python code, retrieving a specific revision is done as follows:

{{{
    tiddler = Tiddler(title, bag_name)
    tiddler.revision = 4
    tiddler = store.get(tiddler)
}}}

If the revision does not exist a {{{NoTiddlerError}}} exception is raised. If {{{revision}}} is not set, the most recent revision is retrieved.
In TiddlyWeb a renderer is a code system that takes a [[tiddler]] as input and returns an HTML form. It is used by the HTML [[serializer]] to generate the HTML content, usually turning wikitext syntax into HTML with a wikitext renderer, such as [[WikklyText]]. This functionality was originally fully in the serializer, but it became clear with use that being able to support multiple syntaxes would be useful.

Two [[config]] items control how wikitext in tiddlers is rendered. They are [[wikitext_renderer]] and [[wikitext_render_map]].

If the HTML form of a tiddler is requested //and// the {{{type}}} attribute on the tiddler is not set its content will be rendered by the default {{{wikitext_renderer}}}. In the default installation [[wikklytextrender]] is used. If the [[tiddlywebwiki]] package has not been installed, the the {{{raw}}} renderer is used, wrapping HTML escaped content in {{{<pre>}}} tags.

If the HTML form of a tiddler is requested //and// the {{{type}}} attribute begins with {{{text/}}} //and// the {{{type}}} attribute is present as a key in [[wikitext_render_map]] the value in the map is used to identify the module which contains the {{{render()}}} method for that type.
[[Recipes|recipe]] combine [[bags|bag]], which in turn are collections of [[tiddlers|tiddler]].
!Examples 
http://fnd.lewcid.org/tmp/osnet.png
{{{
    Bags                Recipes

    \'''''/
    /     \
   /       \            +---------+
  ( public  ) -+        |         |
   \       /    \       |         |
    ```````      +----> | website |
                  \     |         |
    \'''''/        +    |         |
    /     \        |    +---------+
   /       \       |
  ( editors ) --+  |    +---------+
   \       /     \ |    |         |
    ```````       \|    |         |
                   +--> |   CMS   |
    \'''''/       /     |         |
    /     \      /      |         |
   /       \    /       +---------+
  ( system  ) -+
   \       /    \       +---------+
    ```````      \      |         |
                  \     |         |
    \'''''/        +--> |  wiki   |
    /     \       /     |         |
   /       \     /      |         |
  ( private ) --+       +---------+
   \       /
    ```````
}}}
!!Description


!!Parameters


!!Returns


!!Example


!!Notes
<<newTiddler
	label:"New PyApi"
	text:{{store.getTiddlerText("pyapitemplate")}}
	tag:"pyapi"
>>
left to do (at top level):
* manage
* serializations
* serializer
* store
* stores
* web
* model (for the entities)
!!Description
Return a sha1 object from which a digest can be created.

!!Parameters
* //data//

!!Returns
* A {{{hashlib}}} or {{{sha}}} digest on which {{{hexdigest()}}} or {{{update(string)}}} may be called.

!!Example
{{{
    digest = util.sha()
    for word in ['foo', 'bar']:
        digest.update(word)
    print digest.hexdigest()
}}}

!!Notes
This exists to encapsulate the differences between pre Python 2.5 hash handling and post 2.5.
{{{
from tiddlyweb.model.tiddler import Tiddler
from tiddlyweb.model.bag import Bag
from tiddlyweb.store import Store


environ = {}
store = Store("text", {"store_root": "data"}, environ)

bag = Bag("Foo")
bag.desc = "lorem ipsum"
store.put(bag)

tiddler = Tiddler("Bar", bag="Foo")
tiddler.modifier = "FND"
tiddler.text = "dolor sit amet"
store.put(tiddler)
}}}
''N.B.:'' Store creation can be simplified via the {{{get_store}}} function in [[tiddlywebplugins.utils]].
A store is the TiddlyWeb name for a system that does persistent storage of [[recipe]], [[bag]], [[tiddler]], and [[user]] objects. A TiddlyWeb installation may only directly use one store per instance, but a store itself may use one or more other stores (see the [[diststore]] and [[multistore]] for some intriguing examples). The store used is determined by configuration of the [[instance]].
TiddlyWeb is very much a standing-on-the-shoulders-of-giants kind of project. It wouldn't exist without the help and input of many people.

ChrisDent wrote a [[CREDITS|http://cdent.tumblr.com/post/59706028/tiddlyweb-credits]] document a while back.
On the web a representation is one of possible many forms of a single [[resource]]. In TiddlyWeb a [[tiddler]] is a resource. It can be represented in a variety of forms including HTML, text, JSON. Each of these are a representation of the resource. A [[serializer]] is used to turn a resource into a particular representation.
{{{apache.py}}} is a small python module that provides an interface between [[Apache|TiddlyWeb and Apache]] running [[mod_wsgi|Using Mod WSGI]] or [[mod_python|Using Mod Python]] and TiddlyWeb. It has one simple job: presenting a function called {{{application}}} with a [[WSGI]] signature to the [[Python]] interpreter in the Apache server.

{{{apache.py}}} is [[distributed with the TiddlyWeb tarball|http://tiddlyweb.peermore.com/dist]] or [[available from github|http://github.com/tiddlyweb/tiddlyweb/raw/master/apache.py]].
WSGI is "Web Server Gateway Interface"

The [[WSGI Wiki|http://www.wsgi.org/wsgi/What_is_WSGI]] says:

"It is a specification for web servers and application servers to communicate with web applications (though it can also be used for more than that). It is a Python standard, described in detail in [[PEP 333|http://www.python.org/dev/peps/pep-0333/]]."

WSGI is useful to TiddlyWeb for three reasons:
* It makes it easy to create web applications and services independent of the web server through which the services will run. This means it is easy to run simple servers for development and debugging as well as very powerful servers for high load situations.
* It makes it easy to layer web applications to add functionality that is decoupled.
* WSGI encourages the development of highly transparent services.

A WSGI application is identified by the signature of a function or class and the contract of its return value. A WSGI application is a {{{callable}}} that takes [[environ]] and [[start_response]] as arguments, returning an iterator.
Every [[instance]] may have a {{{tiddlywebconfig.py}}} located in the working directory of the instance. If [[twanager]] {{{instance}}} is used to create the instance, it will create a {{{tiddlywebconfig.py}}} for you.

The {{{tiddlywebconfig.py}}} contains information used to override the TiddlyWeb configuration defaults found in the {{{tiddlyweb.config}}} package. You can see more information about the keys of the configuration file:

{{{
    pydoc tiddlyweb.config
}}}

{{{tiddlywebconfig.py}}} is a Python module, containing a {{{dict}}}. At process startup its values are merged over the top of the default config.

In regular usage {{{tiddlywebconfig.py}}} is used to include [[plugins]] in your instance, set logging verbosity and control the CSS used on some pages.
Every [[instance]] has a {{{tiddlyweb.log}}} file. By default requests to the web application are logged to it. If {{{log_level}}} is changed in [[tiddlywebconfig.py]] more information will be written there. Try {{{DEBUG}}}.

The choices are: 'CRITICAL', 'DEBUG', 'ERROR', 'INFO', 'WARNING'.
<<list filter [tag[faq]]>>

If you have a question that you think might be a FAQ add a comment, and we'll see about finding the answer. //Thanks.//
"user" has a few meanings in TiddlyWeb:
* There is the [[User]] object in the TiddlyWeb data model which may be used in [[challengers|challenger]] and [[credentials extractors|credentials extractor]] to store and query password and [[role]] information.
* There is the current user, as indicated by [[tiddlyweb.usersign]] in the environment, which is used in [[authorization]].
* There are the "users", the people who use TiddlyWeb, i.e. //you//.
Development of TiddlyWeb is kept in the TiddlyWiki [[git]] repository, the core code can be found at:

> http://github.com/tiddlyweb/tiddlyweb
TiddlyWeb is available in a variety of forms. If you don't need the source, just want to run it, see [[Installing TiddlyWeb]].

If you want the source you can get it in three ways:
# Check it out from the [[source repository]].
# Get a tarball from [[pypi|http://pypi.python.org/pypi/tiddlyweb]].
# Get a tarball from http://tiddlyweb.peermore.com/dist/.

Learn about [[Developing With TiddlyWeb]].
The cachinghoster plugin replaces the default '/' URL handler with one that presents two different [[TiddlyWikis|TiddlyWiki]] depending on the status of the current user. If the user has a defined role, they get an editable wiki. Otherwise they get one that is read-only.

It is called //caching// hoster because the plugin maintains an on disk cache of the generated wiki so that it can serve the wiki as a static file or if the browser has seen the wiki before (and it has not changed) just send an {{{HTTP 304}}} response.

Find it at [[github|http://github.com/tiddlyweb/tiddlyweb-plugins]].

This is a fairly complex plugin which requires good understanding of TiddlyWeb, HTTP and Unix file handling concepts.
A configuration item that can be set in [[tiddlywebconfig.py]]. It is a list of modules (as [[plugins]]) to be imported when [[twanager]] starts up. Each module must have a method called {{init}} which may {{{pass}}} . To add a method to the [[twanager]] command list use [[@make_command]].

See also: [[Twanager Model]].
selector is the [[WSGI]] application used to dispatch web requests to specific [[handler]] code in TiddlyWeb. It is configured by the [[urls.map]].

selector was written by Luke Arno. It is a nice piece of work: simple yet powerful, focusing on one specific task and doing that task well. There is a [[web page for selector|http://lukearno.com/projects/selector/]].
This image (below) describes the default structure of TiddlyWeb's [[WSGI]] middleware. See [[Server Startup Model]] and [[Server Request Model]] for a bit more information. This illustration was taking from a [[blog posting on TiddlyWeb plugins|http://cdent.tumblr.com/post/55167654/tiddlyweb-plugins]].

[img[http://burningchrome.com/~cdent/images/tiddlywebstructure.png]]
Moved to [[serializer]].
[[Chris Dent's|ChrisDent]] usual handle for email, irc, etc.
If you wish to establish a [[role]] for a [[user]] of the TiddlyWeb system, you need to create or update a [[User]] in the datastore.

You may do this from the command line using the [[twanager]] [[adduser]] command. If you wish to make the changes using Python code, see [[How do I create or update a User object in code?]].

When you update an existing user from the command line it is just like creating the user anew. There is (as yet) no true update functionality. Because of this, when you add a role to an existing user (//from the command line//), you will be resetting their password.

To add a role to the user {{{barney}}} with password {{{dinosaur}}} and the roles {{{ADMIN}}} and {{{science}}} do the following:
{{{
twanager adduser barney dinosaur ADMIN science
}}}

If you are using [[OpenID]] or a similar service that uses it's own password or authentication mechanism but would like for the user to have roles in the [[datastore]] you may create an entry for the user with an empty password:
{{{
twanager adduser barney.example.com '' ADMIN science
}}}

See also:
* [[How do I add a user?]]
* [[How do I create or update a User object in code?]]
* [[May I edit the datastore by hand?]]
If you have the interest and skills you are welcome to edit the TiddlyWeb [[datastore]] by hand. The tools you will need to do so depend on the [[store]] you are using.

The text store that ships with TiddlyWeb is a collection of {{{UTF-8}}} encoded files in a directory hierarchy. Their format should be relatively straightforward.

If you choose to edit the datastore by hand you should be aware that this is quite likely to result in unpredictable HTTP caching behavior as revisions ids, modified times and the like are used for generating [[ETags|ETag]].
[[py.test|http://codespeak.net/py/dist/test.html]] is a simple but powerful tool for writing and running tests. [[cdent]] chose to use it for TiddlyWeb because ~PyUnit just seemed too crufty and noisy. Early code for TiddlyWeb was written test first and py.test made that a painless process.

You can get it from http://codespeak.net/py/dist/test.html where they have some [[quickstart instructions|http://codespeak.net/py/dist/test-quickstart.html]].

{{{
py.test -h
}}}
will reveal some help. {{{-x}}} and {{{-s}}} are useful.
[[httplib2|http://pypi.python.org/pypi/httplib2]] is a Python library for making HTTP requests and dealing with HTTP responses. It is //far// superior to urllib, urllib2 and httplib in that it provides a sensible API that is more comprehensive than any of the other http libraries.

It is used in the TiddlyWeb tests that test the [[HTTP API]] because we need to be able to easy called {{{PUT}}} and {{{DELETE}}} in addition to {{{GET}}} and {{{POST}}}, do correct redirect handling, and properly manage caches with [[ETags|ETag]].
{{{
from tiddlyweb.model.tiddler import Tiddler
from tiddlyweb.serializer import Serializer

tiddler = Tiddler(title)

serializer = Serializer("json")
serializer.object = tiddler
serializer.from_string(json_string)

serializer = Serializer("text")
serializer.object = tiddler
text_string = serializer.to_string()
}}}
''N.B.:'' Here {{{json_string}}} is expected to be a Unicode string (cf. [[Unicode Handling]]).
There are times when you might wish to retrieve a collection of tiddlers, including all their metadata and text. TiddlyWeb supports doing this when retrieving the JSON representation of a collection of tiddlers. Compare the output of the following two ~URLs:

http://tiddlyweb.peermore.com/wiki/bags/system/tiddlers.json

http://tiddlyweb.peermore.com/wiki/bags/system/tiddlers.json?fat=1

The first gets everything but the text of a tiddler. The second gets everything including the text.

For the time being the {{{fat}}} parameter only works with the JSON [[serialization]].
The new style of [[filters|filter]] are ''backwards incompatible'' with the old style. If you are using filters in your [[recipes|recipe]] or ~URLs, you need to change them to the new style. Here are some tips to help with the transition:

The old style filters were in one query parameter {{{filter=[tag[blog]][count[10]]}}}. The new style uses multiple parameters, [[select]], [[sort]] and [[limit]]. The equivalent new style filter is {{{select=tag:blog;limit=10}}}.

The old style select usually had a form of {{{[attribute[value]]}}} or just {{{value}}}. The new style is more explicit: {{{select=attribute:value}}}.

!!20 most recently modified blog tiddlers
''Old''
{{{
    filter=[tag[blog]][sort[-modified]][count[20]]
}}}
''New''
{{{
    select=tag:blog;sort=-modified;limit=20
}}}

!!Only Plugins
''Old''
{{{
    filter=[tag[systemConfig]]
}}}
''New''
{{{
    select=tag:systemConfig
}}}

!!Gotchas
The old style {{{filter=[tag[blog]][tag[publish]]}}} will get all tiddlers tagged {{{blog}}} or tagged {{publish}}}. There is no equivalent syntax in the the new style. {{{select=tag:blog;select=tag:publish}}} will get those tiddlers which tagged both {{{blog}}} AND {{{publish}}}. See [[mselect]] if you want something different.
pathinfohack is a [[plugin]] which modifies the [[WSGI]] environment so the {{{PATH_INFO}}} does not decode %2F in things like tiddler titles. Some servers, notably Apache, decode %2F making '/' in the names of TiddlyWeb entities impossible. pathinfohack gets around this.

It is available via PyPI as [[tiddlywebplugins.pathinfohack|http://pypi.python.org/pypi/tiddlywebplugins.pathinfohack]].
The ~URLs in the [[HTTP API]] grouped by the methods that work with each.

!GET
<<list  filter [tag[method:get]]>>

!PUT
<<list filter [tag[method:put]]>>

!POST
<<list filter [tag[method:post]]>>

!DELETE
<<list filter [tag[method:delete]]>>
The ~URLs in the [[HTTP API]] send and receive a variety of default representations, here they are group by representation:

! text/html
<<list filter [tag[rep:html]]>>

! text/plain
<<list filter [tag[rep:text]]>>

! text/x-tiddlywiki
<<list filter [tag[rep:wiki]]>>

! application/json
<<list filter [tag[rep:json]]>>
When the [[HTML representation|rep:html]] of a [[tiddler]] is requested, the wikitext of the tiddler is rendered, //serverside//, to HTML by a [[renderer]]. When wiki functionality is enabled, the code uses the [[wikklytextrender]] to create HTML by using [[wikklytext]]. Where possible wiki links in the tiddler are made to link to other tiddlers in the same [[bag]] or [[recipe]]. Some of the attributes of the tiddler are encoded into attributes on the div that contains the rendered HTML.
Bags can be created or updated over HTTP by using the [[HTTP API]] to access [[/bags/{bag_name}]] to send a {{{PUT}}} request containing a [[JSON bag]]. The content-type header must be set to {{{application/json}}}.

For a bag that already exists in the store, to make edits the [[current user]] must pass the manage [[constraint]] on the bag. To create a new bag, the current user must pass the [[bag_create_policy]].

See [[How can I use curl to create stuff in TiddlyWeb?]] for a simple example.
In TiddlyWeb a handler is the name used for a piece of code which is a [[WSGI]] application that responds to a web request made to a [[route]] listed in the [[urls.map]] or added via a [[plugin]]. A plugin may also replace an existing route with a new handler.

Handler code can interact with the [[store]] and available [[serializers|serializer]] return data directly or call other handlers.
"Spawning is a wsgi server which supports multiple processes, multiple threads, non-blocking HTTP io, and automatic graceful upgrading of code." -- [[pypi description of spawning|http://pypi.python.org/pypi/Spawning]]

TiddlyWeb can be run with spawning using a [[plugin]] called [[tiddlywebplugins.spawner|http://pypi.python.org/pypi/tiddlywebplugins.spawner]] that provides the {{{wsgi app factory}}} that spawning requires.
{{{
    spawn --factory=tiddlywebplugins.spawner.factory ''
}}}
No effort is made here to instruct you on how to install spwaning itself. Once you get past that point, all that's required is to create a TiddlyWeb [[instance]], install tiddlywebplugins.spawner, and run the above command (note the empty string argument). A server should start up.

//Note//: spawner is experimental and not fully featured, not all aspects of tiddlywebconfig are respected when the server starts, most importantly, server host and port settings. This will come. Please feel to make contributions to tiddlywebplugins.spawner if you find using TiddlyWeb with spawning an interesting thing.
[[wsgi_intercept|http://pypi.python.org/pypi/wsgi_intercept]] is a Python library that makes it possible to test WSGI applications without actually running a web server. This makes testing much simpler. Since TiddlyWeb's primary purpose is to provide an [[HTTP API]] it's useful to have simple HTTP tests.
{{{bag}}} is a [[twanager]] command that is used to create a [[bag]] from the command line. See [[How do I set or edit a bag policy?]].

If you want to create a bag with the default policy, and you are a POSIX platform, you can:
{{{
    twanager bag <bagname> </dev/null
}}}
Replacing {{{<bagname>}}} with the name of the bag.
An [[osmonaut|Osmosoft]] primarily responsible for the [[tiddlywebwiki]] package.

* [[website|http://fnd.lewcid.org]]
There are four basic types of //entities// in TiddlyWeb:
* [[tiddlers|tiddler]]
* [[bags|bag]]
* [[recipes|recipe]]
* [[users|user]]
Note: Since both bags and recipes represent collections of tiddlers, they are sometimes referred to as //containers//.

See also:
* [[Tidders, Bags and Recipes]]
A [[bag]] acts as a container for [[tiddlers|tiddler]]. As a container it provides several related functions:
* A bag provides a topical domain for the tiddlers. Tiddlers in bag X are related to some topic, concept, purpose, application, etc. For example all the tiddlers in the //teamtasks// bag are general data and code for running a teamtasks application whereas the tiddlers in the //notes// bag are random gatherings of tiddlers.
* A bag provides an [[authorization]] domain through the use of [[policies|policy]].
* A bag provides a building block for [[recipes|recipes]].

These functions are implemented at the level of the bag rather than the tiddler to make the functionality easier to manage on a few dimensions: in the minds of people using them, in application design, and in code.

It should be noted that a bag does not //have to// indicate any sense of topicality: it's a place to put things and there is no obligation that those things be the same in any particular way.
!Description
{{{tiddlywebplugins.status}}} is a plugin that adds a {{{/status}}} URL that returns a JSON hash of the current status of the server. At the moment this includes:
* {{{username}}}
** The name of the current active user.
* {{{version}}}
** The version of the running TiddlyWeb.
* {{{challengers}}}
** The available [[authentication]] [[challengers]] on the system.

It is available as a [[distribution|http://pypi.python.org/pypi/tiddlywebplugins.status]] on PyPI.
//work in progress//
* the basic architecture is predisposed to enabling anyone to use the resources at hand in any way imaginable (or even not yet imaginable) 
* first and foremost, [[recipes|recipe]], [[bags|bag]] and [[tiddlers|tiddler]] are for use by humans - which is why they have names rather than IDs
* this allows anyone to "make stuff" with the contents
* "anyone", here, is the guy on the street, the guy you never planned for

You can get a sense of this philosophy by reading the TiddlyWeb related [[blog posts|http://cdent.tumblr.com/tagged/tiddlyweb]] from ChrisDent.
This plugin uses [[Whoosh|http://whoosh.ca]], a Python indexing system, to provide search results and potentially accelerated filtering of TiddlyWeb content.

It is [[available|http://pypi.python.org/pypi/tiddlywebplugins.whoosher]] on PyPI.
Generally, good references on how to perform specific tasks are provided by the [[core code|http://github.com/tiddlyweb/tiddlyweb]] and its [[tests|http://github.com/tiddlyweb/tiddlyweb/tree/master/test/]] in particular. There is also a [[variety|http://github.com/search?q=tiddlyweb]] of [[plugins|http://github.com/tiddlyweb/tiddlyweb-plugins]] which can be consulted for guidance.

The [[pluginmaker]] may provide a good starting point for creating plugins.

!See Also
* [[Customizing TiddlyWeb]]
<<tagging dev>>
[[Python|http://www.python.org/]] is the programming language used to develop TiddlyWeb. It was chosen because it has a clean and clear syntax, has an excellent module system, a relatively good standard library, the [[WSGI|http://www.python.org/dev/peps/pep-0333/]] specification for web applications and is available on most modern platforms.

The features, combined, make Python an excellent choice for an application and library that is to be used as for reference and development.
TiddlyWiki is a wiki in a single HTML file, driven by javascript. It is very extensible with plugins, macros, and all sorts of interesting customizations.

* [[Home TiddlyWiki Web Site|http://www.tiddlywiki.com]]
* [[TiddlyWiki Documentation|http://www.tiddlywiki.org]]
If you have been granted access to edit this wiki you can login using the link below. If you think you should have access to edit but don't, see [[Getting Help]].

[[LOGIN|http://tiddlyweb.peermore.com/wiki/challenge]]
A Tiddler is the fundamental piece of content in a TiddlyWiki. You are reading a Tiddler right now. A Tiddler can contain human readable content, data, or javascript code that makes up a plugin, macro or command.

In basic TiddlyWiki Tiddlers are limited to living in the one HTML file that makes up the TiddlyWiki. With TiddlyWeb Tiddlers have broader scope:
* They have the option of travelling around the internet to be used by multiple people in different [[TiddlyWikis|TiddlyWiki]].
* They can contain any content at all. If you can represent it with a MIME type and a byte stream, you can put it in a tiddler in TiddlyWeb.
* They can be (re-)used in many contexts.
<<list filter [tag[howto]]>>
A configuration item that can be in [[tiddlywebconfig.py]]. It describes a URL path portion which is a prefix to every URL the system uses and produces. Use this to [[mount]] TiddlyWeb in a subdirectory such as {{{/wiki}}}. Default is the empty string.
The location of the empty TiddlyWiki that is used as the starting point for generating a wiki from TiddlyWeb.

See: [[How do I use a different empty.html?]]
An extension to TiddlyWeb that is not part of the core distribution. Useful for customizing or adding behavior.

See: [[Plugin List]] and [[Customizing TiddlyWeb]]
From http://json.org/

> JSON (JavaScript Object Notation) is a lightweight data-interchange format. It is easy for humans to read and write. It is easy for machines to parse and generate. It is based on a subset of the JavaScript Programming Language, Standard ~ECMA-262 3rd Edition - December 1999. JSON is a text format that is completely language independent but uses conventions that are familiar to programmers of the C-family of languages, including C, C++, C#, Java, JavaScript, Perl, Python, and many others. These properties make JSON an ideal data-interchange language.
mselect is a plugin that extends the [[filter]] syntax to allow a union of two or more [[select]] type filters in one filter step. This allows for union or multiple type selections. The following example will select those tiddlers which have tag {{{blog}}} OR tag {{{published}}} and then sort by {{{modified}}} time:
{{{
    mselect=tag:blog,tag:published;sort=-modified
}}}

It is available from PyPI as [[tiddlywebplugins.mselect|http://pypi.python.org/pypi/tiddlywebplugins.mselect]].
http://en.wikipedia.org/wiki/JavaScript

>JavaScript is a scripting language widely used for client-side web development. It was the originating dialect of the ~ECMAScript standard. It is a dynamic, weakly typed, prototype-based language with first-class functions. JavaScript was influenced by many languages and was designed to look like Java, but be easier for non-programmers to work with.
TiddlyWeb is in some sense very simple: it's a place where things called tiddlers are stored. However, in order to achieve flexibility across many dimensions it can be fairly complex to use to its maximum capability. The tiddlers linked from this one attempt to explain how TiddlyWeb does what it does, providing an overview with links to more details.

* [[Server Startup Model]]
* [[Server Request Model]]
* [[Twanager Model]]
* [[Auth Model]]
urls_map is the configuration setting which establishes what file to use for the [[urls.map]]. Generally it is easier to use [[plugins]] to extend the map, rather than replacing it.
Due to [[TiddlyWeb]]'s [[REST]]ful nature, there is not One True Client; any application which supports [[HTTP]] could potentially become a TiddlyWeb client. The most common client of TiddlyWeb is TiddlyWiki.
A vertical (sometimes called "adaptation") is a variant of [[TiddlyWeb]] created for a specific purpose.

Verticals usually consist of a certain configuration, set of plugins and/or client-side functionality.
Yet another [[OpenID]] for [[cdent]], who likes to experiment with open id delegation.

It also happens to be his [[personal homepage|http://burningchrome.com/]].
Wikipedia [[says|http://en.wikipedia.org/wiki/Openid]]:
> OpenID is an open, decentralized standard for user authentication and access control, allowing users to log onto many services with the same digital identity.

In TiddlyWeb, OpenID is one of the available [[challengers|challenger]].
Authentication is the process whereby we confirm that someone or something is who or what they claim to be, or more specifically some entity should be treated as being allowed to act as the someone or something.

To put it another way, authentication is a process in which we make sure someone is who they claim to be. In web services, this is usually done by something claiming they are a particular entity and then providing some piece of information to confirm (make authentic) their claim.

In TiddlyWeb authentication is done through a combination of a [[challenger]] and a [[credentials extractor]]. The challenger provides an initial interface through which a [[user]] can make and confirm their claim. A credentials extractor is then used to verify that claim in subsequent requests.
Authorization is the management of access control: who or what gets access to particular resources or information. The authorization process requires that the requesting entity be [[authentic|authentication]].

Except for two cases, authorization in TiddlyWeb is managed by [[policies|policy]].

The two exceptions are instances of the same problem: the creation of policies. This is controlled by configuration items: [[bag_create_policy]] and [[recipe_create_policy]].
Uppercase user refers a {{{tiddlyweb.model.user.User}}} object.

These are optional members of the TiddlyWeb datastore serving two independent functions:
* An [[authentication]] database for named users and their passwords.
* A database used in [[authorization]] for named users and their [[roles|role]]

See also:
* [[How do I add a user?]]
* [[How do I give a user a role?]]
In a [[plugin]] you can create or update a [[User]] object as follows:
{{{
    username = 'foo'
    password = 'monkey'
    roles = ['ADMIN', 'science']
    user = User(username)
    user.set_password(password)
    for role in roles:
        user.add_role(role)
    environ['tiddlyweb.store'].put(user)
}}}
The code assumes you have the necessary modules imported and that [[environ]] has been populated as expected in a WSGI application. See the [[Plugin List]] for links to existing plugins which have examples of some of the other ways to do this.

Note that there is no requirement for [[roles|role]] to be pre-existing. You can use any string you like. It is up to you to manage that.
The term //datastore// is used here to generically refer to where TiddlyWeb keeps its data and the data itself. //How// it keeps that data is handled by the [[store]].
[[YAML|http://yaml.org/]]
> YAML: YAML Ain't Markup Language
> What It Is: YAML is a human friendly data serialization standard for all programming languages.

YAML is used by at least one of the test files ({{{test_web_http_api.py}}}) in TiddlyWeb because it was a convenient way to serialize the tests themselves.

The Python package that is needed is called [[PyYAML|http://pypi.python.org/pypi/PyYAML]].
Of the [[Etag Header|http://en.wikipedia.org/wiki/HTTP_ETag]] Wikipedia says:
> An ETag (entity tag) is an HTTP response header returned by an HTTP/1.1 compliant web server used to determine change in content at a given URL. When a new HTTP response contains the same ETag as an older HTTP response, the contents are considered to be the same without further downloading. The header is useful for intermediary devices that perform caching, as well as for client web browsers that cache results. One method of generating the ETag is based on the last modified time of the file and the size of the file, another is using a checksum.

In TiddlyWeb an ETag header is produced when retrieving one or a collection of [[tiddlers|tiddler]]. That ETag is then used to do cache-validation or edit conflict handling. More details of how this works can be found in the [[HTTP specification|http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.19]].
An [[osmonaut|Osmosoft]] who got TiddlyWeb running [[Using CGI]].
He has also written some [[validators|validator]].

* [[blog|http://bengillies.net]]
With version 0.9.31 of TiddlyWeb a new style of filtering tiddlers was released. The previous version was based on a filtering syntax used in TiddlyWiki. That syntax proved to be less than satisfactory for TiddlyWeb. The new style is an improvement in several ways:
* The syntax is more compatible with ~URLs.
* The new syntax is easier to break down into independently readable sections, making overall readability and composability better.
* Similarly, because the the syntax is easier to break down, the code for parsing and assembling the filters is easier to write, test, extend and understand.
select is a type of [[filter]] used to select a subset of tiddlers from a collection of tiddlers. You may select by an attribute and some value of that attribute, in a few different forms. We'll use the example of tiddler modified time to expalin.

!Exact
{{{
    select=modified:20090509000000
}}}
This will get those tiddlers which have a modified time of //exactly// midnight at the start of May 9th, 2009.

!Negate
{{{
    select=modified:!20090509000000
}}}
This will get those tiddlers which have a modified time of any time except //exactly// midnight at the start of May 9th, 2009.


!Greater
{{{
    select=modified:>20090509000000
}}}
This will get those tiddlers which have a modified time newer than (greater than, exclusive) midnight at the start of May 9th, 2009.

!Lesser
{{{
    select=modified:<20090509000000
}}}
This will get those tiddlers which have a modified time older than (greater than, exclusive) midnight at the start of May 9th, 2009.

When performing comparisons (i.e. using < or >) TiddlyWeb will canonicalize the attribute to an appropriate form based on (the extensible) {{{ATTRIBUTE_SORT_KEY}}} in {{{tiddlyweb.filters.sort}}}.
env is a [[plugin]] that displays the [[WSGI]] environment of the current request. This can be quite illuminating to display how TiddlyWeb works and how various query parameters and HTTP headers impact the request. Useful for debugging and learning.

The code can be found at [[github|http://github.com/tiddlyweb/tiddlyweb-plugins/tree/master/env]].
When a [[recipe]] is GET or PUT as [[JSON]] the following form is used:
{{{
{
    "recipe": [
        ["bag name 1", "select=tag:blog"],
        ["bag name 2", ""]
    ],
    "policy": {
        "read": [], 
        "write": [],
        "create": [],
        "delete": [],
        "manage": [],
        "owner": ''
    },
    "desc": "optional description of the bag (may be an empty string or absent)",
}
}}}
A plugin which enables support for handling "tunneled" HTTP methods.

Some browsers are unable to perform PUT or DELETE. In these situations it is necessary to send a POST request and tunnel the desired method through a HTTP header ({{{X-HTTP-Method}}}) or URL query ({{{http_method}}}) parameter. Client side changes are required to do this.

{{{methodhack}}} provides serverside [[WSGI]] middleware to process the tunneling.

Find it at: http://github.com/tiddlyweb/tiddlyweb-plugins/tree/master/methodhack
wikklytext is a Python library that provides a variety of tools for dealing with TiddlyWiki content. It is able to render wikitext to XML and HTML and run a serverside wiki which can store content in a TiddlyWiki file.

http://wikklytext.com/
When a [[tiddler]] is retrieved using a [[text representation|rep:text]] it is presented as a UTF-8 encode text/plain file with two sections. The sections are separated by a blank line. The first section makes up headers in a format similar to an [[RFC 822|http://www.faqs.org/rfcs/rfc822.html]] mail message:
{{{
    key: value
}}}
Each key represents an attribute on the tiddler, or an extended field.

The second section, the body, is the wikitext of the tiddler. In the case of a [[binary tiddler]] this will be base64 encoded text.
A [[tiddler]] can be created or updated over HTTP by using the [[HTTP API]] to access [[/bags/{bag_name}/tiddlers/{tiddler_title}]] and sending a {{{PUT}}} request containing a [[JSON tiddler]]. The content-type header must be set to {{{application/json}}}.

For a tiddler that already exists in the store, to make edits the [[current user]] must pass the edit [[constraint]] on the bag. To create a new tiddler, the current user must pass the create constraint.

See [[How can I use curl to create stuff in TiddlyWeb?]] for a simple example.
When using servers that are on an intranet or set up "in the cloud", such as on EC2, it is often the case that the hostname and IP number of the machine, internal to itself, is different from the hostname and IP number used to reach services on the machine from outside.

TiddlyWeb uses hostname and port number information to handle the creation of ~URLs in redirects and information used in the dynamically generated TiddlyWiki files for enabling save back to the server. To set these things adjust the [[server_host]] [[config]] setting in [[tiddlywebconfig.py]].

When you do this on a machine with different internal and external hostnames, you need to use the external hostname, however you may see errors such as
{{{
    socket.error: (99, 'Cannot assign requested address')
}}}
because the external hostname or IP number is not valid for the local interface. To get around this you need to add the external hostname as an alias for the local host. On Unix-like machines this means adding to {{{/etc/hosts}}}.
A [[config]] setting which declares who or what is able to create a [[recipe]] on the system. Since [[policies|policy]] are associated with existing recipes, we need a separate mechanism for controlling creation. The {{{recipe_create_policy}}} does this. It's default value is an empty string, which means anyone can create a new recipe via a {{{PUT}}} to [[/recipes/{recipe_name}]]. Other options are:
;{{{ANY}}}
:Any [[authenticated|authentication]] user may create a recipe.
;{{{ADMIN}}}
:Any user with the {{{ADMIN}}} [[role]] may create a recipe.

Other options are possible by overriding existing code.
> SQLAlchemy is the Python SQL toolkit and Object Relational Mapper that gives application developers the full power and flexibility of SQL.

http://www.sqlalchemy.org/
The formeditor [[plugin]] provides a quick solution for editing a single [[tiddler]] when you visit the HTML representation of that tiddler. It adds an {{{FormEdit}}} link to the page, which points to a page that present a simple textarea in which you can edit the text (but not yet tags) for the tiddler.

The code can be found at [[github|http://github.com/tiddlyweb/tiddlyweb-plugins]].
{{{info}}} is a [[twanager]] command that provides a small amount of information about the current TiddlyWeb installation. Here's the output for this server as of early July 2009:
{{{
This is TiddlyWeb version 0.9.44.
The current store is: caching.
}}}
The primary purpose of {{{info}}} is so you can easily determine what version is being run.
[[TiddlyWeb Documentation]]
[[Downloads]]
[[Glossary]]
[[Howtos]]
[[Plugin List]]
[[FAQ]]
[[API]]
[[Login]]
[[Colophon]]
[[Known Issues]]
tiddlywebwiki is a Python package that provides the TiddlyWeb service. It is made up of some Python code and pointers to other packages on which it depends. See [[Installing TiddlyWeb]].

tiddlywebwiki depends on the [[tiddlyweb]] package. The latter package provides the base functionality and may be installed independently if TiddlyWiki functionality is not required.
!!Description
Given the knowns of a [[recipe]] and a [[tiddler]], determine the [[bag]] which is where the tiddler came from. Generally done to determine what bag we need to load from the [[store]] to (eventually) get the tiddler.

!!Parameters
* [[recipe]]
* [[tiddler]]
* //[[environ]]=None//

!!Returns
* [[bag]]

Raises {{{NoBagError}}} if no bag containing the tiddler can be determined.

!!Example
{{{
    tiddler = Tiddler('somename')
    recipe = Recipe('foobar')
    recipe = store.get(recipe)
    bag = control.determine_tiddler_bag_from_recipe(recipe, tiddler)
}}}

!!Notes
This code is used when getting or deleting a tiddler via a recipe-based URL. When putting a tiddler via a recipe-based URL [[control.determine_bag_for_tiddler]] is used.

If an {{{environ}}} parameter is provided this is assumed to be a {{{dict}}} which is the [[WSGI]] [[environ]]. It is used to process the {{{_recipe_template}}} (see the [[source|source repository]] for details).
!!Description
Yield the fully instantiated (i.e. read from the store) tiddlers that are in this bag. It is assumed that the bag already has un-instantiated tiddlers in it, either by being read from the store itself, or through earlier code.

!!Parameters
* [[bag]]

!!Returns
* Python generator yielding [[tiddler]] objects.

!!Example
{{{
    bag = Bag('somebag')
    bag = store.get(bag)
    for tiddler in control.get_tiddlers_from_bag(bag):
        print tiddler.title, tiddler.tags
}}}

!!Notes
!!Description
Take a string in the form of a CGI query string and parse it for [[filters|filter]], returning filter functions and any remaining query parameters. This is usually used in WSGI middleware to parse filters from ~URLs, but may also be used in plugin code to generate filters from strings.

!!Parameters
* query_string

!!Returns
* list of [[filters|filter]]
* string of remaining query parameters

!!Example
{{{
    filters, leftovers = parse_for_filters('select=tag:systemConfig;fat=1')
}}}

!!Notes
[[store]] implementation to simplify client-side development

available [[via PyPI|http://pypi.python.org/pypi/tiddlywebplugins.devstore]] ({{{$ pip install -U tiddlywebplugins.devstore}}})
source [[on GitHub|http://github.com/FND/tiddlyweb-plugins/tree/master/devstore]]
pip is an install tool for Python, similar to but more modern than [[easy_install]]. It is now the preferred tool for install TiddlyWeb and associated [[plugins]] because it is deals better with namespace packages and resolving requirements.

See: http://pypi.python.org/pypi/pip

If pip is not available on your system it can be installed following instructions at the link above, or if you are an working {{{easy_install}}}:
{{{
   sudo easy_install -U pip
}}}

pip and [[virtualenv]] make is possible to install TiddlyWeb without root access.
<<list filter [tag[glossary]]>>
An [[OpenID]] of ChrisDent.
In [[WSGI]] an application is "mounted" by a web server at specific location in the url space of the web server. This means that requests to that url and anything within or below it will be handled by the WSGI application.
TiddlyWeb is licensed under the [[BSD License|http://opensource.org/licenses/bsd-license.php]].
Configuration settings that can be set or modified in [[tiddlywebconfig.py]].
A term used to describe the process by which a recipe is processed to result in one of the following:

* On a {{{GET}}} request: A list of tiddlers from one or more filtered bags, wherein a [[tiddler]] with the same name found later in the processing will replace the earlier with the same name.
* On a {{{PUT}}} request: A bag to which this tiddler can be saved after processing the recipe in reverse, choosing the first bag+filter combination that will allow the tiddler into the bag.

This cascade process is similar to CSS inheritance or the way in which shadow tiddlers can be overridden in TiddlyWiki.
sort is a type of [[filter]] used to order a collection of tiddlers by some attribute shared by those tiddlers. The basic syntax is {{{sort=attribute}}}. If attribute is prepended with {{{-}}} the sort is reversed.

!Example
Sort all the tiddlers by modified time oldest to newest:
{{{
    sort=modified
}}}
An [[OpenID]] of ChrisDent.
[[Twanager|twanager]] is the command line tool that comes with TiddlyWeb. It is used to administer your [[instance]] from the server. It can be extended with [[plugins]].

When twanager is run, the following process is followed:

* Check for [[twanager_plugins]]. Import the listed modules, if any.
* Assemble of a list of commands via [[@make_command]]
* The first argument to twanager is compared against the list of commands. If there, a corresponding method is run, passed the remaining arguments.
* That method can do whatever it wants. Exceptions are passed up to the user.
When TiddlyWeb receives an HTTP request, the request is processes through several stages before content is handled or produced. Once a response is ready, the response is also processed through several stages.

* Request
** The request is received and processed by the [[WSGI]] applications in [[server_request_filters]] until it arrives at [[selector]].
** The selector application uses [[urls.map]] to determine what TiddlyWeb method (either in the {{{tiddlyweb.web.handler}}} package or a plugin) should handle it.
* Handling
** Each handler method performs the requested action, using the provided [[environ]] to determine the details of the action. The action usually involves getting or putting something to or from the [[store]], transforming the content, as required, with a [[serializer]].
** The handler establishes the headers of a response with [[start_response]] and returns some content as an iterator.
** If there have been any uncaught exceptions during the request, they are caught by the [[PermissionsExceptor]] or [[HTTPExceptor]].
* Response
** The response is processed by the [[server_response_filters]].
** The response is finally given to the controlling web server.
{{{server_response_filters}}} is a configuration item that controls which [[WSGI]] applications a response is processed //through// after being handled by the core of the TiddlyWeb code. The {{{server_response_filters}}} are used to modify the headers or content of the response, log some information, or handle unusual situations appropriately.

Any [[instance]] may add or remove filters, but in practice this has proven rare.

The default response filters, in chronological order of use, are:
# [[HTMLPresenter]]
# [[PermissionsExceptor]]
# [[HTTPExceptor]]
# [[EncodeUTF8]]
# [[SimpleLog]]
UserExtract is the [[WSGI]] application which manages the [[credentials extractor]] subsystem.

Every incoming request passes through UserExtract which in turn passes the request through one or more configured credentials extractors. These look for user information in the request and attempt to validate it. If valid the information is used to set [[tiddlyweb.usersign]] in the environment. If the extractor finds no valid information it returns {{{False}}} and the next extractor is tried. If no extractor finds valid information, {{{tidddlyweb.usersign}}} is set to {{{GUEST}}}.
A role is an attribute of a [[User]] (see also [[user]] for disambiguation) that signifies some right or responsibility the user has. A role shows up in three places in TiddlyWeb:

* As a list in the [[tiddlyweb.usersign]] hash.
* As a list on the [[User]] entity.
* As part of a [[policy]].

A role is similar to a group, but the association is reversed. Whereas a group has a list of members (the users who are in the group), a user has one or more roles. In real world use the latter turns out to be a bit easier to manage (at least for the TiddlyWeb context). See [[I'm running a TiddlyWeb with lots of users and bags. How do I manage access control?]] for more information.
{{{tiddlyweb.usersign}}} is a member of the [[environ]] value that is passed around all the [[WSGI]] code in TiddlyWeb. It contains information about the current [[user]] as determined by the [[credentials extractor]] system. The data is passed to a [[policy]] when it is checked.

There are two elements in the data structure:
* ''name'': A string representing the  identity of the current user. If no user was extracted this will be {{{GUEST}}}. It should never be empty.
* ''roles'': A list of strings of [[roles|role]]. This may be a zero length list.

The name {{{usersign}}} is used because there's nothing preventing the user from having an identifier which bears no resemblance to a name.
http://code.google.com/appengine/

"Run your web apps on Google's infrastructure."
http://www.cherrypy.org/:
> CherryPy is a pythonic, object-oriented HTTP framework.
[[Osmosoft|http://www.osmosoft.com/]]
In the TiddlyWeb context, the current user is the identifier of the already [[authenticated|authentication]] user which will be used in any [[authorization]] that needs to occur during the current request. The current user is determined by the [[credentials extractor]] system. If the extractor extracts no user, the current user is guaranteed to be {{{GUEST}}}.

The current user concept is only present during HTTP requests.
{{{server_store}}} is a configuration item that controls which [[store]] this TiddlyWeb [[instance]] uses. The setting is a two item list.

The first element of the list is a string representing the name of a module which implements the [[StorageInterface]]. The module is first looked up in the {{{tiddlyweb.stores}}} package space and if not found there, {{{sys.path}}} is followed.

The second element of the list is a {{{dict}}} containing configuration needed by the store, for example paths or database names. The dict may be empty. It is also possible to use other, arbitrary, configuration elements.

The default setting for {{{server_store}}} is:
{{{
        'server_store': ['text', {'store_root': 'store'}],
}}}
curl is a command line tool available for many systems that allows the user to make HTTP requests from the command line.

See: http://curl.haxx.se/
{{{auth_systems}}} is a configuration setting that controls which [[challengers|challenger]] are available to this TiddlyWeb [[instance]]. It is a list of strings with each string representing the name of a module that implements the [[ChallengerInterface]]. The name is first looked up in the {{{tiddlyweb.web.challengers}}} package space. If not found there, {{{sys.path}}} is searched.

If there is only one [[challenger]] configured a request that redirects to the challenger system will go directly to that challenger. If there are multiple challengers configured the user will be presented with a list of choices.
wget is a command line tool available for many systems that allows the user to make HTTP requests from the command line.

See: http://www.gnu.org/software/wget/
Oh hi. I have a slash!
limit is a type of [[filter]] used to lessen a collection of tiddlers to a smaller number, either from the front of the list, or some range within. The syntax takes two forms:
{{{
    limit=<count>
    limit=<index>,<count>
}}}

!Example
Get the 10 most recently modified tiddlers:
{{{
    sort=-modified;limit=10
}}}
Get the 2nd, 3rd, and 4th tiddlers:
{{{
    sort=-modified;limit=1,3
}}}
(Index starts at 0, in keeping with programming arrays.)
[[HTTP API]] ~URLs that return an HTML [[representation]].
Those [[HTTP API]] ~URLs which are capable for working with a text/plain [[representation]].
Recipes can be created or updated over HTTP by using the [[HTTP API]] to access [[/recipes/{recipe_name}]] to send a {{{PUT}}} request containing a [[JSON recipe]]. The content-type header must be set to {{{application/json}}}.

For a recipe that already exists in the store, to make edits the [[current user]] must pass the manage [[constraint]] on the recipe. To create a new recipe, the current user must pass the [[recipe_create_policy]].

See [[How can I use curl to create stuff in TiddlyWeb?]] for a simple example.
Which [[challlengers|challenger]] are presented to the user when an authenticated user is required is controlled by the [[auth_systems]] [[config]] item. This is a list of modules which are challengers. To change, set {{{auth_systems}}} in [[tiddlywebconfig.py]]:
{{{
config = {
    'auth_systems': ['openid'],
}
}}}
If there is only one challenger listed, when a challenge happens, the system will automatically redirect to that challenger. Otherwise, a list of the available challengers will be presented.
TiddlyWeb will produce more information in [[tiddlyweb.log]] if you change or set the [[log_level]] config setting in [[tiddlywebconfig.py]]. 'DEBUG' is a common setting:
{{{
config = {
    'log_level': 'DEBUG',
}
}}}
A [[config]] setting which declares who or what is able to create a [[bag]] on the system. Since [[policies|policy]] are associated with existing bags, we need a separate mechanism for controlling creation. The {{{bag_create_policy}}} does this. It's default value is an empty string, which means anyone can create a new bag via a {{{PUT}}} to [[/bags/{bag_name}]]. Other options are:
;{{{ANY}}}
:Any [[authenticated|authentication]] user may create a bag.
;{{{ADMIN}}}
:Any user with the {{{ADMIN}}} [[role]] may create a bag.

Other options are possible by overriding existing code.
gzipper is TiddlyWeb plugin providing [[WSGI]] middleware for compressing web responses with gzip if the requesting user-agent supports it. In some situations this can speed up the apparent responsiveness of the system at the cost of some CPU use on both sides of the transaction. When sending text based content like a TiddlyWiki, the level of compression can be significant.

If compression is desired for a TiddlyWeb instance, using compression support from the hosting web server (e.g. Apache) is probably better than using gzipper. However if you are using the built in server, gzipper will do the job. Use it by adding {{{gzipper}}} to [[system_plugins]] in [[tiddlywebconfig.py]].

The plugin code can be found at [[github|http://github.com/tiddlyweb/tiddlyweb-plugins/tree/master/gzipper]].
sqlstore provides an RDBMS-based StorageInterface implementation for TiddlyWeb using SQLAlchemy. By using SQLAlchemy, the same code can be used to store data in many different systems. Tested so far are:

* sqlite3
* Mysql
* PostgreSQL

The [[store]] has not been extensively tested in production yet, so you should be careful when using it with delicate data. If you have existing TiddlyWeb content that you would like to migrate to the sql store, you might investigate the [[migrate]] plugin.

The code, with instructions, can be [[found on github|http://github.com/tiddlyweb/tiddlyweb-plugins/tree/master/sqlstore]].
Methods in the [[HTTP API]] which respond to the request method {{{PUT}}}.
When [[deleting|HTTP API by method]] a [[tiddler]] in [[TiddlyWeb]], this by default (depending on the [[store]]) leaves no traces allowing the tiddler to be restored.

Such functionality (e.g. trash can / recycle bin) is to be handled at the application level.
Note that there are possible implications on [[access control|policy]] when moving tiddlers between bags. 
A [[twanager]] command that adds a user to the [[store]], creating the user, setting their password and optionally setting their roles. If {{{adduser}}} is used again on the same username, the existing user is clobbered. To update an existing user use [[addrole]] and [[userpass]].

!Syntax
{{{
    twanager adduser <username> <password> [[role] [role] ...]
}}}

!Example
Create the user monkey with password oog, and roles tail and fruit.
{{{
    twanager adduser monkey oog tail fruit
}}}
A [[twanager]] command the adds one or more [[roles|role]] to an existing [[user]]. If the user does not exist an exception is raised. To create a user use [[adduser]].

!Syntax
{{{
    twanager addrole <username> [role] [[role] [role] ...]
}}}

!Example
Add the role mammal to the user monkey.
{{{
    twanager addrole monkey mammal
}}}
A [[twanager]] command that resets the password for an existing [[user]] in the [[store]]. If the user does not exist an exception is raised. To create a user use [[adduser]]. There are no restrictions (from the admin) level on what a password may contain. Any particular [[instance]] may wish to set their only policies on such things.

!Syntax
{{{
    twanager userpass <username> <password>
}}}

!Example
Set the user monkey's password to sw!ng3r
{{{
    twanager userpass monkey 'sw!ng3r'
}}}
A plugin used to [[render|renderer]] TiddlyWiki syntax text to HTML, using the [[wikklytext]] Python module.

Find it on [[github|http://github.com/tiddlyweb/tiddlyweb-plugins/blob/master/wikklytextrender]]
* [[Overview]]
* [[Getting Help]]
* [[Installing TiddlyWeb]]
* [[Using TiddlyWeb]]
* [[Customizing TiddlyWeb]]
* [[Developing With TiddlyWeb]]
* [[Theory of Operation]]
* [[Lego Pieces Model]]
* [[Features]]
* [[Credits]]
{{{
query = environ["tiddlyweb.query"]
param = query.get("foo", [None])[0]
}}}
In TiddlyWiki parlance, a server side is a web-based service that provided storage of TiddlyWiki data on a web server so that it can be access from multiple client machines and potentially multiple users.

There are several different server sides for TiddlyWiki. Some store entire TiddlyWikis as the addressable unit, others store [[tiddlers|tiddler]] as the addressable unit. TiddlyWeb is the latter type.
/***
|''Name''|TiddlyReconMacro|
|''Description''|TiddlyWeb data explorer|
|''Author''|FND|
|''Source''|http://tiddlyweb.com|
|''CodeRepository''|http://github.com/FND/tiddlyrecon|
|''License''|[[BSD|http://www.opensource.org/licenses/bsd-license.php]]|
|''CoreVersion''|2.5|
!Usage
{{{
<<TiddlyRecon [host]>>
}}}
!Code
***/
//{{{
/*
 * TiddlyWeb adaptor
 *
 * TODO:
 * * error handling in callbacks
 */

var tiddlyweb = {
	host: "" // defaults to current domain -- XXX: lacks server_prefix -- TODO: document; expects no trailing slash
};

(function($) {

$.extend(tiddlyweb, {
	/*
	 * container has members type ("bag" or "recipe") and name
	 * callback is passed data, status and error (if applicable)
	 * see jQuery.ajax for details
	 */
	loadTiddlers: function(container, callback) {
		var uri = "/" + container.type + "s/" +
			encodeURIComponent(container.name) + "/tiddlers"
		callback = callback || console.log; // XXX: DEBUG
		this.loadData(uri, callback);
	},

	/*
	 * callback is passed data, status and error (if applicable)
	 * see jQuery.ajax for details
	 */
	loadTiddler: function(title, container, callback) {
		var uri = "/" + container.type + "s/" +
			encodeURIComponent(container.name) + "/tiddlers/" +
			encodeURIComponent(title)
		callback = callback || console.log; // XXX: DEBUG
		this.loadData(uri, callback);
	},

	/*
	 * callback is passed data, status and error (if applicable)
	 * see jQuery.ajax for details
	 */
	loadBags: function(callback) {
		var uri = "/bags";
		callback = callback || console.log; // XXX: DEBUG
		this.loadData(uri, callback);
	},

	/*
	 * callback is passed data, status and error (if applicable)
	 * see jQuery.ajax for details
	 */
	loadBag: function(name, callback) {
		var uri = "/bags/" + encodeURIComponent(name);
		callback = callback || console.log; // XXX: DEBUG
		this.loadData(uri, callback);
	},

	/*
	 * callback is passed data, status and error (if applicable)
	 * see jQuery.ajax for details
	 */
	loadRecipes: function(callback) {
		var uri = "/recipes";
		callback = callback || console.log; // XXX: DEBUG
		this.loadData(uri, callback);
	},

	/*
	 * callback is passed data, status and error (if applicable)
	 * see jQuery.ajax for details
	 */
	loadRecipe: function(name, callback) {
		var uri = "/recipes/" + encodeURIComponent(name);
		callback = callback || console.log; // XXX: DEBUG
		this.loadData(uri, callback);
	},

	/*
	 * policy is an object with members write, create, delete, manage and accept,
	 * each an array of users/roles
	 */
	saveBag: function(name, policy) {
		var uri = "/bags/" + encodeURIComponent(name);
		var data = {
			policy: policy
		};
		this.saveData(uri, data, console.log);
	},

	/*
	 * bags is an array of bag names
	 * filters currently unsupported
	 */
	saveRecipe: function(name, bags) {
		var uri = "/recipes/" + encodeURIComponent(name);
		var data = {};
		this.saveData(uri, data, console.log);
	},

	// generic utility methods

	loadData: function(uri, callback) {
		localAjax({
			url: this.host + uri,
			type: "GET",
			dataType: "json",
			success: callback,
			error: callback
		});
	},

	saveData: function(uri, data, callback) {
		localAjax({
			url: this.host + uri,
			type: "PUT",
			dataType: "json",
			data: $.toJSON(data),
			complete: callback
		});
	}
});

/*
 * enable AJAX calls from a local file
 * triggers regular jQuery.ajax call after requesting enhanced privileges
 */
var localAjax = function(args) { // XXX: not required!?
	if(document.location.protocol.indexOf("file") == 0 && window.Components &&
		window.netscape && window.netscape.security) {
		window.netscape.security.PrivilegeManager.
			enablePrivilege("UniversalBrowserRead");
	}
	return jQuery.ajax(args);
};

})(jQuery);
(function() {

var $ = jQuery;
var tw = tiddlyweb; // TODO: chrjs should provide an instance

$.TiddlyRecon = function(root, host) {
	tw.host = host;
	$.TiddlyRecon.root = $(root).empty(); // XXX: singleton, bad
	notify("loading status");
	loadStatus();
	notify("loading recipes");
	tw.loadRecipes(populateRecipes);
};

// display status
var loadStatus = function() {
	var container = $('<dl id="status" />').hide().appendTo($.TiddlyRecon.root);
	var populateStatus = function(data, status, error) {
		container.
			append("<dt>user</dt>\n").
			create("<dd />\n").text(data.username).end().
			append("<dt>server</dt>\n").
			create("<dd />\n").
				create("<a />").attr("href", tw.host).text(tw.host).end().
				end().
			show();
	};
	tw.loadData("/status", populateStatus);
};

// list recipes
var populateRecipes = function(data, status, error) {
	notify("populating recipes");

	$('<div id="recipes" class="collection container" />').
		append("<h2>Recipes</h2>").
		create('<ul class="listing" />').
			create("<li><i>(none)</i></li>").click(loadRecipe).end().
			append($.map(data, function(item, i) {
				return $("<li />").text(item).click(loadRecipe)[0];
			})).
			end().
		appendTo($.TiddlyRecon.root);
};

// display recipe
var loadRecipe = function(ev) {
	var recipe_node = $(this);
	setActive(recipe_node);
	var recipe_name = recipe_node.text(); // TODO: special handling for "(none)";
	notify("loading recipe", recipe_name);

	var recipe_container = recipe_node.parent().parent(). // XXX: simpler way to do this?
		find("#recipe").remove().end(). // clear existing selection -- TODO: allow for multiple recipes?
		create('<div id="recipe" class="entity" />').
			create("<h3 />").text(recipe_name).end();

	var callback = function(data, status, error) {
		populateBags(recipe_container, data, status, error);
	};
	tw.loadRecipe(recipe_name, callback);
};

// list bags
var populateBags = function(container, data, status, error) {
	notify("populating bags");

	$('<div id="bags" class="collection container" />').
		append("<h2>Bags</h2>").
		create('<ul class="listing" />').
			create("<li><i>(all)</i></li>").click(loadBag).end().
			append($.map(data.recipe, function(item, i) {
				var bag_name = item[0];
				var filter = item[1] || "(none)"; // XXX: bad default
				return $("<li />").text(bag_name).attr("title", filter).click(loadBag)[0]; // XXX: using title to retain filter is hacky
			})).
			end().
		appendTo(container);
};

// display bag
var loadBag = function(ev) {
	var bag_node = $(this);
	setActive(bag_node);
	var bag_name = bag_node.text(); // TODO: special handling for "(all)";
	notify("loading bag", bag_name);

	var bag_container = bag_node.parent().parent(). // XXX: simpler way to do this?
		find("#bag").remove().end(). // clear existing selection -- TODO: allow for multiple bags?
		create('<div id="bag" class="entity" />').
			create("<h3 />").text(bag_name).end();

	var callback = function(data, status, error) {
		populateTiddlers(bag_container, data, status, error);
	};
	var container = {
		type: "bag",
		name: bag_name
	};
	tw.loadTiddlers(container, callback);
};

var populateTiddlers = function(container, data, status, error) {
	notify("populating tiddlers");

	$('<div id="tiddlers" class="collection" />').
		append("<h2>Tiddlers</h2>").
		create('<ul class="listing" />').
			append($.map(data, function(item, i) {
				return $("<li />").text(item.title).attr("title", item.bag).click(loadTiddler)[0]; // XXX: using title to retain bag is hacky
			})).
			end().
		appendTo(container);
};

var loadTiddler = function(ev) {
	var tiddler_node = $(this);
	setActive(tiddler_node);
	var title = tiddler_node.text();
	var bag = tiddler_node.attr("title");
	notify("loading tiddler", title, bag);

	var tiddler_container = tiddler_node.parent().parent(). // XXX: simpler way to do this?
		find("#tiddler").remove().end(). // clear existing selection -- TODO: allow for multiple bags?
		create('<div id="tiddler" class="entity" />').
			create("<h3 />").text(title).end();

	var callback = function(data, status, error) {
		populateTiddler(tiddler_container, data, status, error);
	};
	var container = {
		type: "bag",
		name: bag
	};
	tw.loadTiddler(title, container, callback);
};

var populateTiddler = function(container, data, status, error) {
	notify("populating tiddler");

	$('<div class="content" />').text(data.text).appendTo(container); // XXX: request wikified text!?
};

var setActive = function(node) {
	node.siblings().removeClass("active");
	node.addClass("active");
};

// utility functions -- TODO: move into separate module

var notify = function(msg) { // TODO: use jQuery.notify
	// XXX: DEBUG
	if(window.console && console.log) {
		console.log("notify:", msg);
	}
};

// utility method to create and then select elements
// in combination with jQuery's end method, this is generally useful for
// dynamically generating nested elements within a chain of operations
$.fn.create = function(html) {
	return this.append(html).children(":last");
};

})();
tiddlyweb.host = "http://tiddlyweb.peermore.com/wiki";
/*
 * TiddlyWiki macro wrapper and backstage integration
 */

config.macros.TiddlyRecon = {
	handler: function(place, macroName, params, wikifier, paramString, tiddler) {
		var host = params[0] || config.defaultCustomFields["server.host"];
		jQuery.TiddlyRecon(place, host);
	}
};

config.tasks.server = {
	text: "server",
	tooltip: "TiddlyWeb",
	content: "<<TiddlyRecon>>"
};
config.backstageTasks.push("server");
//}}}
Methods and functions of the [[Python API]].
!!Description
Determine which bag in a recipe a tiddler could be saved into.

!!Parameters
* [[recipe]]
* [[tiddler]]
* //[[environ]]=None//

!!Returns
* bag

Raises {{{NoBagError}}} if no bag can be found.

!!Example
{{{
    tiddler = Tiddler('somename')
    recipe = Recipe('foobar')
    recipe = store.get(recipe)
    bag = control.determine_bag_for_tiddler(recipe, tiddler)
}}}

!!Notes
This is primarily used when putting a tiddler to recipe-based URL (which doesn't happen a lot, you should PUT a tiddler to a bag-based URL). Generally, unless the last bag in the recipe has a filter on it, the last bag is what will be returned from this method.

If an {{{environ}}} parameter is provided this is assumed to be a {{{dict}}} which is the [[WSGI]] [[environ]]. It is used to process the {{{_recipe_template}}} (see the [[source|source repository]] for details).
!!Description
Yield the [[tiddlers|tiddler]] which result from filtering the provide [[bag]] against the provided [[filters|filter]].

!!Parameters
* [[bag]]
* filters, either as filter string or a list of [[filter]] methods

!!Returns
* Python generator yielding [[tiddler]] objects.

!!Example
{{{
    # get those tiddlers in somebag which are tagged systemConfig
    bag = Bag('somebag')
    bag = store.get(bag)
    for tiddler in control.filter_tiddlers_from_bag(bag, 'select=tag:systemConfig')
        print tiddler.title
}}}

!!Notes
When {{{bag.store}}} is set, this function will read the tiddlers in the bag from the store. If {{{bag.store}}} is not set, it is assumed that the tiddlers are either already read or for some reason you don't want to use the fully instantiated tiddlers from filtering. Make sure you are conscious of this distinction.
!!Description
Read a utf-8 encoded file from disk, returning a unicode string.

!!Parameters
* filename

!!Returns
* unicode
!!Description
Write a unicode string to disk, utf-8 encoded.

!!Parameters
* filename
* content

!!Returns
* void
!!Description
Create an advisory lock file, containing the pid of the current process. The lock file's name will be the name of the file being locked with a '.' prepended.

!!Parameters
* filename (of the file being locked)

!!Returns
* None

!!Example
See the TiddlyWeb text [[store]] for details.

!!Notes
This is used by the text store to prevent concurrent writes to the same tiddler (to preserve revision handling).
!!Description
Unlock, without consideration, the lock created [[util.write_lock]] on the same filename.

!!Parameters
* filename

!!Returns
* None

!!Example
See the TiddlyWeb text [[store]] for details.
!!Description
Render a [[tiddler's|tiddler]] contents and attributes to some form, usually, but not always, HTML.

!!Parameters
* [[tiddler]]
* //[[environ]]=None//

!!Returns
* unicode

!!Example
{{{
    tiddler = Tiddler('hello')
    tiddler.text = '!Hello'
    html = wikitext.render_wikitext(tiddler, environ)
}}}

!!Notes
The environ is used to determine what renderer to use based on [[wikitext.type_render_map]] and [[wikitext.default_renderer]] in [[tiddlyweb.config]]. {{{type_render_map}}} is a mapping of MIME-types (or psuedo-MIME-types) to [[renderer]] code. If the provided tiddler has the {{{type}}} attribute set, and it is in this map, that renderer will be used. Otherwise the renderer in {{{default_renderer}}} is used.
!!Description
Update [[config]] settings, usually [[tiddlyweb.config]], with additional date in the form of a dict.

!!Parameters
* global_config
* additional_config
* //reconfig=True//

!!Returns
* None (global config is updated in place)

!!Example
{{{
    merge_config(config, {'css_uri': 'http://example.com'})
}}}

!!Notes
{{{reconfig}}}, when True (the default), will cause [[tiddlywebconfig.py]] to be reread and reprocessed after additional_config has been merged in. This is done to ensure that overrides in tiddlywebconfig.py take precedence.
!!Description
Recursively filter a list of tiddlers against a list of [[filter]] functions. The first filter in the list processes all the [[tiddlers|tiddler]] provided. Subsequent filters process the tiddler results of the previous filter. If the filter list is zero length all tiddlers are returned.

!!Parameters
* list of filter functions
* iterator of tiddlers

!!Returns
* generator of tiddlers

!!Example
{{{
    filters, leftovers = parse_for_filters('select=tag:systemConfig')
    tiddlers = recursive_filter(filters, bag.gen_tiddlers())
}}}

!!Notes
see [[tiddlywebwiki]]
see [[TiddlyWeb]]
PyPI is the Python Package Index: An index of Python packages assembled for easy discovery and installation.

> http://pypi.python.org/
`tiddlywebplugins` is being used as a `namespace_package` for mature TiddlyWeb plugins that are likely to be used in the created of [[verticals|vertical]].

[[Chris Dent]] has written a [[short reference|http://cdent.tumblr.com/post/216241761/python-namespace-packages-for-tiddlyweb]] on using the namespace.
See also [[ChrisDent]], [[cdent]], etc.
A bundle is a zipped archive of Python packages that can be created and installed using [[pip]]. The bundle includes the desired package plus all its dependent packages. Having a bundle makes it possible to install [[tiddlyweb]] and [[tiddlywebwiki]] on a host that does not have access to PyPI.

Starting in November of 2009, TiddlyWeb and TiddlyWebWiki bundles are being made available from http://tiddlyweb.peermore.com/dist/

See [[the google groups announcement|http://groups.google.com/group/tiddlyweb/browse_frm/thread/89d869a6dfb2b233]].
TiddlyWeb has a google group for discussion about all things TiddlyWeb. See: http://groups.google.com/group/tiddlyweb
jsonp provides jsonp wrapper callback handlng for any [[JSON]] representation provided by TiddyWeb. If the plugin is installed, when a JSON type request is made and {{{jsonp_callback}}} is set in the query string of the request, the output will be wrapped with that callback.

jsonp is available from PyPI as [[tiddlywebplugins.jsonp|http://pypi.python.org/pypi/tiddlywebplugins.jsonp]].
wimporter is a plugin that provides a web-based, server-side interface for importing some tiddlers from a remote TiddlyWiki into a selected bag hosted by the TiddlyWeb hosting the wimporter interface. The remote TiddlyWiki can be identified by an http URL, or provided as an uploaded file.

The plugin is available from PyPI as [[tiddlywebplugins.wimporter|http://pypi.python.org/pypi/tiddlywebplugins.wimporter]].
{{{system_plugins}}} is a [[config]] setting in [[tiddlywebconfig.py]] that lists the [[plugins]] which are configured for the running TiddlyWeb server. Another setting [[twanager_plugins]] lists those plugins which add functionality to the [[twanager]] command line tool. Some might be listed in both.

The value of the config item is a Python list of strings. Each string is the name of a Python package or module located either in the [[instance]] directory or somewhere on [[sys.path]].
The pluginmaker is a git repository which provides a template for creating new plugins. It doesn't have //all// the details but it has enough to get started.

See: http://github.com/tiddlyweb/pluginmaker/
A binary tiddler is a way to store non-textual content (such as an image, an office document, an mp3) in TiddlyWeb so that it is accessible as a [[tiddler]]. When the tiddler is retrieved, if no specific content-type is requested  then the content will be delivered with the content-type with which it was stored. Thus, if an image is stored to a tiddler as image/png it will be displayed in the browser as an image when requested. If the {{{text/plain}}} or {{{application/json}}} content-types are requested, then the {{{text}}} field of the resulting output will be a base64 encoded version of the data.

See [[How can I use curl to create stuff in TiddlyWeb?]] for an explanation of how to PUT a binary tiddler to a TiddlyWeb server.
<<<
1) First use curl to post username and password to the cookie_form and store a cookie for it locally:
{{{
curl ---cookie-jar cookies.txt -d "user=<username>&password=<password>&submit=submit" <yourwebsite.com>/challenge/cookie_form
}}}
2) Pass the created cookie to subsequent post to upload tiddlers
{{{
curl --cookie cookies.txt -X PUT -H 'Content-Type: text/plain' --data-binary @<filename> <yourwebsite.com>/bags/default/tiddlers/monkey
}}}
<<<
[[source|http://groups.google.com/group/tiddlyweb/browse_thread/thread/f756973de4146676/97828872a7eda93c?#97828872a7eda93c]]