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]];}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

hr {height:1px;}

a {text-decoration:none;}

dt {font-weight:bold;}

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

.txtOptionInput {width:11em;}

#contentWrapper .chkOptionInput {border:0;}

.externalLink {text-decoration:underline;}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

.whenBackstage {display:none;}
.backstageVisible .whenBackstage {display:block;}
/*}}}*/
/***
StyleSheet for use when a translation requires any css style changes.
This StyleSheet can be used directly by languages such as Chinese, Japanese and Korean which use a logographic writing system and 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;}

.htmlarea .toolbarHA table {border:1px solid ButtonFace; margin:0em 0em;}
/*}}}*/
/*{{{*/
@media print {
#mainMenu, #sidebar, #messageArea, .toolbar, #backstageButton, #backstageArea {display: none ! important;}
#displayArea {margin: 1em 1em 0em 1em;}
/* Fixes a feature in Firefox 1.5.0.2 where print preview displays the noscript content */
noscript {display:none;}
}
/*}}}*/
<!--{{{-->
<div class='header' macro='gradient vert [[ColorPalette::PrimaryLight]] [[ColorPalette::PrimaryMid]]'>
<div class='headerShadow'>
<span class='siteTitle' refresh='content' tiddler='SiteTitle'></span>&nbsp;
<span class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'></span>
</div>
<div class='headerForeground'>
<span class='siteTitle' refresh='content' tiddler='SiteTitle'></span>&nbsp;
<span class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'></span>
</div>
</div>
<div id='mainMenu' refresh='content' tiddler='MainMenu'></div>
<div id='sidebar'>
<div id='sidebarOptions' refresh='content' tiddler='SideBarOptions'></div>
<div id='sidebarTabs' refresh='content' force='true' tiddler='SideBarTabs'></div>
</div>
<div id='displayArea'>
<div id='messageArea'></div>
<div id='tiddlerDisplay'></div>
</div>
<!--}}}-->
<!--{{{-->
<div class='toolbar' macro='toolbar closeTiddler closeOthers +editTiddler > fields syncing permalink references jump'></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 +saveTiddler -cancelTiddler deleteTiddler'></div>
<div class='title' macro='view title'></div>
<div class='editor' macro='edit title'></div>
<div macro='annotations'></div>
<div class='editor' macro='edit text'></div>
<div class='editor' macro='edit tags'></div><div class='editorFooter'><span macro='message views.editor.tagPrompt'></span><span macro='tagChooser'></span></div>
<!--}}}-->
To get started with this blank TiddlyWiki, you'll need to modify the following tiddlers:
* SiteTitle & SiteSubtitle: The title and subtitle of the site, as shown above (after saving, they will also appear in the browser title bar)
* MainMenu: The menu (usually on the left)
* DefaultTiddlers: Contains the names of the tiddlers that you want to appear when the TiddlyWiki is opened
You'll also need to enter your username for signing your edits: <<option txtUserName>>
These InterfaceOptions for customising TiddlyWiki are saved in your browser

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

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

----
Also see AdvancedOptions
# cmd muninpks pokersource.info muninpks.pokersource.mksp.tld loic@dachary.org
set -e
meta="$1"
name="$(xmlstarlet sel -t -v /appliance/@name < <(dog --no-header $meta))"
realm="$(xmlstarlet sel -t -v /appliance/@realm < <(dog --no-header $meta))"
domain="$(xmlstarlet sel -t -v /appliance/@domain < <(dog --no-header $meta))"
vserver_realm="$(xmlstarlet sel -t -m /appliance/vserver_master/vserver -v ../@realm < <(dog --no-header $meta))"
view_host=$name.$realm.$vserver_realm.tld
name="$1"
domain="$2"
host="$3"
author="$4"
cd /etc/bind

test -f views/$domain.view

if ! grep "^$name" views/$domain.view > /dev/null
then
    echo -e "$name\t\tIN\tCNAME\t$host." >> views/$domain.view
    /etc/init.d/bind9 reload
    hg commit -u $author -m "bind $name to $host in $domain view" /etc/bind
fi
#
* ''Apache appliance on a laptop inside a LAN''
** Proppy wants to run a new online service available to the general public.
** Proppy creates a vlan on his GNU/Linux laptop and name it eth0.2.
** The eth0.2 interface is assigned a permanent private IP address range of 192.168.50.0/24.
**  Proppy adds shorewall rules to NAT all outgoing packets from eth0.2 and route them to eth0 or eth1 (the wifi interface).
** The 37000:38000 port range is abitrarily DNAT to eth0.2.
** Proppy creates a new Debian etch based vserver with address 192.168.50.10 on eth0.2 and names it VOD.
** Apache2 is installed in VOD and bound to 37080 in addtion to the 80 port.
** The laptop is run from inside a ~NATed LAN and and has a fixed DHCP allocated fixed IP based on his MAC address.
** Proppy adds a rule to the firewall ~NATing the LAN so that ports 37000:38000 are redirected to the laptop fixed IP.
# cmd openalpp osgal dachary.org
set -e

name="$1"
newname="$2"
domain="$3"

cd /etc/apache2
a2dissite $name.$domain
mv sites-available/$name.$domain sites-available/$newname.$domain
perl -pi -e "s/\b$name\b/$newname/g" sites-available/$newname.$domain
! grep -l $name sites-available/$newname.$domain
a2ensite $newname.$domain
for log in /var/log/apache2/*$name* ; do
    newlog=$(echo $log | perl -p -e "s/\b$name\b/$newname/g")
    mv $log $newlog
done
/etc/init.d/apache2 reload
* Request for inclusion in debian package http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=425008;repeatmerged=no

* One liner that will work on a newly installed apache2 from Debian GNU/Linux etch
{{{
author=loic@dachary.org ; app=apache2 ; apt-get install -y --force-yes $app && hg addremove && hg commit -u $author -m "apt-get install $app"
app=patch ; apt-get install -y --force-yes $app && hg addremove && hg commit -u $author -m "apt-get install $app"
cd / ; wget -O - http://hg.nagios.fsffrance.org/raw-rev/22ed4d555572 | patch -p1 
hg commit -m 'Apache x-forwarded-for log when behind a proxy' /etc/apache2
/etc/init.d/apache2 reload
}}}
* Emacs macro
{{{
; C-x e on the CustomLog line
(setq last-kbd-macro "\C-k\C-k\C-y\C-y\C-p\C-p\C-e env=!from_proxy\C-n_forwarded env=from_proxy")
}}}
* Complete patch
{{{
cd /
patch -p1 <<'EOF'
--- a/etc/apache2/apache2.conf	Thu May 03 23:57:15 2007 +0200
+++ b/etc/apache2/apache2.conf	Thu May 03 23:59:07 2007 +0200
@@ -199,9 +199,12 @@ Include /etc/apache2/conf.d/
 # a CustomLog directive (see below).
 #
 LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
+LogFormat "%{X-Forwarded-For}i %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined_forwarded
 LogFormat "%h %l %u %t \"%r\" %>s %b" common
 LogFormat "%{Referer}i -> %U" referer
 LogFormat "%{User-agent}i" agent
+
+SetEnvIfNoCase X-Forwarded-For "." from_proxy=1
 
 #
 # ServerTokens
--- a/etc/apache2/sites-available/default	Thu May 03 23:57:15 2007 +0200
+++ b/etc/apache2/sites-available/default	Thu May 03 23:59:07 2007 +0200
@@ -34,7 +34,8 @@ NameVirtualHost *
 	# alert, emerg.
 	LogLevel warn
 
-	CustomLog /var/log/apache2/access.log combined
+	CustomLog /var/log/apache2/access.log combined env=!from_proxy
+	CustomLog /var/log/apache2/access.log combined_forwarded env=from_proxy
 	ServerSignature On
 
EOF
}}}
{{{
diff -r 36c2ae3235c9ea8a3d640b6dba5811ed6a54f9f0 -r b03e45844f4ee52e777288dad5c2cf3a361f92bd bind/db.aminche.com
--- a/bind/db.aminche.com	Mon Apr 02 00:16:32 2007 +0200
+++ b/bind/db.aminche.com	Thu May 17 21:32:08 2007 +0200
@@ -1,6 +1,6 @@
 $ttl 3d
 @       IN      SOA     ns.aminche.com. hostmaster.aminche.com. (
-                        2007040102      ; serial, todays date + todays serial #
+                        2007041602      ; serial, todays date + todays serial #
                         28800           ; refresh, seconds
                         7200            ; retry, seconds
                         604800          ; expire, seconds
@@ -28,4 +28,5 @@ muzine		IN	A 88.191.13.165
 muzine		IN	A 88.191.13.165
 hg		IN	A 88.191.13.165
 zanna		IN	A 88.191.13.165
+*.aminche.com.	IN	A 88.191.13.165
 aminche.com.	IN	A 88.191.13.165

}}}
** Proppy boots the real machine using a live CD
** Proppy installs and run the ssh daemon
** The ssh daemon allows root access and the password is set
** The hard disk is explored using fdisk
** Proppy mounts the file systems in /mnt as if it was / (for instance /dev/sda2 on /mnt and /dev/sda3 on /mnt/home)
** From the vserver host, proppy copies all the files (could also be done using the rsync vserver build method but it would not cross the file system boundaries because of the -x option and would therefore miss files)
{{{
rsync -avH --numeric-ids root@mekensleep.com:/mnt/ /var/lib/vservers/newmachine/
}}}
mkdir app
cd app
mkdir universe
ruby /usr/bin/tiddlywiki_cp -a http://garden.dachary.org/universe.html universe
emacs meta.xml # use model http://yocto-reader.flouzo.net/meta/meta.xml

meta=http://localhost/app/meta.xml

script_url="$(xmlstarlet sel -t -v /appliance/public_ns/@create < <(dog --no-header "$meta"))" ; \
 ssh -p $(xmlstarlet sel -t -v /appliance/public_ns/@ns_port < <(dog --no-header "$meta")) \
        root@$(xmlstarlet sel -t -v /appliance/public_ns/@public_ns < <(dog --no-header "$meta")) \
        bash -x '<(dog --no-header '$script_url')' $meta

script_url="$(xmlstarlet sel -t -v /appliance//ns/@create < <(dog --no-header "$meta"))" ; \
 ssh root@$(xmlstarlet sel -t -m /appliance/vserver_master/ns -v ../@host < <(dog --no-header "$meta")) \
        bash -x '<(dog --no-header '$script_url')' $meta

script_url="$(xmlstarlet sel -t -v /appliance//vserver/@create < <(dog --no-header "$meta"))" ; \
 ssh root@$(xmlstarlet sel -t -m /appliance/vserver_master/vserver -v ../@host < <(dog --no-header "$meta")) \
        bash -x '<(dog --no-header '$script_url')' $meta

script_url="$(xmlstarlet sel -t -v /appliance//garden/@create < <(dog --no-header "$meta"))" ; \
 ssh root@$(xmlstarlet sel -t -m /appliance//garden -v ../@host < <(dog --no-header "$meta")) \
   cat '<(dog --no-header '$script_url')' \| vserver $(xmlstarlet sel -t -v /appliance/@name < <(dog --no-header "$meta")) exec "bash -x -s '$meta'"

script_url="$(xmlstarlet sel -t -v /appliance//mercurial/@create < <(dog --no-header "$meta"))" ; \
 ssh root@$(xmlstarlet sel -t -m /appliance//mercurial -v ../@host < <(dog --no-header "$meta")) \
   cat '<(dog --no-header '$script_url')' \| vserver $(xmlstarlet sel -t -v /appliance/@name < <(dog --no-header "$meta")) exec "bash -x -s '$meta'"

script_url="$(xmlstarlet sel -t -v /appliance//http_proxy/@create < <(dog --no-header "$meta"))" ; \
 ssh root@$(xmlstarlet sel -t -m /appliance//http_proxy -v ../@host < <(dog --no-header "$meta")) \
   cat '<(dog --no-header '$script_url')' \| vserver $(xmlstarlet sel -t -v /appliance//http_proxy/@vserver_name < <(dog --no-header "$meta")) exec "bash -x -s '$meta'"

view_host=$name.$realm.$vserver_realm.tld
scp 'universe/Add DNS name in view.tiddler' root@$vserver_host:/tmp/step6
ssh root@$vserver_host bash -x /tmp/step6 $name $domain $view_host $author
ssh root@$vserver_host bash -x /tmp/step6 hg.$name $domain $view_host $author

script_url="$(xmlstarlet sel -t -v /appliance//nagios/@create < <(dog --no-header "$meta"))" ; \
 ssh root@$(xmlstarlet sel -t -m /appliance//nagios -v ../@host < <(dog --no-header "$meta")) \
   cat '<(dog --no-header '$script_url')' \| vserver $(xmlstarlet sel -t -v /appliance//nagios/@vserver_name < <(dog --no-header "$meta")) exec "bash -x -s '$meta'"

nagios_vserver_host=mango.pokersource.info
nagios_name=nagiosfsf
parent_in_nagios_graph=mango
#nagios_host=hg.$name.$realm.$vserver_realm.tld.
nagios_host=hg.$name.$domain.
scp universe/Monitor\ the\ mercurial\ server\ with\ nagios.tiddler root@$nagios_vserver_host:/var/lib/vservers/$nagios_name/tmp/step7
ssh root@$nagios_vserver_host vserver $nagios_name exec "bash -x /tmp/step7 hg.$name $domain $parent_in_nagios_graph $nagios_host $author"

script_url="$(xmlstarlet sel -t -v /appliance/rss/@create < <(dog --no-header "$meta"))" ; \
 ssh root@$(xmlstarlet sel -t -v /appliance/rss/@host < <(dog --no-header $meta)) bash -x '<(dog --no-header '$script_url')' $meta

rss_host=dachary.org
#rss_url=http://hg.$name.$domain/rss-log
rss_url=http://$name.conf.tld:8000/rss-log
scp universe/Syndicate\ the\ mercurial\ changes.tiddler root@$rss_host:/tmp/step8
ssh root@$rss_host bash -x /tmp/step8 $rss_url $name

service=ssh
zone=tld
scp 'universe/open firewall port for appliance.tiddler' root@$vserver_host:/tmp/step9
ssh -t root@$vserver_host bash -x /tmp/step9 $name $domain $service $realm $vserver_realm $zone
set -e
meta="$1"
name="$(xmlstarlet sel -t -v /appliance/@name < <(dog --no-header $meta))"
domain="$(xmlstarlet sel -t -v /appliance/@domain < <(dog --no-header $meta))"
author="$(xmlstarlet sel -t -v /appliance/@author < <(dog --no-header $meta))"
vserver_realm="$(xmlstarlet sel -t -m /appliance/vserver_master/vserver -v ../@realm < <(dog --no-header $meta))"
realm="$(xmlstarlet sel -t -v /appliance/@realm < <(dog --no-header $meta))"
vserver_name="$name.$realm.$vserver_realm.tld"
apt-get install debootstrap util-vserver
ip=$(getent hosts $vserver_name | cut -f1 -d' ')
test "$ip"
fqdn=$name.$domain
method="$(xmlstarlet sel -t -v /appliance/vserver_master/vserver/@distribution < <(dog --no-header $meta))"
case "$method" in
etch|lenny)
        method="debootstrap -- -d $method -m http://ftp.fr.debian.org/debian "
        ;;
skeleton)
        method=skeleton
        ;;
esac
iface=$(xmlstarlet sel -t -m /appliance/vserver_master/vserver -v ../@iface < <(dog --no-header $meta))
#ip=$(getent hosts $name.$domain | head -1 | cut -f1 -d' ')
addr=$(expr $ip : '.*\.\([0-9]*\)')
test "$addr"
net=$(expr $ip : '\(.*\)\.')
test "$net"
eval vserver $name build --hostname $fqdn --interface a$addr=$iface:$net.$addr/24 --context 2$addr -m $method
echo default > /etc/vservers/$name/apps/init/mark
hg addremove /etc/vservers
hg commit -u $author -m "create $name vserver" /etc/vservers
cat > /var/lib/vservers/$name/etc/resolv.conf <<EOF
search $domain
nameserver $net.1
EOF
case "$method" in
etch|lenny)
        if ! grep APT::Cache-Limit /etc/apt/apt.conf.d/70debconf > /dev/null ; then
		echo 'APT::Cache-Limit 100000000;' >> /etc/apt/apt.conf.d/70debconf
	fi
        ;;
esac
mkdir -p /var/lib/vservers/$name/proc /var/lib/vservers/$name/sys
ln -s /proc/self/fd /var/lib/vservers/$name/dev/fd
chroot /var/lib/vservers/$name apt-get remove --yes klogd || /bin/true
chroot /var/lib/vservers/$name update-rc.d cron defaults
env -i TERM=vt100 /usr/sbin/vserver $name start
echo DONE
should be converted to use the programable API of bind9 at some point
* The named.conf file //must// include views only. That's the only tricky bit : the top level configuration file may not contain any stanza. When views are used, all must be views. Note that match-clients is on the same line as {{{view}}} so that scripts can easily manipulate it.
{{{
include "/etc/bind/named.conf.options";

view "pokersource.info" { match-clients { 192.168.50.10; };
  zone "conf.tld" {
    type master;
    file "/etc/bind/pokersource.info.view";
  };
  include "/etc/bind/named.conf.zones";
  include "/etc/bind/named.conf.common";
};

view "default" {
  include "/etc/bind/named.conf.zones";
  include "/etc/bind/named.conf.common";
};

include "/etc/bind/named.conf.local";

}}}

* The //named.conf.common// that's included in each view holds what you'd like to include outside the views if bind9 allowed this. It's typically what you find in a named.conf bind9 file when not using views:

{{{
// prime the server with knowledge of the root servers
zone "." {
	type hint;
	file "/etc/bind/db.root";
};

// be authoritative for the localhost forward and reverse zones, and for
// broadcast zones as per RFC 1912

zone "localhost" {
	type master;
	file "/etc/bind/db.local";
};

zone "127.in-addr.arpa" {
	type master;
	file "/etc/bind/db.127";
};

zone "0.in-addr.arpa" {
	type master;
	file "/etc/bind/db.0";
};

zone "255.in-addr.arpa" {
	type master;
	file "/etc/bind/db.255";
};
}}}

* The {{{/etc/bind/named.conf.zones}}} file included in the {{{/etc/bind/named.conf}}} contains the list of supported zones (master, slave and forwarded). Forwarded zones are used to make sure DNS requests for domains under your control refer only to the master server, to [[avoid propagation delays|avoid DNS delays]]. 
{{{
zone "my" {
	type master;
	file "/etc/bind/db.my";
};

zone "pokersource.info."{
   type forward ;
   forward only ;
   forwarders {
       88.191.250.41 ;
   } ;
};
}}}
In the above file, the //my// zone is used to define the .my top level domain that points to the IP of the appliances running on the local machine and unknown to the outside world.
# cmd meta
set -e
meta="$1"
name="$(xmlstarlet sel -t -v /appliance/@name < <(dog --no-header $meta))"
domain="$(xmlstarlet sel -t -v /appliance/@domain < <(dog --no-header $meta))"
author="$(xmlstarlet sel -t -v /appliance/@author < <(dog --no-header $meta))"
cname="$(xmlstarlet sel -t -v /appliance/public_ns/@cname < <(dog --no-header $meta))"
dns="$(xmlstarlet sel -t -v /appliance/public_ns/@public_ns_ip < <(dog --no-header $meta))"
cd /etc/bind
if ! grep $domain db.$domain > /dev/null
then
    echo "the /etc/bind/db.$domain file must exist and contain the $domain string"
    exit 1
fi
if ! grep "^$name" db.$domain > /dev/null
then
    echo "$name                IN      CNAME   $cname." >> db.$domain
    echo "hg.$name             IN      CNAME   $cname." >> db.$domain
    perl -ni -e 'if(/(\d+).*; serial/) { $s = $1; $s++; print "\t\t\t$s\t; serial\n"; } else { print; }' db.$domain
    /etc/init.d/bind9 reload
    sleep 2
fi
dig @$dns $name.$domain | grep "CNAME.*$cname"
dig @$dns hg.$name.$domain | grep "CNAME.*$cname"
hg commit -u $author -m "define $name.$domain" /etc/bind/db.$domain
echo DONE
# cmd markerclock 192.168.50 call dachary dachary.org loic@dachary.org
set -e
meta="$1"
name="$(xmlstarlet sel -t -v /appliance/@name < <(dog --no-header $meta))"
domain="$(xmlstarlet sel -t -v /appliance/@domain < <(dog --no-header $meta))"
author="$(xmlstarlet sel -t -v /appliance/@author < <(dog --no-header $meta))"
realm="$(xmlstarlet sel -t -v /appliance/@realm < <(dog --no-header $meta))"
net="$(xmlstarlet sel -t -m /appliance//ns -v ../@net < <(dog --no-header $meta))"
vserver_realm="$(xmlstarlet sel -t -m /appliance//ns -v ../@realm < <(dog --no-header $meta))"
reverse=$(echo $net | perl -p -e 's/(\d+).(\d+).(\d+)/$3.$2.$1/')
cd /etc/bind
db_file=db.$net
if ! test -f $db_file
then
        db_file=db.$(expr $net : '\(.*\)\.')
fi

if ! dig @$net.1 $name.$realm.$vserver_realm.tld. | grep "^$name.$realm.$vserver_realm.tld.*IN.*A" > /dev/null
then
        perl -ni -e 'if(/(\d+).*; serial/) { $s = $1; $s++; print "\t\t\t$s\t; serial\n"; } else { print; }' \
                $db_file db.$vserver_realm views/$domain.view
        ip=$(expr "$(grep available $db_file | tail -1)" : '.*available-\([0-9][0-9]*\)')
        if test -z "$ip"
        then
                echo "NO IP"
                exit 1
        fi
        for file in $db_file db.$vserver_realm
        do
                if ! grep "^$name.$realm" $file > /dev/null
                then
                        perl -pi -e "s/available-$ip/$name.$realm/" $file
                fi
        done
	vserver_proxy="$(xmlstarlet sel -t -m /appliance//http_proxy -v ../@host < <(dog --no-header $meta))"
	domain_proxy="$(xmlstarlet sel -t -m /appliance//http_proxy/@domain < <(dog --no-header $meta))"
	vserver_ns="$(xmlstarlet sel -t -m /appliance//ns -v ../@host < <(dog --no-header $meta))"
	if [ "$domain_proxy" -a "$vserver_proxy" = "$vserver_ns" -a "$domain" != "$domain_proxy" ] ; then
	        if ! grep "^$name" views/$domain_proxy.view > /dev/null
	        then
	                echo -e "$name\t\tIN\tCNAME\t$name.$realm.$vserver_realm.tld." >> views/$domain_proxy.view
	        fi
	fi
        if ! grep "^$name" views/$domain.view > /dev/null
        then
                echo -e "$name\t\tIN\tCNAME\t$name.$realm.$vserver_realm.tld." >> views/$domain.view
        fi
        /etc/init.d/bind9 reload
        sleep 2
        dig @$net.1 $name.$realm.$vserver_realm.tld. | grep $ip
        dig @$net.1 -x $net.$ip | grep $name.$realm.$vserver_realm.tld
else
        ip=$(expr "$(dig @$net.1 $name.$realm.$vserver_realm.tld | grep \^$name.$realm)" : ".*$net.\([0-9]*\)")
fi
# ??? how to test that a resolution within a view works ???
perl -pi -e 's/};$/'$net.$ip'; };/ if(/^view "'$realm'/ && !/'$net.$ip'/)' named.conf
grep "$realm.*$net.$ip" named.conf
/etc/init.d/bind9 reload
hg commit -u $author -m "define $name local names in $realm" /etc/bind
echo DONE
ns2:~# meta=http://garden.conf.tld/packaging-farm.xml
ns2:~# name="$(xmlstarlet sel -t -v /appliance/@name < <(dog --no-header $meta))"
ns2:~# author="$(xmlstarlet sel -t -v /appliance/@author < <(dog --no-header $meta))"
ns2:~# domain="$(xmlstarlet sel -t -v /appliance/@domain < <(dog --no-header $meta))"
ns2:~#
ns2:~# cd /etc/bind
ns2:/etc/bind# echo $domain
dachary.org
ns2:/etc/bind# #perl -pi -e '$_ = '' if(/^'$name'/ || /^hg.'$name'/)' db.$domain
ns2:/etc/bind# grep $name db.$domain
packaging-farm          IN      CNAME   dachary.org.
hg.packaging-farm       IN      CNAME   dachary.org.
ns2:/etc/bind# perl -pi -e '$_ = '' if(/^'$name'/ || /^hg.'$name'/)' db.$domain
syntax error at -e line 1, near "=  if"
Execution of -e aborted due to compilation errors.
ns2:/etc/bind# perl -pi -e '$_ = "" if(/^'$name'/ || /^hg.'$name'/)' db.$domain
ns2:/etc/bind# grep $name db.$domain
ns2:/etc/bind# dns="$(xmlstarlet sel -t -v /appliance/public_ns/@public_ns_ip < <(dog --no-header $meta))"
ns2:/etc/bind# echo $dns
192.168.50.16
ns2:/etc/bind#     perl -ni -e 'if(/(\d+).*; serial/) { $s = $1; $s++; print "\t\t\t$s\t; serial\n"; } else { print; }' db.$domain
ns2:/etc/bind# hg diff db.$domain
*** output flushed ***
ns2:/etc/bind# /etc/init.d/bind9 reload
Reloading domain name service...: bind.
ns2:/etc/bind#
ns2:/etc/bind# ! dig @$dns $name.$domain | grep "CNAME.*$cname"
ns2:/etc/bind# #hg commit -u $author -m "undefine $name.$domain" /etc/bind/db.$domain
ns2:/etc/bind# echo $author
loic@dachary.org
ns2:/etc/bind# hg commit -u $author -m "undefine $name.$domain" /etc/bind/db.$domain
ns2:/etc/bind#
pecho:~# meta=http://garden.conf.tld/packaging-farm.xml

pecho:~# name="$(xmlstarlet sel -t -v /appliance/@name < <(dog --no-header $meta))"
domain="$(xmlstarlet sel -t -v /appliance/@domain < <(dog --no-header $meta))"
author="$(xmlstarlet sel -t -v /appliance/@author < <(dog --no-header $meta))"
realm="$(xmlstarlet sel -t -v /appliance/@realm < <(dog --no-header $meta))"
net="$(xmlstarlet sel -t -m /appliance//ns -v ../@net < <(dog --no-header $meta))"
vserver_realm="$(xmlstarlet sel -t -m /appliance//ns -v ../@realm < <(dog --no-header $meta))"
pecho:~# pecho:~# pecho:~# pecho:~# pecho:~# pecho:~# 
pecho:~# echo $realm
dachary
pecho:~# cd /etc/bind
pecho:/etc/bind# reverse=$(echo $net | perl -p -e 's/(\d+).(\d+).(\d+)/$3.$2.$1/')
pecho:/etc/bind# db_file=db.$net
if ! test -f $db_file
then
        db_file=db.$(expr $net : '\(.*\)\.')
fi
pecho:/etc/bind# > > > pecho:/etc/bind# 
pecho:/etc/bind# echo $db_file
db.192.168
pecho:/etc/bind# dig @$net.1 $name.$realm.$vserver_realm.tld | grep "^$name.$realm.$vserver_realm.tld.*IN.*A"
pecho:/etc/bind# echo dig @$net.1 $name.$realm.$vserver_realm.tld
dig @192.168.50.1 packaging-farm.dachary.fsf.tld
pecho:/etc/bind# ifconfig
*** output flushed ***
pecho:/etc/bind# dig @$net.1 $name.$realm.$vserver_realm.tld. | grep "^$name.$realm.$vserver_realm.tld.*IN.*A"
pecho:/etc/bind# dig @$net.1 $name.$realm.$vserver_realm.tld. 

; <<>> DiG 9.3.2-P1 <<>> @192.168.50.1 packaging-farm.dachary.fsf.tld.
; (1 server found)
;; global options:  printcmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 23377
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 0

;; QUESTION SECTION:
;packaging-farm.dachary.fsf.tld.	IN	A

;; AUTHORITY SECTION:
fsf.tld.		1800	IN	SOA	ns.fsf.tld. hostmaster.fsf.tld. 2007072308 3600 1800 1209600 1800

;; Query time: 0 msec
;; SERVER: 192.168.50.1#53(192.168.50.1)
;; WHEN: Thu Sep 27 00:06:12 2007
;; MSG SIZE  rcvd: 98

pecho:/etc/bind# dig @$net.1 $name.$realm.$vserver_realm.tld. 

; <<>> DiG 9.3.2-P1 <<>> @192.168.50.1 packaging-farm.dachary.fsf.tld.
; (1 server found)
;; global options:  printcmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 12598
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 1, ADDITIONAL: 1

;; QUESTION SECTION:
;packaging-farm.dachary.fsf.tld.	IN	A

;; ANSWER SECTION:
packaging-farm.dachary.fsf.tld.	3600 IN	A	192.168.50.20

;; AUTHORITY SECTION:
fsf.tld.		3600	IN	NS	ns.fsf.tld.

;; ADDITIONAL SECTION:
ns.fsf.tld.		3600	IN	A	192.168.50.1

;; Query time: 0 msec
;; SERVER: 192.168.50.1#53(192.168.50.1)
;; WHEN: Thu Sep 27 00:09:55 2007
;; MSG SIZE  rcvd: 97

pecho:/etc/bind# dig @$net.1 $name.$realm.$vserver_realm.tld. | grep "^$name.$realm.$vserver_realm.tld.*IN.*A"
packaging-farm.dachary.fsf.tld.	3600 IN	A	192.168.50.20
pecho:/etc/bind#        perl -ni -e 'if(/(\d+).*; serial/) { $s = $1; $s++; print "\t\t\t$s\t; serial\n"; } else { print; }' \
                $db_file db.$vserver_realm views/$domain.view
> pecho:/etc/bind# 
pecho:/etc/bind# hg diff .
diff -r b01accd3be91 etc/bind/db.192.168
--- a/etc/bind/db.192.168	Thu Sep 27 00:09:42 2007 +0200
+++ b/etc/bind/db.192.168	Thu Sep 27 00:11:01 2007 +0200
@@ -4,7 +4,7 @@
 ;
 $TTL	604800
 @	IN	SOA	localhost. root.localhost. (
-			2007092700	; serial
+			2007092701	; serial
 			 604800		; Refresh
 			  86400		; Retry
 			2419200		; Expire
diff -r b01accd3be91 etc/bind/db.fsf
--- a/etc/bind/db.fsf	Thu Sep 27 00:09:42 2007 +0200
+++ b/etc/bind/db.fsf	Thu Sep 27 00:11:01 2007 +0200
@@ -4,7 +4,7 @@
 
 $ORIGIN fsf.tld.
 @                       IN      SOA             ns hostmaster (
-			2007092700	; serial
+			2007092701	; serial
                                 1h              ; refresh - time when the slave will try to refresh the zone from the master (8h)
                                 30m             ; update retry - time between retries if the slave (secondary) (2h)
                                                 ; fails to contact the master when refresh (above) has expired.
diff -r b01accd3be91 etc/bind/views/dachary.org.view
--- a/etc/bind/views/dachary.org.view	Thu Sep 27 00:09:42 2007 +0200
+++ b/etc/bind/views/dachary.org.view	Thu Sep 27 00:11:01 2007 +0200
@@ -4,7 +4,7 @@
 
 $ORIGIN conf.tld.
 @                       IN      SOA             ns hostmaster (
-			2007092700	; serial
+			2007092701	; serial
                                 1h              ; refresh - time when the slave will try to refresh the zone from the master (8h)
                                 30m             ; update retry - time between retries if the slave (secondary) (2h)
                                                 ; fails to contact the master when refresh (above) has expired.
pecho:/etc/bind# echo $db_file
db.192.168
pecho:/etc/bind# grep $name $db_file
20.50	IN	PTR	packaging-farm.dachary.fsf.tld.
pecho:/etc/bind# getent hosts $name.$realm.$vserver_realm.tld.
192.168.50.20   packaging-farm.dachary.fsf.tld
pecho:/etc/bind# expr "$(getent hosts $name.$realm.$vserver_realm.tld.)" : ".*\.\([0-9][0-9]*\)"
20
pecho:/etc/bind# ip=(expr "$(getent hosts $name.$realm.$vserver_realm.tld.)" : ".*\.\([0-9][0-9]*\)")
pecho:/etc/bind# echo $ip
expr
pecho:/etc/bind# ip=$(expr "$(getent hosts $name.$realm.$vserver_realm.tld.)" : ".*\.\([0-9][0-9]*\)")
pecho:/etc/bind# echo $ip
20
pecho:/etc/bind# perl -pi -e "s/$name.$realm/available-$ip/" $db_file
pecho:/etc/bind# perl -pi -e "s/$name.$realm/available-$ip/" db.$vserver_realm
pecho:/etc/bind# perl -pi -e '$_ = "" if(/^'$name'/)' views/$domain.view
pecho:/etc/bind# /etc/init.d/bind9 reload
Reloading domain name service...: bind.
pecho:/etc/bind# dig @$net.1 $name.$realm.$vserver_realm.tld. | grep $ip
fsf.tld.		1800	IN	SOA	ns.fsf.tld. hostmaster.fsf.tld. 2007092702 3600 1800 1209600 1800
;; WHEN: Thu Sep 27 00:34:10 2007
pecho:/etc/bind# dig @$net.1 $name.$realm.$vserver_realm.tld. | grep $name.$realm.$vserver_realm.tld
; <<>> DiG 9.3.2-P1 <<>> @192.168.50.1 packaging-farm.dachary.fsf.tld.
;packaging-farm.dachary.fsf.tld.	IN	A
pecho:/etc/bind# dig @$net.1 $name.$realm.$vserver_realm.tld. | grep "^$name.$realm.$vserver_realm.tld"
pecho:/etc/bind# ! dig @$net.1 $name.$realm.$vserver_realm.tld. | grep "^$name.$realm.$vserver_realm.tld"
pecho:/etc/bind# echo $net.$ip
192.168.50.20
pecho:/etc/bind# grep $net.$ip named.conf
view "dachary.org" { match-clients { 192.168.50.13; 192.168.50.14; 192.168.50.17; 192.168.50.19; 192.168.50.20; 192.168.50.22; 192.168.50.23; 192.168.50.27; 192.168.50.28; 192.168.50.33; 192.168.50.35; 192.168.50.38; 192.168.50.40; 192.168.50.41; 192.168.50.43; 192.168.50.44; 88.191.250.36; 192.168.50.254; 192.168.50.253; 192.168.50.251; 192.168.50.250; 192.168.50.249; 192.168.50.248; };
pecho:/etc/bind# perl -pi -e "s/$net.$ip; //" named.conf
pecho:/etc/bind# hg status .
M db.192.168
M db.fsf
M named.conf
M views/dachary.org.view
pecho:/etc/bind# grep $net.$ip named.conf
pecho:/etc/bind# /etc/init.d/bind9 reload
Reloading domain name service...: bind.
pecho:/etc/bind# hg commit -u $author -m "undefine $name local names in $realm" /etc/bind
pecho:/etc/bind# echo DONE
DONE
pecho:/etc/bind# 
[[Summary]]
[[Rationale]]
[[Use Cases]]
[[Scope]]
[[Design]]
[[Implementation]]
[[Unresolved Issues]]
set -e
meta="$1"
echo $meta
name="$(xmlstarlet sel -t -v /appliance/@name < <(dog --no-header $meta))"
echo $name
domain="$(xmlstarlet sel -t -v /appliance/@domain < <(dog --no-header $meta))"
author="$(xmlstarlet sel -t -v /appliance/@author < <(dog --no-header $meta))"
http_host="$(xmlstarlet sel -t -v /appliance//http_proxy/@http_host < <(dog --no-header $meta))"
hg_host="$(xmlstarlet sel -t -v /appliance//http_proxy/@hg_host < <(dog --no-header $meta))"
cd /etc/apache2/mods-available/
if ! a2enmod proxy_http | grep already ; then
patch <<'EOF'
diff -r 8177988b2d1d etc/apache2/mods-available/proxy.conf
--- a/etc/apache2/mods-available/proxy.conf     Fri Mar 30 12:18:19 2007 +0200
+++ b/etc/apache2/mods-available/proxy.conf     Fri Aug 03 18:40:24 2007 +0200
@@ -7,7 +7,8 @@

        <Proxy *>
                Order deny,allow
-               Deny from all
+               Allow from all
+               #Deny from all
                #Allow from .your_domain.com
        </Proxy>
EOF
fi
cd /etc/apache2/sites-available/
if [ ! -f template.$domain ] ; then
  cat > template.$domain <<EOF
<VirtualHost *>
    ServerName          template.$domain
    ServerAlias         template.conf.tld
    ProxyPass           / http://http_host/
    ProxyPassReverse    / http://http_host/
    ServerAdmin         root@$domain
    ErrorLog            /var/log/apache2/http_host-error.log
    CustomLog           /var/log/apache2/http_host-access.log common
</VirtualHost>

<VirtualHost *>
    ServerName          hg.template.$domain
    ServerAlias         hg.template.conf.tld
    ProxyPass           / http://hg_host/
    ProxyPassReverse    / http://hg_host/
    ServerAdmin         root@$domain
    ErrorLog            /var/log/apache2/http_host-error.log
    CustomLog           /var/log/apache2/http_host-access.log common
</VirtualHost>
EOF
fi
sed -e "s/template/$name/g" -e "s/hg_host/$hg_host/g" -e "s/http_host/$http_host/g" < template.$domain > $name.$domain
a2ensite $name.$domain
/etc/init.d/apache2 reload
sleep 2
if [ ! -f /var/log/apache2/$http_host-error.log ] ; then
        echo "/var/log/apache2/$http_host-error.log does not exist"
        exit 1
fi
hg add $name.$domain
hg commit -u $author -m "define proxy for $name.$domain" $name.$domain
echo DONE
Write no code. The actual implementation must consist of configuration lines for each software involved. The implementation must be a set of configuration actions described to fit one or more use case.

Use configuration generators that are designed to create a variety of configuration tweaks (files or patches) based on a centralized description.
/***
|''Name:''|GenerateRssByTagPlugin|
|''Description:''|Only tiddlers with a specific tag are inluded in the RSSFeed. If no tiddlers are selected then works as before. (see ticket #270: http://trac.tiddlywiki.org/tiddlywiki/ticket/270). <br>RssTag: <<option txtRssTag>>|
|''Version:''|1.0.3|
|''Date:''|May 17, 2007|
|''Source:''|http://tiddlywiki.bidix.info/#GenerateRssByTagPlugin|
|''Author:''|BidiX (BidiX (at) bidix (dot) info)|
|''License:''|[[BSD open source license|http://tiddlywiki.bidix.info/#%5B%5BBSD%20open%20source%20license%5D%5D ]]|
|''~CoreVersion:''|2.2.0 (Beta 5)|
***/
//{{{
version.extensions.GenerateRssByTagPlugin = {
	major: 1, minor: 0, revision: 3, 
	date: new Date("May 17, 2007"),
	source: 'http://tiddlywiki.bidix.info/#GenerateRssByTagPlugin',
	author: 'BidiX (BidiX (at) bidix (dot) info',
	coreVersion: '2.2.0 (Beta 5)'
};

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

bidix.generateRssByTag = function()
{
	var s = [];
	var d = new Date();
	var u = store.getTiddlerText("SiteUrl");
	// Assemble the header
	s.push("<" + "?xml version=\"1.0\"" + " encoding='UTF-8' " + "?" + ">");
	s.push("<rss version=\"2.0\">");
	s.push("<channel>");
	s.push("<title" + ">" + wikifyPlain("SiteTitle").htmlEncode() + "</title" + ">");
	if(u)
		s.push("<link>" + u.htmlEncode() + "</link>");
	s.push("<description>" + wikifyPlain("SiteSubtitle").htmlEncode() + "</description>");
	s.push("<language>en-us</language>");
	s.push("<copyright>Copyright " + d.getFullYear() + " " + config.options.txtUserName.htmlEncode() + "</copyright>");
	s.push("<pubDate>" + d.toGMTString() + "</pubDate>");
	s.push("<lastBuildDate>" + d.toGMTString() + "</lastBuildDate>");
	s.push("<docs>http://blogs.law.harvard.edu/tech/rss</docs>");
	s.push("<generator>TiddlyWiki " + version.major + "." + version.minor + "." + version.revision + "</generator>");
	// The body
	var tiddlers;
	if (config.options.txtRssTag && store.getTaggedTiddlers(config.options.txtRssTag).length > 0)
		tiddlers = store.getTaggedTiddlers(config.options.txtRssTag,"modified");
	else
		tiddlers = store.getTiddlers("modified","excludeLists");
	var n = config.numRssItems > tiddlers.length ? 0 : tiddlers.length-config.numRssItems;
	for (var t=tiddlers.length-1; t>=n; t--)
		s.push(tiddlers[t].saveToRss(u));
	// And footer
	s.push("</channel>");
	s.push("</rss>");
	// Save it all
	return s.join("\n");
};

//
// Initializations
//
bidix.generateRss = generateRss; // backup core version
generateRss = bidix.generateRssByTag; // install new one
config.options.txtRssTag = "toRSS"; // default RssTag. use <<option txtRssTag>> to overwritte
merge(config.optionsDesc,{txtRssTag: "Only tiddlers with this tag will be included in the RSS Feed."});
//}}}
/***
| Name|HideWhenPlugin|
| Description|Allows conditional inclusion/exclusion in templates|
| Version|3.0 ($Rev: 1845 $)|
| Date|$Date: 2007-03-16 15:19:22 +1000 (Fri, 16 Mar 2007) $|
| Source|http://mptw.tiddlyspot.com/#HideWhenPlugin|
| Author|Simon Baird <simon.baird@gmail.com>|
| License|http://mptw.tiddlyspot.com/#TheBSDLicense|
For use in ViewTemplate and EditTemplate. Example usage:
{{{<div macro="showWhenTagged Task">[[TaskToolbar]]</div>}}}
{{{<div macro="showWhen tiddler.modifier == 'BartSimpson'"><img src="bart.gif"/></div>}}}
***/
//{{{

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

merge(config.macros,{

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

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

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

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

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

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

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

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

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

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

});

//}}}

The context is a Debian etch GNU/Linux distribution.
[[Summary]]
[[Rationale]]
[[Use Cases]]
[[Scope]]
[[Design]]
[[Implementation]]
[[Unresolved Issues]]
[img[Cedre du barouk|images/small/Cedre du barouk.jpg][images/large/Cedre du barouk.jpg]]<<imagebox>>
# cmd openalpp osgal dachary.org /etc/bind
set -e
name="$1"
newname="$2"
domain="$3"
file="$4"
if grep -rl $name $file ; then
    grep -rl $name $file | xargs perl -ni -e 'if(/(\d+).*; serial/) { $s = $1; $s++; print "\t\t\t$s\t; serial\n"; } else { print; }' 
    grep -rl $name $file | xargs perl -pi -e "s/\b$name\b/$newname/g"
    ! grep -rl $name $file
    /etc/init.d/bind9 reload
    sleep 1
    ! getent hosts $name.$domain
    getent hosts $newname.$domain
fi
set -e
meta="$1"
name="$(xmlstarlet sel -t -v /appliance/@name < <(dog --no-header $meta))"
domain="$(xmlstarlet sel -t -v /appliance/@domain < <(dog --no-header $meta))"
author="$(xmlstarlet sel -t -v /appliance/@author < <(dog --no-header $meta))"
parent="$(xmlstarlet sel -t -v /appliance//nagios/@parent < <(dog --no-header $meta))"
address="$(xmlstarlet sel -t -v /appliance//nagios/@address < <(dog --no-header $meta))"
cd /etc/nagios2/conf.d
cat >> $domain.cfg <<EOF
define host {
        host_name   $name
        parents     $parent
        alias       $name mercurial
        address     $address
        hostgroups  http-servers, debian-servers
        use         http-host
        }
EOF
/etc/init.d/nagios2 stop ; sleep 2; /etc/init.d/nagios2 start
hg commit -u $author -m "monitor $name" $domain.cfg
echo DONE
# cmd openalpp osgal dachary.org loic@dachary.org
set -e
name="$1"
newname="$2"
domain="$3"
author="$4"
cd /etc/nagios2/conf.d
grep -l $name $domain.cfg
perl -pi -e "s/\b$name\b/$newname/ if(/host_name.*$name/ .. /\}/)" $domain.cfg
! grep -l $name $domain.cfg
/etc/init.d/nagios2 stop
sleep 1
/etc/init.d/nagios2 start
hg commit -u $author -m "nagios rename $name into $newname" /etc/nagios2
** Proppy wants the apache appliance to access the ~MySQL appliance.
** Both appliances are on the same LAN.
** Proppy creates a view in the ~BIND9 DNS serving the apache appliance.
** The view is only active for the 192.168.50.0/24 addresses.
** Within this view a new top level domain name is availble : .conf.
** Proppy defines mysql.conf to be the IP address of the mysql software appliance.
** Proppy configures the phpmyadmin available on the apache appliance to use the ~MySQL database from the mysql.conf host.
** When the apache appliance is moved on another LAN, the DNS of this new LAN must bind mysql.conf to the appropriate IP address. 
** Proppy will not have to make changes within the software appliance as long as all references to resources on the LAN are named within the .conf top level domain name.
After {{{NameVirtualHost *}}} add the following so that it catches all unknown hostnames instead of being delivered to the first virtual host.
{{{
<VirtualHost _default_>
ServerName fake
</VirtualHost>
}}}

{{{
(03:08:09 PM) dachary: yo
(03:08:50 PM) dachary: un petit tip apache2 ?
(03:10:23 PM) gryzor: y a qu'a demander, mon bon Loic :)
(03:11:52 PM) dachary: alors alors
(03:11:54 PM) dachary: hum
(03:12:02 PM) dachary: mais qui tu me connais toi que je te connais ?
(03:12:43 PM) gryzor: de vue seulement
(03:12:56 PM) dachary: question: apache2 + virtual host : comment faire pour qu'un host qui n'est pas explicitement liste donne une erreur ?
(03:13:07 PM) dachary: ma question est pas hyper claire
(03:13:14 PM) gryzor: il suffit de faire donner une erreur par le 1er virtualhost
(03:13:22 PM) dachary: mais comment ?
(03:13:24 PM) gryzor: (donc, de le dedier a cela)
(03:13:27 PM) dachary: ah
(03:13:28 PM) dachary: ah
(03:13:31 PM) dachary: hum
(03:13:33 PM) dachary: ok
(03:13:40 PM) dachary: j'essaye
(03:13:41 PM) dachary: smart
(03:13:41 PM) fajita: smart is not enabled
(03:13:50 PM) gryzor: ou alors de definir un virtualhost qui s'appelle "_default_"
(03:14:53 PM) dachary: <VirtualHost _default_>
(03:14:57 PM) dachary: genre ca ?
(03:18:01 PM) dachary: hum
(03:18:13 PM) dachary: alors bon ca marche mais ca a des effets zarb
(03:19:52 PM) gryzor: faq1
(03:19:52 PM) fajita: The value of a NameVirtualHost directive has to match the content of <VirtualHost> exactly. For example, NameVirtualHost *:80 must be used with <VirtualHost *:80>
(03:20:47 PM) dachary: ...
(03:20:50 PM) dachary: ok
(03:20:57 PM) dachary: faq0 : url de la faq ?
(03:21:01 PM) dachary: nan j'abuse ;-)
(03:21:37 PM) dachary: <VirtualHost *>
(03:21:42 PM) dachary: ServerName pokersource.info
(03:21:48 PM) dachary: ServerAlias www.pokersource.info
(03:21:56 PM) dachary: et avant j'ai
(03:22:12 PM) dachary: <VirtualHost _default_>
(03:22:27 PM) dachary: et avant j'ai
(03:22:33 PM) dachary: NameVirtualHost *
(03:22:33 PM) fajita: NameVirtualHost * is 6usually what you want, if you only have one ip address
(03:22:43 PM) dachary: j'ai une seule IP
(03:22:58 PM) dachary: j'ai lu la faq mais la logique m'echape
(03:23:03 PM) dachary: *:80 ce n'est pas *exact*
(03:23:10 PM) dachary: pisque y'a un wildcard
(03:23:28 PM) dachary: donc je comprends pas ce que veut dire "exactly" dans ce contexte
(03:23:46 PM) dachary: ou alors il faut que je mette
(03:23:56 PM) dachary: NameVirtualHost pokersource.info:80
(03:23:58 PM) dachary: avant 
(03:24:08 PM) dachary: <VirtualHost pokersource.info:80>
(03:24:21 PM) dachary: je vais essayer ca
(03:24:32 PM) gryzor: non surtout pas
(03:24:41 PM) dachary: y'a un truc qui m'echape
(03:24:47 PM) dachary: ca doit etre enorme
(03:24:54 PM) gryzor: jamais de nom comme parametre a VirtualHost
(03:24:59 PM) gryzor: toujours une IP, ou une *
(03:25:07 PM) gryzor: ou _default&#195;_
(03:25:32 PM) gryzor: donc la conf avec * et _default_ est bonne
(03:25:36 PM) gryzor: tu as quoi comme effet de bord ?
(03:25:41 PM) dachary: ok
(03:26:01 PM) dachary: http://pokersource.info/ -> not found
(03:26:09 PM) dachary: http://www.pokersource.info/ -> ok
(03:26:16 PM) gryzor: ServerAlias
(03:26:16 PM) fajita: ServerAlias is http://httpd.apache.org/docs/2.2/mod/core.html#serveralias or http://httpd.apache.org/docs/1.3/mod/core.html#serveralias
(03:26:17 PM) dachary: j'ajoute le :80
(03:26:31 PM) dachary: je regarde
(03:26:43 PM) dachary: ServerAlias www.pokersource.info
(03:26:49 PM) gryzor: voila
(03:26:54 PM) dachary: j'ai ca deja
(03:26:59 PM) gryzor: et en ServerName
(03:27:03 PM) gryzor: ?
(03:27:52 PM) gryzor: dns www.pokersource.info
(03:27:53 PM) fajita: gryzor: www.pokersource.info is 88.191.250.37
(03:27:55 PM) dachary: ServerName pokersource.info
(03:27:55 PM) gryzor: dns pokersource.info
(03:27:55 PM) fajita: gryzor: pokersource.info is 88.191.250.37
(03:27:59 PM) dachary: voila
(03:28:20 PM) gryzor: aucun des 2 ne fonctionne
(03:28:26 PM) dachary: NameVirtualHost *
(03:28:26 PM) dachary: <VirtualHost _default_>
(03:28:26 PM) dachary: </VirtualHost>
(03:28:26 PM) dachary: <VirtualHost *>
(03:28:26 PM) dachary:         ServerName pokersource.info
(03:28:26 PM) dachary:         ServerAlias www.pokersource.info
(03:28:26 PM) dachary:  
(03:28:27 PM) fajita: NameVirtualHost * is 6usually what you want, if you only have one ip address
(03:28:29 PM) gryzor: The requested URL / was not found on this server.
(03:28:40 PM) gryzor: apc
(03:28:40 PM) fajita: Try using http://apache.pastebin.ca - It's a good pastebin, and is even set up to highlight Apache 'stuff'.
(03:28:44 PM) dachary: www.pokersource.info ne marche pas ??
(03:28:47 PM) gryzor: non
(03:28:52 PM) gryzor: vide ton cache
(03:29:00 PM) dachary: putain de firefox de mes couilles !!!!
(03:29:22 PM) dachary: :-)
(03:29:58 PM) dachary: hum
(03:30:10 PM) dachary: wget http://www.pokersource.info/ ca marche chez moi
(03:30:20 PM) dachary: je regarde les logs
(03:31:25 PM) gryzor: ok, maintenant oui
(03:32:04 PM) dachary: uof
(03:32:04 PM) dachary: ouf
(03:32:06 PM) dachary: :-)
(03:32:18 PM) dachary: par contre wget http://pokersource.info/ marche pas
(03:32:26 PM) dachary: avec la config ci dessus
(03:32:38 PM) gryzor: que dit le journal d'erreurs
(03:32:39 PM) gryzor: ?
(03:33:58 PM) dachary: file does not exist /htdocs
(03:34:10 PM) gryzor: paste config
(03:34:28 PM) gryzor: fajita: paste config
(03:34:28 PM) fajita: gryzor: i'm not following you...
(03:34:37 PM) gryzor: bon, 
(03:34:39 PM) gryzor: stupid bot
(03:34:39 PM) fajita: Dumb human.
(03:34:47 PM) dachary: http://hg.pokersource.info/file/7cde5a08ed7f/etc/apache2/sites-available/default
(03:34:54 PM) dachary: :-)
(03:35:01 PM) dachary: j'ai juste change le debut
(03:35:04 PM) dachary: de la config
(03:35:15 PM) dachary: comme montre ci dessus
(03:36:16 PM) gryzor: tout VirtualHost devrait avoir un ServerName
(03:36:50 PM) dachary: oh
(03:36:56 PM) dachary: y compris le premier _default_ ?
(03:37:07 PM) gryzor: oui
(03:37:14 PM) gryzor: meme si le nom est bidon
(03:37:16 PM) dachary: ah
(03:37:19 PM) dachary: je fais
(03:38:37 PM) dachary: http://hg.pokersource.info/file/a61226fbf24e/etc/apache2/sites-available/default
(03:38:39 PM) dachary: marche mieux
(03:38:41 PM) dachary: :-)
(03:38:52 PM) dachary: j'aurais JAMAIS trouve cette subtilite
(03:39:27 PM) gryzor: disons que c a ca que le support sert :)
(03:39:28 PM) dachary: c'est genial
(03:39:39 PM) dachary: ben bravo les gars
}}}
PasswordOptionPlugin is not compatible TiddlyWiki version 2.1.
See http://tiddlylab.bidix.info/#PasswordOptionPlugin
** Proppy wants to add a forum to the apache appliance.
** Using //hg incoming//, proppy checks if pending modifications from the publicly available apache appliance need to be transfererd to the copy running on his laptop.
** After applying the changes, proppy installs the forum.
** Proppy tests the forum and asks his friends to give it a try using the 37080 port that is being forwarded to his laptop.
** Turns out that the forum is a really bad software that requires too much work. 
** Proppy stops the apache appliance and revert to the state it was before trying the forum software using the //hg revert// command.
** When proppy is satisfied with the forum software installed, he creates a changeset and publishes it to the publicly available appliance. 
set -e
app=dog ; apt-get install -y --force-yes $app
app=xmlstarlet ; apt-get install -y --force-yes $app
meta="$1"
name="$(xmlstarlet sel -t -v /appliance/@name < <(dog --no-header $meta))"
domain="$(xmlstarlet sel -t -v /appliance/@domain < <(dog --no-header $meta))"
url="$(xmlstarlet sel -t -v /appliance//garden/@url < <(dog --no-header $meta))"
seed="$(xmlstarlet sel -t -v /appliance//garden/@seed < <(dog --no-header $meta))"
mkdir -p /home/www
cd /home/www
wget -q "$url"
wget -q "$seed"
echo DONE
** Proppy wants to publish sensitive information as part of the software appliance
** The information is not essential for the appliance to work
** It's not extremely sensitive either, otherwise proppy would not publish it at all
** Proppy installs seahorse, the gnome cryptographic assistant
** Proppy uses nautilus to select the files or directories that he want to encrypt
** When asked by seahorse, proppy crypts the selected files for decryption by himself and a few others
** Proppy creates a skeleton vserver on the OS where a public IP was dedicated to the apache appliance.
** The skeleton vserver has a LAN IP that will receive incoming connections from the public IP.
** Proppy edits the DNS to define the .conf names required by the apache appliance.
** Proppy creates a mercurial repository at the root of the apache appliance.
** Proppy stops the apache appliance on his laptop.
** The apache appliance is rsync'ed from the laptop to the remote OS.
** Proppy starts the appliance on the remote OS and accesses it from the public IP.
When running a networked service there is a need to experiment with a clone while the original is still available to the public. Virtual machines are easy to setup based on a backup of an existing virtual server. Switches, cables and firewalls are less intuitives to replicate.
dachary:~# meta=http://garden.conf.tld/packaging-farm.xml
dachary:~# echo $name.$domain
.
dachary:~# name="$(xmlstarlet sel -t -v /appliance/@name < <(dog --no-header $meta))"
dachary:~# domain="$(xmlstarlet sel -t -v /appliance/@domain < <(dog --no-header $meta))"
dachary:~# author="$(xmlstarlet sel -t -v /appliance/@author < <(dog --no-header $meta))"
dachary:~# a2dissite $name.$domain
Site packaging-farm.dachary.org disabled; run /etc/init.d/apache2 reload to fully disable.
dachary:~# hg addremove /etc/apache2/
removing ../etc/apache2/sites-enabled/packaging-farm.dachary.org
dachary:~# rm -f /etc/apache2/sites-available/packaging-farm.dachary.org
dachary:~# hg addremove /etc/apache2/
removing ../etc/apache2/sites-available/packaging-farm.dachary.org
dachary:~# #hg commit -u $author -m "remove proxy for $name.$domain" /etc/apache2
dachary:~# hg status /etc/apache2
R ../etc/apache2/sites-available/packaging-farm.dachary.org
R ../etc/apache2/sites-enabled/packaging-farm.dachary.org
dachary:~# hg commit -u $author -m "remove proxy for $name.$domain" /etc/apache2
# rm /var/log/apache/*$name*
dachary:~# echo DONE
DONE
dachary:~#


pecho:~# meta=http://garden.conf.tld/packaging-farm.xml
pecho:~# name="$(xmlstarlet sel -t -v /appliance/@name < <(dog --no-header $meta))"
pecho:~# echo $name
packaging-farm
pecho:~# vserver $name stop
*** output flushed ***
pecho:~# vserver $name status
*** output flushed ***
pecho:~# vserver $name status | grep stop
Vserver 'packaging-farm' is stopped
pecho:~#
dachary:/etc# meta=http://garden.conf.tld/packaging-farm.xml
dachary:/etc# name="$(xmlstarlet sel -t -v /appliance/@name < <(dog --no-header "$meta"))"
dachary:/etc# rss="$(xmlstarlet sel -t -v /appliance/rss/@url < <(dog --no-header "$meta"))"
dachary:/etc# echo $name
packaging-farm
dachary:/etc# #perl -pi -e '$_ = "" if(/\['$rss'/)' /etc/planet.conf
dachary:/etc# grep $rss /etc/planet.conf
http://packaging-farm.conf.tld:8000/rss-log
dachary:/etc# #perl -pi -e '$_ = "" if(/\['$rss'/)' /etc/planet.conf
dachary:/etc# grep $rss /etc/planet.conf
[http://packaging-farm.conf.tld:8000/rss-log]
dachary:/etc# perl -pi -e '$_ = "" if(/\['$rss'/)' /etc/planet.conf
Warning: Use of "log" without parentheses is ambiguous at -e line 1.
syntax error at -e line 1, near "tld:"
Search pattern not terminated at -e line 1.
dachary:/etc# perl -pi -e '$_ = "" if(|\['$rss'|)' /etc/planet.conf
Bareword found where operator expected at -e line 1, near "//packaging"
        (Missing operator before packaging?)
syntax error at -e line 1, near "(|"
Missing right curly or square bracket at -e line 1, at end of line
Execution of -e aborted due to compilation errors.
dachary:/etc# perl -pi -e '$_ = "" if(m|\['$rss'|)' /etc/planet.conf
dachary:/etc# grep $rss /etc/planet.conf
dachary:/etc# #perl -pi -e '$_ = "" if(m|^name = '$name'|)' /etc/planet.conf
dachary:/etc# grep '^name = '$name /etc/planet.conf
dachary:/etc# grep '^name = '$name /etc/planet.conf
name = packaging-farm
dachary:/etc# perl -pi -e '$_ = "" if(m|^name = '$name'|)' /etc/planet.conf
dachary:/etc# grep '^name = '$name /etc/planet.conf
dachary:/etc#


[[Rename a software appliance (script)]]
# [[Modify a DNS entry to change a host name]] on the DNS hosting the public name
# [[Modify a DNS entry to change a host name]] on the DNS hosting the vserver
# [[Rename a vserver]] with the new name
# [[Apache proxy name change]] with the new name
# [[Nagios monitored vserver name change]] with the new name
# [[Rename planet aggregated feed]] with the new name
# [[Rename shorewall port redirections]] with the new name
mkdir app
cd app
mkdir universe
ruby /usr/bin/tiddlywiki_cp -a http://garden.dachary.org/universe.html universe

author=loic@dachary.org
name=feed-reader
newname=yocto-reader
domain=dachary.org
file=/etc/bind
public_ns=ns2.fsffrance.org
scp universe/Modify\ a\ DNS\ entry\ to\ change\ a\ host\ name.tiddler root@$public_ns:/tmp/step1
ssh root@$public_ns sh -x /tmp/step1 $name $newname $domain $file $author

vserver_realm=fsf
realm=dachary
vserver_host=pecho.fsffrance.org
scp universe/Modify\ a\ DNS\ entry\ to\ change\ a\ host\ name.tiddler root@$vserver_host:/tmp/step2
ssh root@$vserver_host sh -x /tmp/step2 $name $newname $realm.$vserver_realm.tld $file $author

scp universe/Rename\ a\ vserver.tiddler root@$vserver_host:/tmp/step3
ssh root@$vserver_host sh -x /tmp/step3 $name $newname $author

proxy_vserver_host=pecho.fsffrance.org
proxy_name=dachary
scp universe/Apache\ proxy\ name\ change.tiddler root@$proxy_vserver_host:/var/lib/vservers/$proxy_name/tmp/step4
ssh root@$proxy_vserver_host vserver $proxy_name exec "sh -x /tmp/step4 $name $newname $domain $author"

nagios_vserver_host=mango.pokersource.info
nagios_name=nagiosfsf
scp universe/Nagios\ monitored\ vserver\ name\ change.tiddler root@$nagios_vserver_host:/var/lib/vservers/$nagios_name/tmp/step5
ssh root@$nagios_vserver_host vserver $nagios_name exec "sh -x /tmp/step5 $name $newname $domain $author"

rss_host=dachary.org
scp universe/Rename\ planet\ aggregated\ feed.tiddler root@$rss_host:/tmp/step6
ssh root@$rss_host sh -x /tmp/step6 $name $newname $author
# cmd openalpp osgal 
set -e

name="$1"
newname="$2"

vserver $name stop
#http://oldwiki.linux-vserver.org/TweakingTheConfig
mv /etc/vservers/$name /etc/vservers/$newname
mv /var/lib/vservers/$name /var/lib/vservers/$newname
cd /etc/vservers/$newname
rm cache run vdir
ln -s /etc/vservers/.defaults/cachebase/$newname cache
ln -s /var/run/vservers/$newname run
ln -s /etc/vservers/.defaults/vdirbase/$newname vdir
xid=$(cat context)
rm /var/run/vservers.rev/$xid
ln -s /etc/vservers/$newname /var/run/vservers.rev/$xid
echo $newname > name
perl -pi -e "s/\b$name\b/$newname/" uts/nodename
grep -rl $name /var/lib/vservers/$newname/var/cache/mercurial/rss | xargs perl -pi -e "s/\b$name\b/$newname/" 
grep -rl $name /var/lib/vservers/$newname/etc/default /var/lib/vservers/$newname/etc/hosts | xargs perl -pi -e "s/\b$name\b/$newname/" 
vserver $newname start
# cmd openalpp osgal dachary.org loic@dachary.org
set -e
name="$1"
newname="$2"
author="$3"
cd /etc/
grep -l $name planet.conf
perl -pi -e "s/\b$name\b/$newname/" planet.conf
! grep -l $name planet.conf
for file in /var/cache/planet/*$name* ; do
    newfile=$(echo $file | perl -p -e "s/\b$name\b/$newname/g")
    mv $file $newfile
done
hg commit -u $author -m "planet rename $name into $newname" /etc/planet.conf
something like /etc/shorewall/$ip/$name /etc/shorewall/$ip/$newname
/***
| Name:|RenameTagsPlugin|
| Description:|Allows you to easily rename or delete tags across multiple tiddlers|
| Version:|3.0 ($Rev: 1845 $)|
| Date:|$Date: 2007-03-16 15:19:22 +1000 (Fri, 16 Mar 2007) $|
| Source:|http://mptw.tiddlyspot.com/#RenameTagsPlugin|
| Author:|Simon Baird <simon.baird@gmail.com>|
| License|http://mptw.tiddlyspot.com/#TheBSDLicense|
Rename a tag and you will be prompted to rename it in all its tagged tiddlers.
***/
//{{{
config.renameTags = {

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

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

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

	storeMethods: {

		saveTiddler_orig_renameTags: TiddlyWiki.prototype.saveTiddler,

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

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

		removeTiddler_orig_renameTags: TiddlyWiki.prototype.removeTiddler,

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

	},

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

config.renameTags.init();

//}}}

** Proppy wants to use his ssh private key from withing the vserver to gain write access to a SVN repository
** Proppy adds the following lines to /etc/vservers/pokerdev/fstab
{{{
/home/proppy /home/proppy	none bind 0 0
}}}
** Proppy mkdir /home/proppy within the vserver
** Proppy adds the following line in /etc/ssh/sshd_config
{{{
X11UseLocalhost no
}}}
** Proppy installs xauth so that X11 forwarding works
{{{
apt-get install xbase-clients
}}}
** Proppy creates the file /etc/hosts with the following content where pokerdev.pokersource.info is the hostname of the vserver and 192.168.70.18 is its IP
{{{
192.168.70.18 pokerdev.pokersource.info
}}}
** Proppy creates the user proppy making sure the uid matches his local machine uid (1000) in this case. He also inserts himself in the users group (100) so that other users of the same appliance can group with him.
{{{
adduser --gecos 'Proppy Aminche' --disabled-password  --uid 1000 --gid 100 proppy
}}}
** Proppy logs in the server using
{{{
ssh -X proppy@pokerdev
}}}
** Proppy apt-get install ssh-askpass or another package providing X11 based passphrase challenge
** Proppy sets the following environment variables when he wants to work as root. Although he prefers to work as himself, his home is not always available when in a remote location.
{{{
export SVN_SSH='ssh -i /home/proppy/.ssh/id_rsa'
export SSH_ASKPASS=/usr/lib/ssh/x11-ssh-askpass
}}}
** Proppy extracts a svn tree in /usr/src, making sure the directory have the setgid bit set to allow editing by other members of the users group
** Proppy installs emacs-snapshot because emacs does not have the svn-status command
** Proppy runs emacs, edit files, run svn-status and when commiting with svn-status gives his passphrase to write the repository
Vritual machines are meant to be used in the context of an online service. Average GNU/Linux system administration skills are required.

No software must be implemented. If a new ~BIND9 feature or a vserver feature is to be implemented, another specification has to be written.
including OS, cables, switches and firewalls
Software Appliances
http://garden.dachary.org/universe.html
Virtual machines such as vmware, xen instances, vserver or even chroot can be connected using virtual cables  and switches and their access controled by virtual firewalls. 
set -e
meta="$1"
name="$(xmlstarlet sel -t -v /appliance/@name < <(dog --no-header $meta))"
rss="$(xmlstarlet sel -t -v /appliance/rss/@url < <(dog --no-header $meta))"
echo "[$rss]" >> /etc/planet.conf
echo "name = $name" >> /etc/planet.conf
su www-data -c 'planetplanet -v /etc/planet.conf'
echo DONE
/***
| Name|TagglyTaggingPlugin|
| Description|tagglyTagging macro is a replacement for the builtin tagging macro in your ViewTemplate|
| Version|3.1 ($Rev: 2341 $)|
| Date|$Date: 2007-07-05 10:02:27 +1000 (Thu, 05 Jul 2007) $|
| Source|http://mptw.tiddlyspot.com/#TagglyTaggingPlugin|
| Author|Simon Baird <simon.baird@gmail.com>|
| License|http://mptw.tiddlyspot.com/#TheBSDLicense|
!Notes
See http://mptw.tiddlyspot.com/#TagglyTagging
***/
//{{{
config.taggly = {

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

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

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

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

	setTagglyOpt: function(title,opt,value) {
		if (!store.tiddlerExists(title))
			// create it silently
			store.saveTiddler(title,title,config.views.editor.defaultText.format([title]),config.options.txtUserName,new Date(),null);
		// if value is default then remove it to save space
		return store.setValue(title,
			this.config.valuePrefix+opt,
			value == this.config.listOpts[opt][0] ? null : value);
	},

	getNextValue: function(title,opt) {
		var current = this.getTagglyOpt(title,opt);
		var pos = this.config.listOpts[opt].indexOf(current);
		// a little usability enhancement. actually it doesn't work right for grouped or sitemap
		var limit = (opt == "numCols" ? store.getTaggedTiddlers(title).length : this.config.listOpts[opt].length);
		var newPos = (pos + 1) % limit;
		return this.config.listOpts[opt][newPos];
	},

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

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

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

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

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

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

		var upperColsize = colSize;
		var lowerColsize = colSize;

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

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

		return output;
	},

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

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

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

	getExcerpt: function(inTiddlerTitle,title,indent) {
    if (!indent)
			indent = 1;
		if (this.getTagglyOpt(inTiddlerTitle,"excerpts") == "excerpts") {
			var t = store.getTiddler(title);
			if (t) {
				var text = t.text.replace(/\n/," ");
				var marker = text.indexOf(this.config.excerptMarker);
				if (marker != -1) {
					return " {{excerpt{<nowiki>" + text.substr(0,marker) + "</nowiki>}}}";
				}
				else if (text.length < this.config.excerptSize) {
					return " {{excerpt{<nowiki>" + t.text + "</nowiki>}}}";
				}
				else {
					return " {{excerpt{<nowiki>" + t.text.substr(0,this.config.excerptSize) + "..." + "</nowiki>}}}";
				}
			}
		}
		else if (this.getTagglyOpt(inTiddlerTitle,"excerpts") == "contents") {
			var t = store.getTiddler(title);
			if (t) {
				return "\n{{contents indent"+indent+"{\n" + t.text + "\n}}}";
			}
		}
		else if (this.getTagglyOpt(inTiddlerTitle,"excerpts") == "sliders") {
			var t = store.getTiddler(title);
			if (t) {
				return "<slider slide>\n{{contents{\n" + t.text + "\n}}}\n</slider>";
			}
		}
		return "";
	},

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

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

		var list = store.getTaggedTiddlers(title,this.getTagglyOpt(title,"sortBy"));

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

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

				first = false;
			}
		}

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

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

		var list = store.getTaggedTiddlers(title,sortBy);

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

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

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

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

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

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

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

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

						}
					}
				}
			}
		}

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

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

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

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

		var output = [];

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

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

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

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

	},

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

		var list = store.getTaggedTiddlers(title,sortBy);
		if (sortOrder == "desc")
			list.reverse();

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

		var childOutput = "";
		for (var i=0;i<list.length;i++)
			if (list[i].title != title)
				if (this.notHidden(list[i].title,this.config.inTiddler))
					childOutput += this.treeTraverse(list[i].title,depth+1,sortBy,sortOrder);

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

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

	macros: {
		tagglyTagging: {
			handler: function (place,macroName,params,wikifier,paramString,tiddler) {
				var refreshContainer = createTiddlyElement(place,"div");
				// do some refresh magic to make it keep the list fresh - thanks Saq
				refreshContainer.setAttribute("refresh","macro");
				refreshContainer.setAttribute("macroName",macroName);
        			refreshContainer.setAttribute("title",tiddler.title);
				this.refresh(refreshContainer);
			},

			refresh: function(place) {
				var title = place.getAttribute("title");
				removeChildren(place);
				if (store.getTaggedTiddlers(title).length > 0) {
					var lingo = config.taggly.lingo;
					config.taggly.createListControl(place,title,"hideState");
					if (config.taggly.getTagglyOpt(title,"hideState") == "show") {
						createTiddlyElement(place,"span",null,"tagglyLabel",lingo.labels.label.format([title]));
						config.taggly.createListControl(place,title,"title");
						config.taggly.createListControl(place,title,"modified");
						config.taggly.createListControl(place,title,"created");
						config.taggly.createListControl(place,title,"listMode");
						config.taggly.createListControl(place,title,"excerpts");
						config.taggly.createListControl(place,title,"numCols");
						config.taggly.createTagglyList(place,title);
					}
				}
			}
		}
	},

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

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

config.taggly.init();

//}}}

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

// syntax adjusted to not clash with NestedSlidersPlugin

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

//}}}

/***
|''Name:''|TiddlyLightBox|
|''Date:''|Jan 1, 2006|
|''Version:''|1.0 beta|
|''Author:''|Saq Imtiaz|
|''Location:''|http://tw.lewcid.org/#TiddlyLightBoxPlugin|
|''Documentation:''|http://tw.lewcid.org/#TiddlyLightBoxDocs|
|''License:''|[[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|''Based on:''|DC3.LightBox<br>Light Box Gone Wild <br>Ibox|

!!Code
***/
//{{{
config.macros.imagebox ={};
config.macros.imagebox.handler = function (place,macroName,params,wikifier,paramString,tiddler)
{
    var e = place.lastChild;
    e.onclick = function(){TiddlyLightBox.initBox('image',this,params[1],params[2],params[0]);return false;};
}

config.macros.divbox ={};
config.macros.divbox.handler = function (place,macroName,params,wikifier,paramString,tiddler)
{
    if (params[0]!=".")
        createTiddlyButton(place,params[0],params[0],function(){TiddlyLightBox.initBox('html',params[1],params[3],params[4],params[2]);return false;});
    else
        {
        var e = place.lastChild;
        e.onclick = function(){TiddlyLightBox.initBox('html',params[1],params[3],params[4],params[2]);return false;};
        }
}

config.macros.tiddlerbox ={}
config.macros.tiddlerbox.handler = function (place,macroName,params,wikifier,paramString,tiddler)
{
    config.macros.divbox.handler(place,macroName,[params[0],"tiddler:"+params[1],params[2],params[3],params[4]]);
    return false;
}

store.addNotification("TiddlyLightBoxStyles",refreshStyles);

if (!window.TiddlyLightBox)
    window.TiddlyLightBox = {};
    var loadingImage = "indicator.gif";
    window.TiddlyLightBox =
    {
    _curBox: null, // [sentinel]

    lightBoxHtml : '<div id="lightBoxOverlay" onclick="TiddlyLightBox.hideBox()" style="display:none"></div><div id="lightboxprogress" style="display:none;"><img src=\''+loadingImage+'\' alt=\'loading\' style="width:128px;height:128px;"></div><div class="lightBox" id="lightBox" style="display:none"><div id="lightBoxContent"></div><div id="lightBoxTitle">This is a title</div><div id="lightBoxClose"><a href:"#" onclick="TiddlyLightBox.hideBox();return false;">Click to close</a></div></div>',

    createBoxWrapper : function()
        {
        var wrapper = createTiddlyElement(document.getElementsByTagName("body")[0],"div","tiddlyLightBoxWrapper");
        wrapper.innerHTML = this.lightBoxHtml;
        },

    initBox : function(contentType,url,w,h,text)
        {
        if (this._curBox)
            return;
        this.showProgress();
        this.hideSelects("hidden");
        this.showBg();
        this._curBox = true;
        this.sizeTheBox(contentType,w,h);
        if (contentType == 'image')
            this.showImage(url,text);
        else if (contentType == 'html')
            this.showHtml(url,text);
        return false;
        },
        
    sizeTheBox : function(contentType,w,h)
        {
        var box = document.getElementById("lightBoxContent");
        if (w && isNaN(parseInt(w)))
            {
            addClass(box,w);
            }
        else if (w ||h || contentType == 'html')
            {
            box.style.width = w? w+ "px" : "450px";
            box.style.height = h? h+ "px" : "280px";
            if (contentType=='image')
                setStylesheet("#lightBoxContent img{height:100%;width:100%;}","lightBoxImageSizeHack");
            }
        },

    showProgress : function()
        {
        var progress = document.getElementById("lightboxprogress");
        progress.style.display='';
        this._center(progress);
        },
    
    hideProgress: function()
        {
        var progress = document.getElementById("lightboxprogress");
        progress.style.display='none';
        },

    //this function lifted from Lightbox Gone Wild
    hideSelects: function(visibility)
        {
        var selects = document.getElementsByTagName('select');
        for(i = 0; i < selects.length; i++)
            {
            selects[i].style.visibility = visibility;
            }
        },

    showBg: function()
        {
        var overlay = document.getElementById('lightBoxOverlay');
        if (config.browser.isIE)
            {
            overlay.style.height = Math.max(document.documentElement.scrollHeight,document.documentElement.offsetHeight);
            overlay.style.width = document.documentElement.scrollWidth;
            }
        overlay.style.display = 'block';
        },

    showImage: function (url,text)
        {
        imgPreloader = new Image();
        imgPreloader.onload = function ()
            {
            var lb = document.getElementById("lightBoxContent");
            lb.innerHTML = "<img src="+url+">";
            lb.onclick = function(){TiddlyLightBox.hideBox();return false;};
            TiddlyLightBox.posBox(text);
            };
        imgPreloader.src = url;
        },
        
    showHtml : function(theID,text)
        {
        var lb = document.getElementById("lightBoxContent");
        if (theID.indexOf("tiddler:")==-1)
             lb.innerHTML = document.getElementById(theID).innerHTML;
        else
            { 
             wikify(store.getTiddlerText(theID.replace("tiddler:","")),lb);
             lb.className='tiddler';
            }
        lb.style.overflow = "auto";
        this.posBox(text);
        },

    posBox: function(text)
       {
       this.setTitle(text);
       this.hideProgress();
       var lb = document.getElementById("lightBox");
       lb.style.display = "";
       lb.style.visibilty = "hidden";
       lb.style.position = "absolute";
       this._center(lb);
       if(!TiddlyLightBox._curBox) return;
       lb.style.visibility = "visible";
       lb.style.display = "block";
       },

     setTitle: function(text)
        {
        document.getElementById("lightBoxTitle").innerHTML=  (text==undefined)? '': text;
        },

    _center: function(lb)
       {
       var lbSize = new TiddlyLightBox.getElementSize(lb);
       lb.style.left = (Math.round(findWindowWidth()/2) - (lbSize.width /2) + findScrollX())+'px';
       lb.style.top = (Math.round(findWindowHeight()/2) - (lbSize.height /2) + findScrollY())+'px';
       },

    //this function lifted from Ibox
    getElementSize : function(elem)
       {
       this.width = elem.offsetWidth || elem.style.pixelWidth;
       this.height = elem.offsetHeight || elem.style.pixelHeight;
       },

     hideBox: function()
         {
         if(!this._curBox)
             return;
         document.getElementById("tiddlyLightBoxWrapper").innerHTML= this.lightBoxHtml;
         setStylesheet("","lightBoxImageSizeHack");
         this._curBox = null;
         return false;
         }
}

TiddlyLightBox.createBoxWrapper();

Story.prototype.findContainingTiddler = function(e)
{
    while(e && (!hasClass(e,"tiddler") || !e.getAttribute("tiddler")))
        e = e.parentNode;
    return(e);
}

config.shadowTiddlers.TiddlyLightBoxStyles="/*{{{*/\n#lightBoxOverlay {\n position:absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n z-index: 90; \n background-color: #000;\n -moz-opacity: 0.75;\n opacity: .75;\n filter: alpha(opacity=75);\n}\n#lightBoxOverlay[id]{ \n position: fixed;\n}\n\n#lightboxprogress { \n margin:0;padding:0;\n position: absolute;\n z-index:95;\n}\n\ndiv.lightBox {\n background: #fff;\n color: #fff;\n border: 4px solid #525252;\npadding:20px 20px 25px 20px; position:absolute; z-index:99;\n}\n\n#lightBoxClose {text-align:right; color:#000; font-size:1.0em; position:absolute; bottom:6px; right:20px;}\n#lightBoxClose a{color:#666; border-bottom:1px solid #666;cursor:pointer;}\n#lightBoxClose a:hover {color:#111; border-bottom:1px solid #666; cursor:pointer; background:transparent;}\n\n#lightBoxContent {border:1px solid #525252;color:#000; background:#fff;}\n#lightBox .tiddler {background:#fff;}\n\n#lightBoxContent img {border:0;margin:0;padding:0;display:block;cursor:pointer;}\n\n#lightBoxTitle {padding:0px; font-weight:bold; position:absolute; left:20px;bottom:6px; font-size:1.1em; color:#000;}\n\n/*}}}*/";
//}}}
* When a package installation spans more than one software appliance (forum installation implying database configuration) the result can't be published with mercurial.
* The content of a database is usualy stored in binary form and text based tools can't be used for backups.
* mercurial does not handle symbolic links or empty directories (0.9.3)
* ''X11 forwarding depends on a match between the IP and the hostname (either from the DNS or from hosts)''
* /etc/resolv.conf must list an IP that depends on the DNS address available on a given vserver host. There is maybe a way to update this globaly from /etc/vserver 
* //hg pull// can't be used in [[Patching the apache appliance]] because the hg protocol transmits too many information and it lasts for ages. This is not going to change any time soon.

<<<
With a //linux-2.6// kernel, creating a virtual ethernet interface is made easy. 
{{{
apt-get install vlan
}}}
provides the extensions needed for ///etc/network/interfaces//. To create the //eth0.2// interface add the following lines to ///etc/network/interfaces//.
//sources.list// and //resolv.conf// are to be modified when moving the appliance because they are geographicaly dependent.
{{{
auto eth0.2
iface eth0.2 inet static
        address 192.168.50.1
        netmask 255.255.255.0
	pre-up modprobe 8021q
#	up iptables -t nat -A POSTROUTING -o eth1 -j MASQUERADE
#	up iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
	up echo 0 > /proc/sys/net/ipv4/conf/eth0.2/rp_filter

}}}
Note that once this is done, packets originating from the 192.168.50.0/24 subnet won't be routed because the MASQUERADE lines are commented out. Routing is being dealt with by shorewall. However, if you don't have or don't want shorewall, the MASQUERADE lines will do the work.
<<<
<!--{{{-->
<div class='toolbar' macro='toolbar closeTiddler closeOthers +editTiddler > fields syncing permalink references jump'></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="tagglyTagging" macro="tagglyTagging"></div>
<div class='tagged' macro='tags'></div>
<div macro="hideWhen tiddler.tags.containsAny(['css','html','pre','systemConfig']) && !tiddler.text.match('{{'+'{')">
<div class='viewer' macro='view text wikified'></div>
</div>
<div macro="showWhen tiddler.tags.containsAny(['css','html','pre','systemConfig']) && !tiddler.text.match('{{'+'{')">
<div class='viewer'><pre macro='view text'></pre></div>
</div>
<div class='tagClear'></div>
<!--}}}-->
/***
|''Name:''|WebDavPlugin|
|''Description:''|Allows a TiddlyWiki to be saved to a WebDav server|
|''Author:''|Saq Imtiaz ( lewcid@gmail.com )|
|''Co-author:''|Loic Dachary|
|''Source:''|http://tw.lewcid.org/#WebDavPlugin|
|''Code Repository:''|http://tw.lewcid.org/svn/plugins|
|''Version:''|1.0|
|''Date:''|17/11/2007|
|''License:''|[[Creative Commons Attribution-ShareAlike 3.0 License|http://creativecommons.org/licenses/by-sa/3.0/]]|
|''~CoreVersion:''|2.2.3|

***/
// /%
//!BEGIN-PLUGIN-CODE
DAV = {
	run : function(type,u,data,cb,params,headers){
		var callback = function(status,params,responseText,url,xhr) {
			url = url.indexOf("nocache=") < 0 ? url : url.substring(0,url.indexOf("nocache=")-1);
			if(params.length){
				params.shift().apply(this,[status,params,responseText,url,xhr]);
			}
		};	
		params = params||[];
		params.unshift(cb);		
		var r = doHttp.apply(this,[type,u,data,null,null,null,callback,params,headers]);
		if (typeof r == "string")
			alert(r);
		return r;
	},
	
	get : function(url,cb,params){
		return DAV.run("GET",url,null,cb,params,null);
	},

	put : function(url,cb,params,data) {
		return DAV.run("PUT",url,data,cb,params,null);
	},

	move : function(url,cb,params,destination) {
		return DAV.run("MOVE",url,null,cb,params,{"Destination":destination,"Overwrite":"T"});
	}, 

	copy : function(url,cb,params,destination) {
		return DAV.run("COPY",url,null,cb,params,{"Destination":destination,"Overwrite":"T","Depth":0});
	},
	
	propfind : function(url,cb,params,prop,depth){	// !!!
		var xml = '<?xml version="1.0" encoding="UTF-8" ?>' +
			'<D:propfind xmlns:D="DAV:">' +
			'<D:prop>'+
			'<D:'+prop+'/>'+
			'</D:prop>'+
			'</D:propfind>';
		return DAV.run("PROPFIND",url,xml,cb,params,{"Content-type":"text/xml","Depth":depth?depth:0});
	},
	
	makeDir : function(url,cb,params){
		return DAV.run("MKCOL",url,null,cb,params,null);
	},

	options : function(url,cb,params){
		return DAV.run("OPTIONS",url,null,cb,params,null);
	},
	
	safeput : function(url,cb,params,data){
		firstcb = function(status,p,responseText,u,xhr){
			if(status)
				DAV.move(u,cb,p,u.replace("-davsavingtemp",""));
			else
				cb.apply(firstcb,arguments);
		};
		return DAV.put(url+"-davsavingtemp",firstcb,params,data);
	}	
};

config.DavSaver = {
	defaultFileName : 'index.html',
	messages : {
		startSaveMessage : 'saving to server...',
		endSaveMessage : 'TiddlyWiki successfuly saved to server',
		overwriteNewerPrompt : 'The remote file has changed since you last loaded or saved it.\nDo you wish to overwrite it?',
		getModDateError : "Could not get last modified date",
		raceError: "Save failed because the remote file is newer than the one you are trying to save"
	},
	errors:{
		raceconflict : 'The save failed because your file is out of date',
		getlastmodified : 'The save was aborted because the last modified date of the file could not be retrieved',
		davenabled : 'The server does not support WebDav',
		saverss : 'There was an error saving the rss file, the save was aborted',
		saveempty: 'There was an error saving the empty file, the save was aborted',
		savemain : 'Save failed! There was an error saving the main TW file',
		savebackup: 'Save failed! There was an error creating a backup file',
		makebackupdir: 'Save failed! The backup directory could not be created'		
	},
	timestamp: new Date().toGMTString(),
	orig_saveChanges: saveChanges,
	saver : null
};

DavSaver = function(){
	
	this.Q = [];	

	this.reset = function(){
		config.DavSaver.saver = null;
	};
	this.runQ = function(){
		if(this.Q.length){
			this.Q.shift().apply(this,arguments);
		}
		else
			this.reset();
	};
	this.posDiv = null;
	this.original = null;
	
	this.getOriginalPath = function(){
		var p = document.location.toString();
		p = convertUriToUTF8(p,config.options.txtFileSystemCharSet);
		var argPos = p.indexOf("?");
		if(argPos != -1)
			p = p.substr(0,argPos);
		var hashPos = p.indexOf("#");
		if(hashPos != -1)
			p = p.substr(0,hashPos);		
		if (p.charAt(p.length-1) == "/")
			p = p + config.DavSaver.defaultFileName;
		return p;
	};
	
	this.originalPath = this.getOriginalPath();
	this.backupPath = null;
	this.emptyPath = null;
	this.rssPath = null;
	this.throwError = function(er){
		clearMessage();
		this.reset();
		alert(config.DavSaver.errors[er]);   //cl