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
The API documentation of following versions are available:
* [[sof_1.3_12100|http://sof.sourceforge.net/api_1.3_12100/sof/html/]]
* [[sof_1.3_11090|http://sof.sourceforge.net/api_1.3_11090/sof/html/]]
* [[sof_1.2_11050|http://sof.sourceforge.net/api_1.2_11050/sof/html/]]
* [[sof_1.0.1_10120|http://sof.sourceforge.net/api_1.0.1_10120/sof/html/]]
* [[sof_1.0_9120|http://sof.sourceforge.net/api_1.0_9120/sof/html/]]
* [[sof_8070|http://sof.sourceforge.net/api_8070/html/]]
* [[sof_8050|http://sof.sourceforge.net/api_8050/html/]]
The API documentation of following versions are available:
* [[sof_1.3_12100|http://sof.sourceforge.net/api_1.3_12100/sof_remote/html/]]
* [[sof_1.3_11090|http://sof.sourceforge.net/api_1.3_11090/remote_sof/html/]]
* [[sof_1.2_11050|http://sof.sourceforge.net/api_1.2_11050/remote_sof/html/]]
* [[sof_1.0.1_10120|http://sof.sourceforge.net/api_1.0.1_10120/remote_sof/html/]]
* [[sof_1.0.1_10120|http://sof.sourceforge.net/api_1.0.1_10120/remote_sof/html/]]
* [[sof_1.0_9120|http://sof.sourceforge.net/api_1.0_9120/remote_sof/html/]]
* [[sof_remote_9070|http://sof.sourceforge.net/api_9070/html/]]
//SOF// (Service Oriented Framework) wants to help software developers to avoid developing monolithic software. The //SOF// framework allows to separate a software system in several small components which are communicating via clearly defined interfaces. Components can be started and stopped at runtime and the components are notified about the lifecycle of other components if necessary. //SOF// is implemented in standard C++ and provides an OS independent framework for developing component based software. The //SOF// API is very similar to the OSGI API (see [[OSGI|http://www.osgi.org]]).

''Note:''
* SOF names components (like OSGI) as bundles.
* Bundles can consist of one or several classes.
* Bundles can be also implemented as DLL (=''D''ynamic ''L''ink ''L''ibrary).
* Bundles are loaded, started and stopped by SOF.
* Each bundle can register zero or several services which can be tracked by other bundles.
* Each bundle can track (listen to) one or several services.

[img[http://farm4.static.flickr.com/3271/2477292881_b67f8ff660_o.png]]
//SOF// provides a framework for supporting software modularization. Software components called bundles can communicate via defined service interfaces with other bundles. For getting the reference of a service each bundle can register service listeners which observe the lifecyle of services. 
//Remote SOF// represents an extension for //SOF//. That means services can not only be tracked and registered within the same //SOF// container (=process) but across several processes whereas CORBA is used as communication layer.
[img[http://farm3.static.flickr.com/2481/3566511834_427819b320_o.png]]
The diagram above shows the simplified architecture of //Remote SOF//. There exist several //SOF// processes (here two) and every //SOF// process hosts several bundles. Bundles are able to register services and service listeners (just as with //SOF//) at the registry component of each //SOF// container. So far there is no big difference to the //SOF// framework. But for notifying other //SOF// processes about (de)registered services and service listeners all calls to the local registry component are delegated to the remote registry component which is implemented as CORBA object and reachable via the CORBA naming service. All calls which are received by the remote registry component are forwarded to all running //SOF// processes.
Articles for SOF and Remote SOF can be found here:

http://www.codeproject.com/KB/library/SOF_.aspx
http://www.codeproject.com/KB/library/Remote_SOF.aspx
!!Building 3rd party CORBA library MICO
//Remote SOF// uses MICO (=CORBA implementation) as third party library for implementing remote accessible services and service listeners. Before //Remote SOF// can be build, the MICO libraries must be build.
!!!Windows
Execute following steps for building MICO version 2.3.13 on Windows with Visual C++. 
* Download the MICO distribution (http://www.mico.org/mico-2.3.13.zip)
* Extract the zip file
* Start the Visual Studio command shell
* Change into MICO main directory 
* Enter 'nmake /f Makefile.win32'
Afterwards MICO is build as a ''dynamic'' library. Binaries (executables, ~DLLs, ~LIBs) are placed into 'mico\win32-bin' and 'mico\win32-bin\lib' directory. 
!!!Unix/Linux
Execute following steps for building MICO version 2.3.13 on Unix/Linux with GNU GCC. 
* Download the MICO distribution (http://www.mico.org/mico-2.3.13.zip)
* Change into MICO main directory 
* Run the configure script: //./configure//
* Use gmake to start compilation and install the programs and libraries, possibly becoming root before installation:
** //gmake//
** //gmake install//
Afterwards MICO is build as a ''dynamic'' library which is located in the 'mico/libs' directory. Executables are placed in specific folders:
* mico/coss/naming: //nsd//, //nsadmin//
* mico/tools: //iordump//
* mico/idl: //idl//
!!!Other platforms
For building other MICO versions or building on different platforms please read the MICO documentation.
!!Building //Remote SOF//
First of all please set the //~MICO_HOME// environment variable to the //MICO// root directory. It is used by Visual Studio project files as well as by //~CMake// build scripts.
!!!Windows
!!!!Visual Studio
* Extract the zip file of the //Remote SOF// distribution into a directory
* Load file called 'sof_remote.sln' in directory 'sof\remote\impl' with Visual Studio
* Build all projects
!!!!~CMake (with Visual C++ compiler)
* Please install ~CMake (look at http://www.cmake.org for latest releases and documentation)
* Open a command shell on Windows and set the path and environment variables for command line builds. This can be done by changing to the //\bin// subdirectory of your Visual C++ installation and running //vcvars32.bat// (or just opening a Visual Studio command shell).
* Make sure that the //MICO_HOME// environment variable is set.
* Change to a directory where you want to build //SOF// and type:
** //"""cmake -G "NMake Makefiles" <source-dir> -DSOF_REMOTE=true -DCMAKE_BUILD_TYPE=Release"""// for creating a release build
** //"""cmake -G "NMake Makefiles" <source-dir> -DSOF_REMOTE=true -DCMAKE_BUILD_TYPE=Debug"""// for creating a debug build
** The <source-dir> parameter defines the root directory where the //SOF// source files are located.
* Type //nmake help// for listing possible build targets:
** //sof_remote// -> building the //Remote SOF// library
** //sof_remote_test// -> building the //Remote SOF// unit tests
** //sof_remote_console// -> building the //Remote SOF// console application providing a command line interface for starting and stopping bundles
* Enter //nmake install// for building all targets
!!!Unix/Linux
!!!!~CMake (with GNU GCC compiler)
* Please install ~CMake (look at http://www.cmake.org for latest releases and documentation)
* Make sure that the //MICO_HOME// environment variable is set.
* Change to a directory where you want to build //SOF// and type:
** //"""cmake -G "Unix Makefiles" <source-dir> -DSOF_REMOTE=true -DCMAKE_BUILD_TYPE=Release"""// for creating a release build
** //"""cmake -G "Unix Makefiles" <source-dir> -DSOF_REMOTE=true -DCMAKE_BUILD_TYPE=Debug"""// for creating a debug build
** The <source-dir> parameter defines the root directory where the //SOF// source files are located.
* Type //make help// for listing possible build targets:
** //sof_remote// -> building the //SOF// library
** //sof_remote_test// -> building the //SOF// unit tests
** //sof_remote_console// -> building the //SOF// console application providing a command line interface for starting and stopping bundles
* Enter //make install// for building all targets
''Note:''
Following compiler versions were tested so far:
* Windows: VC++ 9 (15.00)
* Linux: Ubuntu 10.10, GNU GCC 4.4.5
!!!Using //Remote SOF//
After building //Remote SOF// the //<remote_sof_build_dir>/remote/impl// directory contains a library called //sof_remote.lib// which can be linked.
!!!!Running the //Remote SOF// console
For running the SOF console you have to make sure that you have executed the //install// target (e.g. nmake install).
Afterwards you have to
* open a command shell and change to the 'remote/registry' directory in the build directory
* enter 'run_ns.bat' (on Windows) and 'run_ns.sh' (on Unix/Linux) for starting the CORBA naming service
* open another command shell and change to the 'remote/registry' directory in the build directory
* enter 'run_registry.bat' (on Windows) and 'run_registry.sh' (on Unix/Linux) for starting the registry process
* open another command shell and change to the 'remote/console' directory in the build directory
* enter 'run_remote_console.bat -proc_name:XXX' (on Windows) and 'run_remote_console.sh -proc_name:XXX' (on Unix/Linux)
* The console is started and can be used.
!!!!Running unit tests
For running the SOF unit tests you have to make sure that you have built the //install// target (e.g. nmake install).
Note: After entering 'nmake help' all possible build targets are listed.
Afterwards you have to 
* change to the 'remote/test' directory in the build directory
* enter 'run_remote_test.bat' (on Windows) or 'run_remote_test.sh' (on Unix/Linux) for starting the unix tests
The unit tests will be successful, if 'There were no test failures' is printed out.
!!!Supported Platforms
Basically //SOF// is implemented platform independent and can be compiled and run for all possible platforms where a standard C++ compiler is available. 
[[CMake|http://http://www.cmake.org/]] is the command line build tool which allows building //SOF// for different platforms. Since //SOF// was implemented on a Windows PC with Visual Studio C++ 2008 there are also Visual Studio project files available for building the framework. 
!!!Building SOF
!!!!Windows
!!!!!Visual Studio
Start the Visual Studio, go to the //sof/impl// directory and load the //sof.sln// (Microsoft Visual Studio Solution) file. Afterwards the build process can be started with Visual Studio.
!!!!!~CMake (with Visual C++ compiler)
* Please install ~CMake (look at http://www.cmake.org for latest releases and documentation)
* Open a command shell on Windows and set the path and environment variables for command line builds. This can be done by changing to the //\bin// subdirectory of your Visual C++ installation and running //vcvars32.bat// (or just opening a Visual Studio command shell).
* Change to a directory where you want to build //SOF// and type:
** //"""cmake -G "NMake Makefiles" <source-dir> -DSOF_REMOTE=false -DCMAKE_BUILD_TYPE=Release"""// for creating a release build
** //"""cmake -G "NMake Makefiles" <source-dir> -DSOF_REMOTE=false -DCMAKE_BUILD_TYPE=Debug"""// for creating a debug build
** The <source-dir> parameter defines the root directory where the //SOF// source files are located.
* Type //nmake help// for listing possible build targets:
** //sof// -> building the //SOF// library
** //sof_test// -> building the //SOF// unit tests
** //sof_console// -> building the //SOF// console application providing a command line interface for starting and stopping bundles
** //sof_examples// -> building the //SOF// examples
* Enter //nmake install// for building all targets
!!!!Unix/Linux
!!!!!~CMake (with GNU GCC compiler)
* Please install ~CMake (look at http://www.cmake.org for latest releases and documentation)
* Change to a directory where you want to build //SOF// and type:
** //"""cmake -G "Unix Makefiles" <source-dir> -DSOF_REMOTE=false -DCMAKE_BUILD_TYPE=Release"""// for creating a release build
** //"""cmake -G "Unix Makefiles" <source-dir> -DSOF_REMOTE=false -DCMAKE_BUILD_TYPE=Debug"""// for creating a debug build
** The <source-dir> parameter defines the root directory where the //SOF// source files are located.
* Type //make help// for listing possible build targets:
** //sof// -> building the //SOF// library
** //sof_test// -> building the //SOF// unit tests
** //sof_console// -> building the //SOF// console application providing a command line interface for starting and stopping bundles
** //sof_examples// -> building the //SOF// examples
* Enter //make install// for building all targets
''Note:''
Following compiler versions were tested so far:
* Windows: VC++ 9 (15.00)
* Linux: Ubuntu 10.10, GNU GCC 4.4.5
!!!Using SOF
After building SOF the //<sof_build_dir>/impl// directory contains a library called //sof.lib// which can be linked.
!!!!Running the //SOF// console
For running the //SOF// console you have to make sure that you have built all targets or have built the //sof_console// target at least. 
''Note'': After entering 'nmake help' all possible build targets are listed.
Afterwards you must change to the //console// directory and start the //sof_console// executable.

!!!!Running unit tests
For running the //SOF// unit tests you have to make sure that you have built all targets or have built the //sof_test// target at least. 
''Note'': After entering 'nmake help' all possible build targets are listed.
Afterwards you must change to the //test// directory and start the //sof_test// executable. The unit tests will be successful, if 'There were no test failures' is printed out.
This chapter describes how bundles are created, started and stopped by the framework.
![[Instantiation of the Bundle Activator]]
![[Starting SOF]]
![[Starting Bundles]]
![[Stopping Bundles]]
Copying the CORBA binaries of the MICO distribution into the //Remote SOF// directory:
* 'idl.exe' and 'nsd.exe' to 'sof\remote\corba\bin'
* The content of the MICO 'include' directory into 'sof\remote\corba\include'
* The libraries 'idl2313.lib', 'mico2313.lib', 'micocoss2313.lib', 'pthreadVC2.lib', 'idl2313.dll', 'mico2313.dll', 'micocoss2313.dll', 'pthreadVC2.dll' into 'sof\remote\corba\libs'
** for debug build name the libraries as follows:
*** idl2313.lib / idl2313.dll
*** mico2313.lib / mico2313.dll
*** micocoss2313.lib / micocoss2313.dll
*** pthreadVC2.lib / pthreadVC2.dll
** for release build name the libraries as follows:
*** idl2313.lib / idl2313.dll
*** mico2313.lib / mico2313.dll
*** micocoss2313.lib / micocoss2313.dll
*** pthreadVC2d.lib / pthreadVC2d.dll
The SOF console provides a text based user interface for starting and stopping bundles. The console can be started by calling {{{sof_console.exe}}} which is located in directory '//console//'. See [[Starting SOF]] for further information.

[img[http://farm4.static.flickr.com/3251/2678806149_914f03de0d_o.gif]]

If you enter 'help' the console prints out all possible commands which can be executed within the console application. Following commands are available:

''Commands for creating and starting bundles''
* //stb//: 
** Starts a local bundle which means that the bundle activator class is linked to the console application.
** Parameters:
*** The name of the bundle.
*** The name of the bundle activator class.
** Example: {{{stb test_bundle TestBundleActivator}}}
* //stbdll//:
** Starts a bundle from DLL.
** Parameters:
*** The name of the bundle.
*** The name of the bundle activator class.
*** The directory where the DLL is located.
*** The name of the DLL.
** Example: {{{stbdll test_bundle TestBundleActivator c:/libs test_bundle.dll}}}
* //stbfile//:
** Starts bundles which are specified in a configuration file.
** Example: {{{stbfile c:/test/test_config_file.sof}}}
** Each line of the configuration file represents the bundle configuration of one bundle.
*** Configuration line for a local bundle: <bundle_name>,<bundle_activator_class_name>
*** Configuration line for a bundle loaded from a DLL: <bunde_name>,<bundle_activator_class_name>,<dll_directory>,<dll_name> 
''Commands for stopping bundles''
* //spb//:
** Stops a bundle.
** Parameters:
*** The name of the bundle.
** Example: {{{spb test_bundle}}}
* //spab//:
** Stops all active bundles.
''Commands for getting bundle information''
* //dbi//:
** Dumps all relevant information of the specified bundle.
** Parameters:
*** The name of the bundle.
** Example: {{{dbi test_bundle}}}
* //dab//:
** Dumps all relevant information of all bundles.
** Parameters:
*** None
** Example: {{{dab}}}
[[About]]
!The ''S''ervice ''O''riented ''F''ramework (SOF)
The SOF supports developing modular software which consists of components (bundles). Each component can register services which can be used by other bundles. 
!![[Building SOF]]
!![[Implementing a bundle]]
!![[Bundle Lifecycle]]
!![[Implementing a service]]
!![[Registering services]]
!![[Tracking services]]
!![[Building Remote SOF|Building Remote SOF]]
!![[Using Remote SOF]]
!![[Local Services within Remote SOF Container]]
Following stable builds are available. For downloading the software please click [[here|http://sourceforge.net/project/showfiles.php?group_id=217435]].
* ''sof_1.3_12100 (last stable version, includes SOF and Remote SOF)''
** ''Note:''
*** There is no new //~SofAdminUI// version. Please use the //~SofAdminUI// of the previous release //sof_1.0.1_10120//
** Changes:
*** Windows specific code from test classes removed. Test code was made platform independent.
** Bugfixes:
*** 
** Features:
*** Build scripts: make target (compile_idl) added for generating C++ code from CORBA IDL files (~CORBAObjects, ~CORBAAdminObjects) automatically. The compile_idl target is implicitely executed if //Remote SOF// is build.
*** Automatic API doc generation (with Doxygen). Use 'make doc' for generating //SOF// API or 'make doc_remote' for //Remote SOF// API.
*** It is now possible to use //Remote SOF// without the need of starting the CORBA naming service. Please click [[here|Running Remote SOF without CORBA Naming Service]].
* ''sof_1.3_11090 ( includes SOF and Remote SOF)''
** ''Note:''
*** There is no new //~SofAdminUI// version. Please use the //~SofAdminUI// of the previous release //sof_1.0.1_10120//
** Bugfixes:
*** Visual Studio project files - ~MICO_HOME [[ID 3309130|http://sourceforge.net/tracker/?func=detail&aid=3309130&group_id=217435&atid=1040234]]
** Features:
*** //Remote SOF// supports registering and tracking local services as well (please see [[here|Local Services within Remote SOF Container]]).
* ''sof_1.2_11050 (last stable version, includes SOF and Remote SOF)''
** ''Note:''
*** There is no new //~SofAdminUI// version. Please use the //~SofAdminUI// of the previous release //sof_1.0.1_10120//
** Features:
*** //SOF// and //Remote SOF// can be build now for Unix/Linux as well. Please follow the links for building [[SOF|Building SOF (new)]] and [[Remote SOF|Building Remote SOF (new)]] by using the build tool ~CMake. ''The build tool ~SCons will no longer be supported''.
* ''sof_1.0.1_10120 (includes SOF and Remote SOF)''
** ''Note:''
*** There is no new //~SofAdminUI// version. Please use the //~SofAdminUI// of the previous release //sof_1.0_9120//
** Features:
*** Unit tests for //Remote SOF// are available now. Please look at 'sof/remote/test' directory.
*** Project configurations for debug builds (Visual Studio) added.
*** Smart pointer implementation for avoiding memory leaks added.
** Bugfixes:
*** ~RemoteServiceTracker not exception safe [[2927344|https://sourceforge.net/tracker/?func=detail&aid=2927344&group_id=217435&atid=1040234]]
*** [SOF] Remove redundancy in registry class [[ID 2819393|https://sourceforge.net/tracker/?func=detail&aid=2819393&group_id=217435&atid=1040234]]
*** Concrete naming service address has to be removed [[ID 2940740|https://sourceforge.net/tracker/?func=detail&aid=2940740&group_id=217435&atid=1040234]]
*** Problem when stopping all bundles in console [[ID 2021277|https://sourceforge.net/tracker/?func=detail&aid=2021277&group_id=217435&atid=1040234]]
*** Problems found with [[CppCheck|http://sourceforge.net/projects/cppcheck/]] fixed.
*** Crash when dumping all bundles in console [[ID 3067288|https://sourceforge.net/tracker/?func=detail&aid=3067288&group_id=217435&atid=1040234]]
*** Memory leak of ~RemoteServiceInfo objects [[ID 2970487|https://sourceforge.net/tracker/?func=detail&aid=2970487&group_id=217435&atid=1040234]]
*** Remote registry not synchronizable [[ID 2952968|https://sourceforge.net/tracker/?func=detail&aid=2952968&group_id=217435&atid=1040234]]
*** Remote registry not exception safe [[ID 2928038|https://sourceforge.net/tracker/?func=detail&aid=2928038&group_id=217435&atid=1040234]]
*** Logger implementation not thread safe [[ID 2936130|https://sourceforge.net/tracker/?func=detail&aid=2936130&group_id=217435&atid=1040234]]
*** ~ServiceTracker not exception safe [[ID 2927343|https://sourceforge.net/tracker/?func=detail&aid=2927343&group_id=217435&atid=1040234]]
*** GCC compile error (enum)  [[ID 2936129|https://sourceforge.net/tracker/?func=detail&aid=2936129&group_id=217435&atid=1040234]]
*** Concrete naming service address has to be removed [[ID 2940740|https://sourceforge.net/tracker/?func=detail&aid=2940740&group_id=217435&atid=1040234]]
*** Compile Errors in ~VC2008 fixed (thanks to Philipp Kursawe) [[ID 3000083|http://sourceforge.net/tracker/?func=detail&aid=3000083&group_id=217435&atid=1040234]] 
* ''sof_1.0_9120 (includes SOF and Remote SOF'')
** Release notes:
*** Features:
**** Platform independent build tool for building [[SOF|Building]] and [[Remote SOF|Building Remote SOF]]
**** The //Remote SOF// console application (sof_remote_console) requires now a process name ('-proc_name:<process_name>') which is defined as program argument of the console application. The process name is necessary for identifying the //Remote SOF// processes in the new diagnosis and administration UI.
**** [[Diagnosis & Administration UI|SofAdminUI]]
*** Thank you very much for the patches:
**** Provided by Eugene Burov:
***** 'null reference exception - [[ID: 2909759|http://sourceforge.net/tracker/index.php?func=detail&aid=2909759&group_id=217435&atid=1040234]]'
**** Provided by Jan Hölscher:
***** 'simple Patch File to build this project on Linux - [[ID: 2904953|http://sourceforge.net/tracker/index.php?func=detail&aid=2904953&group_id=217435&atid=1040236]]'
*** Bugfixes:
**** The instance map of class {{{ObjectCreator}}} has to be checked for null before using it [[2808884|http://sourceforge.net/tracker/?func=detail&aid=2808884&group_id=217435&atid=1040234]]
**** Services and service listeners were not deregistered correctly [[2818458|http://sourceforge.net/tracker/?func=detail&aid=2818458&group_id=217435&atid=1040234]]
**** Services which are in use are not listed in Remote SOF console [[2818461|http://sourceforge.net/tracker/?func=detail&aid=2818461&group_id=217435&atid=1040234]]
**** Services are listed twice as 'used' services in Remote SOF console [[2821783|http://sourceforge.net/tracker/?func=detail&aid=2821783&group_id=217435&atid=1040234]]
* ''sof_9070 (includes SOF and Remote SOF)''
** Release notes: 
*** New features:
**** SOF supports distributed bundles now. That means services and service listeners can be called across several processes whereas CORBA is used as communication layer.
*** Changes:
**** Implementation of Remote SOF
**** {{{BundleInfoBase}}} as base class for {{{RemoteBundleInfo}}} and {{{BundleInfo}}} class implemented
**** Using the {{{IMultiplier}}} interface as service interface for SOF examples
**** The implementationof {{{IBundleContextIImpl#registerService}}} was moved completely to the {{{IRegistryImpl}}} class.
**** The creation of {{{ServiceInfo}}} and {{{ServiceListenerInfo}}} object was moved to the {{{IBundleContextImpl}}} class.
**** Implementation of {{{toString}}} method for {{{ServiceEvent}}} and {{{ServiceReference}}} class 
* ''sof_8070''
** Release notes:
*** New features:
**** The {{{addingService}}} method of the {{{IServiceTrackerCustomizer}}} interface has been extended by a boolean return value. By this the service tracker can accept or refuse found services. If the service tracker accepts a service by returning 'true', the service is regarded as a 'used service', otherwise not.  
**** The threading and creation policies have been introduced. This allows to make the way of loading bundles and the threading behaviour of the framework configurable.
**** An 'examples' project has been added which gives examples for implementing bundles, registering and tracking services.
*** Bugfixes:
**** Registering the administration service [[2002904|http://sourceforge.net/tracker/index.php?func=detail&aid=2002904&group_id=217435&atid=1040234]]
**** Bugfix for service listener notification problem [[1997433|http://sourceforge.net/tracker/index.php?func=detail&aid=1997433&group_id=217435&atid=1040234]] 
* ''sof_8050''
** Release notes:
*** Supported features:
**** Implementing bundles
**** Starting and stopping bundles via //SOF// console
**** Implementing services
**** Registering, unregistering and tracking services
*** Open issues:
**** Only single threaded solution available
**** Hard coded windows solution for starting bundles from ~DLLs.
Please look at SOF's [[download|Download]] section where you can find further information. There is no extra download package for the //Remote SOF// software. //SOF// and //Remote SOF// are packed together in one zip file.
For implementing a bundle the {{{sof::framework::IBundleActivator}}} interface has to be implemented:
{{{
class IBundleActivator
{
	public:
		virtual void start( IBundleContext::ConstPtr context ) = 0;
		virtual void stop( IBundleContext::ConstPtr context ) = 0;
};
}}}
In the {{{start( IBundleContext::ConstPtr )}}} method you have to do all the things which are necessary for running the application code. The passed bundle context object allows you to interact with the SOF framework, like registering or tracking services (see [[Registering and tracking services]]).
When {{{stop( IBundleContext::ConstPtr )}}} is called all the application relevant resources which were allocated by the bundle must be cleaned. The {{{start}}} and {{{stop}}} methods are called by the framework. When {{{stop}}} method is called, the bundle context pointer need not be deleted by the bundle but is deleted by the SOF framework. 
The bundle activator need not be instantiated by the application developer but is created also by the framework (see [[Bundle Lifecycle]]). For this the developer of every bundle has to make known the bundle activator class with the framework. This is done by using the {{{REGISTER_BUNDLE_ACTIVATOR_CLASS}}} macro defined in the {{{sof/instantiation/ObjectCreator.h}}} header file:
{{{
#include "BundleActivatorImpl.h"

#include "sof/instantiation/ObjectCreator.h"

using namespace sof::framework;
using namespace sof::instantiation;

void BundleActivatorImpl::start( IBundleContext::ConstPtr ctxt )
{
}

BundleActivatorImpl::~BundleActivatorImpl()
{
}

void BundleActivatorImpl::stop( IBundleContext::ConstPtr context )
{
}

REGISTER_BUNDLE_ACTIVATOR_CLASS( "BundleActivatorImpl", BundleActivatorImpl)
}}}

The {{{REGISTER_BUNDLE_ACTIVATOR_CLASS}}} macro expects three parameters:
* The name of the activator class (can be any name, but normally the name of the bundle activator class is chosen).
* The type of the specific bundle activator class which implements the {{{IBundleActivator}}} interface.

!Implementing a Local Bundle
Local means, that the class which implements the {{{IBundleActivator}}} interface is linked to the executable within the framework runs. The bundle need not to be created by loading a DLL (=''D''ynamic ''L''ink ''L''ibrary). For implementing a local bundle you have to do the things as described above (implementing the {{{IBundleActivator}}} interface and registering the activator class). Afterwards the bundle classes have to be linked with the main class which starts the framework.
!Implementing a DLL Bundle
Loading bundles from a dynamic link library is dependent on the used operating system. 
For implementing a bundle which is loaded from a Windows DLL following operations have to be done:
* Only for Windows: A {{{DllMain}}} method has to be implemented (instead of implementing a common {{{main}}} method for executable code)
* The DLL code must provide the method {{{IBundleActivator* createObject( const string &className )}}}. This method uses the {{{ObjectCreator}}} class (provided by //SOF//) for creating the {{{IBundleActivator}}} object by name.
* A bundle activator class has to be implemented.
* The bundle classes (the bundle activator, the class containing the {{{DllMain}}} etc.) must be build as DLL with the IDE.

The following code block displays the necessary operations for implementing a DLL for Windows and Unix/Linux as well and can be reused.

{{{
#ifdef WIN32
#include <windows.h>
#endif 

#include <stdlib.h>
#include <string>
#include <iostream>

#include "sof/instantiation/ObjectCreator.h"
#include "sof/framework/IBundleActivator.h"

using namespace std;
using namespace sof::instantiation;
using namespace sof::framework;

#ifdef WIN32
#define DLL extern "C" __declspec(dllexport)

BOOL APIENTRY DllMain( HANDLE hModule, 
                       DWORD  ul_reason_for_call, 
                       LPVOID lpReserved
					 )
{				
	return TRUE;
}

#elif UNIX
#define DLL extern "C" __attribute__((visibility("default")))
#endif

DLL IBundleActivator* createObject( const string &className )
{	
	ObjectCreator<IBundleActivator> OC_BUNDLE_ACTIVATOR;

	return OC_BUNDLE_ACTIVATOR.createObject( className );					
}
}}}
A service is registered with the framework by a bundle and implements a well known interface. The service can be tracked and then called by other bundles. Each bundle can register zero or several services.
!The {{{IService}}} interface
Every service has to implement the {{{IService}}} interface which is defined in the {{{sof::framework}}} namespace. The {{{IService}}} interface does not provide any methods. It is only a marker interface which declares a class as a service.
!Example:

''The service interface:''
{{{
#ifndef I_MY_SERVICE_H
#define I_MY_SERVICE_H

#include "sof/framework/IService.h"

using namespace sof::framework;

class IMyService: public IService
{
	public:
		virtual int getValue() = 0;
};
#endif
}}}
The user defined service interface {{{IMyService}}} which inherits from the service interface of the framework ({{{sof::framework::IService}}}) provides here only one method called {{{int getValue()}}}.

''The implementation:''
The following code snippets show the implementation of the user defined service  interface.
Header file:
{{{
#ifndef I_MY_SERVICE_IMPL_H
#define I_MY_SERVICE_IMPL_H

#include "IMyService.h"

using namespace sof::framework;

class IMyServiceImpl: public IMyService
{

	public:
		int getValue();
};
#endif
}}}
CPP file:
{{{
#include "IMyServiceImpl.h"

int IMyServiceImpl::getValue()
{
	return 42;
}
}}}
Now instances of class {{{IMyServiceImpl}}} can be registered with the framework. See chapter [[Registering services]]
The intention of the framework is to avoid that the application developer is responsible for the lifecycle of his implemented bundles. That means the creation, starting and stopping of the software bundles must be done by the framework:

[img[http://farm3.static.flickr.com/2183/2326314896_c15355177a_o.gif]]

The only thing the developer must do is [[implementing the bundle|Implementing a bundle]] and specifiying (by configuration file for example) which bundles shall be created and started. Consequently the framework must be able to create instances of type {{{sof::framework::IBundleActivator}}} by name. Ok, you have to do a little more than only implementing the {{{IBundleActivator}}} interface. The name of the class which implements the {{{IBundleActivator}}} interface has to be registered with the framework (see usage of {{{REGISTER_BUNDLE_ACTIVATOR_CLASS}}} macro in following code example):

{{{
#include "TestBundleActivator.h"

#include "sof/instantiation/ObjectCreator.h"

#include "sof/util/logging/Logger.h"
#include "sof/util/logging/LoggerFactory.h"

using namespace std;

using namespace sof::instantiation;
using namespace sof::framework;

void TestBundleActivator::start( IBundleContext::ConstPtr context )
{
	LoggerFactory::getLogger( "Test" ).log( Logger::DEBUG, "[TestBundleActivator#start] Called." 
}

TestBundleActivator::~TestBundleActivator()
{
	LoggerFactory::getLogger( "Test" ).log( Logger::DEBUG, "[TestBundleActivator#destructor] Called." );
}

void TestBundleActivator::stop( IBundleContext::ConstPtr context )
{
	LoggerFactory::getLogger( "Test" ).log( Logger::DEBUG, "[TestBundleActivator#stop] Called." );
}

REGISTER_CLASS("TestBundleActivator",IBundleActivator,TestBundleActivator)
}}}

The {{{REGISTER_BUNDLE_ACTIVATOR_CLASS}}} macro is defined in the header file named {{{sof/instantiation/ObjectCreator.h}}}  and asks for two parameters:
* The name of the class which is used for instantiation
* The name of the class which implements the {{{IBundleActivator}}} interface
/***
|''Name:''|LoadRemoteFileThroughProxy (previous LoadRemoteFileHijack)|
|''Description:''|When the TiddlyWiki file is located on the web (view over http) the content of [[SiteProxy]] tiddler is added in front of the file url. If [[SiteProxy]] does not exist "/proxy/" is added. |
|''Version:''|1.1.0|
|''Date:''|mar 17, 2007|
|''Source:''|http://tiddlywiki.bidix.info/#LoadRemoteFileHijack|
|''Author:''|BidiX (BidiX (at) bidix (dot) info)|
|''License:''|[[BSD open source license|http://tiddlywiki.bidix.info/#%5B%5BBSD%20open%20source%20license%5D%5D ]]|
|''~CoreVersion:''|2.2.0|
***/
//{{{
version.extensions.LoadRemoteFileThroughProxy = {
 major: 1, minor: 1, revision: 0, 
 date: new Date("mar 17, 2007"), 
 source: "http://tiddlywiki.bidix.info/#LoadRemoteFileThroughProxy"};

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

bidix.core.loadRemoteFile = loadRemoteFile;
loadRemoteFile = function(url,callback,params)
{
 if ((document.location.toString().substr(0,4) == "http") && (url.substr(0,4) == "http")){ 
  url = store.getTiddlerText("SiteProxy", "/proxy/") + url;
 }
 return bidix.core.loadRemoteFile(url,callback,params);
}
//}}}
//Remote SOF// makes it possible to track and register services across //Remote SOF// container running in different processes. For that you have to use following methods of the {{{IRemoteBundleContext}}} class:
{{{
virtual IServiceRegistration* registerRemoteService( const string &className, POA_sof::framework::remote::corba::generated::CORBAService* remoteService, const Properties &dict ) = 0;

virtual void addRemoteServiceListener( POA_sof::framework::remote::corba::generated::CORBAServiceListener* remoteServiceListener, const string &serviceName ) = 0;
}}}

Services which are supposed to be only called by bundles living in the same //Remote SOF// container don't have to be registered as 'remote service' but can be registered as local services:
{{{
virtual IServiceRegistration* registerService( const string &className, IService::ConstPtr service, const Properties &dict );
}}}
For tracking local services you have to register local service listeners:
{{{
virtual void addServiceListener( IServiceListener::ConstPtr serviceListener, const string &serviceName ) = 0;
}}}
Of course it is possible to register services which are only called inside a //Remote SOF// container as remote services but would cause unnecessary overhead due to the involved CORBA layer.
[img[netzwerk|http://farm3.static.flickr.com/2271/2249573201_120174d813_o.png]]
[[News]]
[[About]]
[[Articles]]
[[Project Structure]]
[[Documentation|Documentation]]
[[API|API]]
[[Download|Download]]
[[SOF Console|Console]]
[[Remote SOF]]
[[Open Issues]]

''May 10, 2011''
SOF 1.2 out now! The new build system (~CMake) of SOF version 1.2 allows to build SOF for Windows and Unix/Linux platforms as well. Please look [[here|Download]] for the release notes.

''December 21, 2009'' 
New version ''SOF 1.0'' (including the frameworks SOF and Remote SOF) available. Please look [[here|Download]] for the release notes.
Merry Christmas!

''July 8, 2009'' 
Remote SOF is available. It represents an extension for SOF and supports calling distributed bundles by using CORBA as communication layer.
* Directly ask the bundle context for service references (instead of being notified)
* Unloading bundle libraries
* Implementing OSGI services like
** Log service
** HTTP service etc.
* Improving error robustness
* More features for ~SofAdminUI
** Starting and stopping bundles
** Code generation of infrastructure code (registering listeners, tracking services etc.)
* Unit tests
** Evaluating other unit test frameworks like 'google test'
* Adding dependencies between bundles
** Examples:
*** Bundle A requires version 2.0 of bundle B
*** Bundle A requires version 1.2 of service B

[<img[netzwerk|http://farm4.static.flickr.com/3202/2679653624_fc6aed3ace_o.gif]]
''The SOF software consists of the four projects:''
* //impl//: The SOF kernel
* //test//: Unit tests for testing the framework
* //examples//: Examples of implemented bundles (which register/track services)
* //console//: The SOF console which provides a text based user interface for starting and stopping bundles, dump bundle infos etc.

''Each project can consist of following sub directories:''
* //src//: Contains header and source files
* //build//: Used for building the project (no longer used by new build system ~CMake)
* //bin//: Contains run scripts for starting SOF processes or unit tests and contains the output of the build process, e.g. an '.exe' of '.dll' file (is not applicable to ~CMake which uses a separate output directory)

The 'doc' directory contains the SOF documentation including the API documentation and the website content as local file. For implemented unit tests an extern unit test library is necessary called '~CppUniteLite' which is located in the 'extern directory'.



[<img[remote_sof_project_structure|http://farm4.static.flickr.com/3573/3551576055_569cbd97ca_o.gif]]
''The //Remote SOF// software consists of the four projects:''
* //impl//: The //Remote SOF kernel// which extends the //SOF// kernel
* //examples//: Examples of implemented bundles (which register/track services)
* //registry//: The registry which delegates the registering/deregistering of services and service listeners to all //SOF// processes.
* //test//: Implements unit tests.

''Each project can consist of following sub directories:''
* //src//: Contains header and source files
* //build//: Used for building the project (no longer used by new build system ~CMake)
* //bin//: Contains run scripts for starting SOF processes or unit tests and contains the output of the build process, e.g. an '.exe' of '.dll' file (is not applicable to ~CMake which uses a separate output directory)

The 'corba' directory contains following sub directories:
* //bin//: Contains executable CORBA MICO files (e.g. for running the CORBA naming service, running the IDL compiler etc.).
* //include//: Contains the CORBA MICO header files.
* //libs//: Contains the CORBA MICO libraries.
''Note:'' The 'corba' directory is no longer used by the new build system ~CMake and the Visual Studio project files. The home directory of the //MICO// installation is directly referenced by ~CMake build files and Visual Studio project files.

[<img[netzwerk|http://farm3.static.flickr.com/2252/2266693776_2d4c510ec1_o.gif]]
''The SOF software consists of the three projects:''
* //impl//: The SOF kernel
* //test//: Unit tests for testing the framework
* //console//: The SOF console which provides a text based user interface for starting and stopping bundles, dump bundle infos etc.

''Each project has following sub directories:''
* //src//: Contains header and source files
* //build//: Used for building the project
* //bin//: Contains the output of the build process, e.g. an '.exe' of '.dll' file

The 'doc' directory contains the SOF documentation including the API documentation and the website content as local file. For implemented unit tests an extern unit test library is necessary called 'CppUniteLite' which is located in the 'extern directory'.



Service objects can be registered during the total lifetime of a bundle. In the following example a service object is registered by the {{{start( IBundleContext )}}} method. For registering a service the {{{registerService}}} method of the bundle context object has to be called.
The {{{registerService}}} method expects three parameters:
* The arbitrary service name
* The service object (which implements the {{{IService}}} interface)
* The {{{Properties}}} object which contains user defined additional information regarding to the service object.
{{{
...
void BundleActivator::start( IBundleContext::ConstPtr context )
{
	LoggerFactory::getLogger( "Test" ).log( Logger::DEBUG, "[BundleActivator#start] Called." );
	
	Properties props;
        props.put( "ID", "4711 );
	IServiceRegistration* serviceReg = context->registerService( "ServiceA", new IMyServiceImpl(), props );
}
...
}}}
After a service is registered the framework notifies all service listeners (which were registered for the specified service name, here: "~ServiceA") about the registered service object. See chapter [[Tracking services]].

''Note:''
The {{{registerService}}} method returns a pointer to a {{{IServiceRegistration}}} object which provides only one method called {{{unregister}}}. That means the registration object allows to unregister the service object with the framework (if it is no longer needed) and the framework notifies all other bundles which are using this service via the service listeners.

The following diagram shows an use case where one bundle registers a service object and the other bundles (which track this service) are notified via the service listeners. This diagram shows the case when the service listeners are registered after the service object was registered. It could also happen that the service object is registered after the service listener objects were registered. In this case the service listeners would be notified after the registration of the service object.

[img[http://farm3.static.flickr.com/2362/2437534147_4e84b3db6b_o.jpg]]
[[About|About Remote SOF]]
[[Project Structure|Project Structure - Remote SOF]]
[[Documentation|Documentation - Remote SOF]]
[[API|API Remote SOF]]
[[Download|Download Remote SOF]]
[[SOF Console|Remote SOF console]]
[[Diagnosis & Administration UI|SofAdminUI]]

Before starting a //Remote SOF// container you usually have to execute a CORBA Naming Service and the registry process:
* build_dir/remote/registry/run_ns.sh
* build_dir/remote/registry/run_registry.sh
Both processes have been necessary for exchanging bundle information between two or several //Remote SOF// containers. By version sof_1.3_12100 (see [[Download]] section) it is also possible to drop the start of the CORBA naming service (run_ns.sh). Only the new registry script (run_registry_no_ns.sh) have to be started from now on before the //Remote SOF// containers are started (run_remote_console_no_ns.sh).

All scripts are available as Windows batch scripts as well.
Service Oriented Framework
SOF
The //~SofAdminUI// represents a diagnosis an administration tool for //Remote SOF//. The first version of the tool does not implement any administration features yet but it allows to display the bundle data of the running bundles. 
At [[Sourceforge|http://sourceforge.net/projects/sof/files/]] you'll find the latest binaries for several platforms. Please choose the right one and unzip the archive file into a directory. Afterwards run the 'eclipse' executable which you find in the 'eclipse' directory of the unzipped distribution. The tool is started and looks like as follows:

[img[SofAdminUI|http://farm5.static.flickr.com/4010/4202818162_6e800c7d6f_o.gif]]

The UI consists of two parts, the process view on the left side and the bundle data view on the right side. The process view lists all running //Remote SOF// processes (here 'ernie' and 'bert'). The process names here are consistent with the process names which are used for the //Remote SOF// console application. The view can be updated maybe after running further //Remote SOF// processes by pressing the 'Update View' button. Everytime you press the update button the ~SofAdminUI connects the CORBA naming service and reads all registered //Remote SOF// processes. The UI uses 'localhost:5000' as default address of the CORBA naming service. For the case you started the CORBA naming service on a different address and port, it is possible to define the address for the UI. For this you have to pass a program argument to its executable.

''Example:''
//eclipse.exe -~ORBInitRef.~NameService=corbaloc::<ip-address>:<port-number>/~NameService//

After choosing a process in the process view the bundle data view displays all running bundles of the selected process in the 'Bundle Names' list. If you click a bundle in the list, all registered services, used services and registered service listeners are listed in the fields next to the bundle list.
!By program at framework startup
The {{{Launcher}}} class offers following method for starting bundles:
{{{
void start( vector<BundleConfiguration> &configuration );
}}}
The parameter which has to be passed to the method call represents a vector of {{{sof::config::BundleConfiguration}}} objects. Each {{{BundleConfiguration}}} object defines the configuration of one bundle.

''Example:''
{{{
BundleConfiguration bundleConf( "MyBundle", "MyBundleActivator", "c:/temp", "mybundle.dll" );
}}}
The {{{BundleConfiguration}}} constructor requires following parameters:
* The name of the bundle (e.g. "~MyBundle" )
* The name of the activator class (e.g. "~MyBundleActivator") which must be defined in the implementation class by using the  {{{REGISTER_BUNDLE_ACTIVATOR_CLASS}}} macro .
* The following parameters are optional and only necessary for configuring an external bundle (which is loaded from a library):
** The path to the directory where the bundle library is located (e.g. "c:/temp")
** The name of the bundle library (e.g. "mybundle.dll")
In the following example the launcher starts two bundles, one local and one external bundle:
{{{
#include <iostream>

#include "sof/framework/Launcher.h"
#include "sof/framework/Global.h"
#include "sof/config/BundleConfiguration.h"
#include "sof/instantiation/win/WinDllCreator.h"
#include "sof/util/threading/SingleThreaded.h"

using namespace std;
using namespace sof::framework;
using namespace sof::instantiation::win;
using namespace sof::config;
using namespace sof::util::threading;

int main(int argc, char* argv[])
{	
        // Framework launcher class
	Launcher<SingleThreaded,WinDllCreator> launcher;

        // Sets the log level of the framework
	launcher.setLogLevel( Logger::LogLevel::DEBUG );

        // Creating the bundle configuration
        BundleConfiguration bundleConf1( "bundle1", "BundleActivator2", ".", "sof_TestDll2.dll" );
	BundleConfiguration bundleConf2( "bundle2", "TestBundleActivator" );
	vector<BundleConfiguration> bundleConfVec;
	bundleConfVec.push_back( bundleConf1 );
	bundleConfVec.push_back( bundleConf2 );

        // Starts the bundles which are configured by BundleConfiguration vector
        launcher.start( bundleConfVec );

        // Starts the administration bundle which implements the SOF console
	launcher.startAdministrationBundle();

	return 0;
}
}}}
!By program via administration interface
//SOF// offers an administration interface which can be tracked and called. The administration interface or bundle can be started as follows:
{{{
laucher.startAdministrationBundle();
}}}
The administration interface is defined in class {{{sof::services::admin::IAdministrationService}}} and can be tracked by using the name 'sof::services::admin::~IAdministrationService'. The provided methods for starting bundles are:
{{{
class IAdministrationService
{
	public:
		virtual void startBundleFromDLL( const string& bundleName, const string& className, const string& libPath, const string& libName ) = 0;
		virtual void startBundle( const string& bundleName, const string& className ) = 0;
		virtual void startBundlesFromConfigFile( const string& configFile ) = 0;
};
}}}

Method parameters:
* {{{startBundle}}}: Starts a local bundle.
** //bundleName//: The name of the bundle which is started.
** //className//: The name of the bundle activator class.
* {{{startBundleFromDLL}}}: Starts a bundle from a dynamic link library.
** //bundleName//: The name of the bundle which is started.
** //className//: The name of the bundle activator class.
** //libPath//: The path to the directory where the library file is located (e.g. 'c:/bundles').
** //libName//: The name of the library which contains the bundle classes.
* {{{startBundlesFromConfigFile}}}: Starts a bundle which is configured in a file.
** //configFile//: The configuration file which specifies the bundle configuration data.
*** The configuration file can contain several entries whereas one entry consists of:
**** for external bundles (loaded from DLL): bundle_name,bundle_activator_class_name,library_path,library_name
**** for local bundles: bundle_name,bundle_activator_class_name
!By //SOF// console
It is also possible to start bundles via console after //SOF// was started. For starting the framework please look [[here|Starting SOF]]. When framework is up and the //SOF// console is ready for processing commands, following commands for starting bundles are available:
* stb (= starting bundle)
* stbdll (= starting bundle from DLL)
The exact notation of the commands (including passing parameters) you can find [[here|Console]]
Before bundles can be created and started the SOF framework has to be started. For this you have to create a class with following {{{main}}} method:
{{{
#include <iostream>

#include "sof/framework/Launcher.h"
#include "sof/framework/Global.h"
#ifdef WIN
    #include "sof/instantiation/win/WinDllCreator.h"
#endif
#include "sof/util/threading/SingleThreaded.h"

using namespace std;
using namespace sof::framework;
#ifdef WIN
    using namespace sof::instantiation::win;
#endif
using namespace sof::util::threading;

int main(int argc, char* argv[])
{	
        // Framework launcher class
	#ifdef WIN
		Launcher<SingleThreaded,WinDllCreator> launcher;
	#else
		Launcher<SingleThreaded,NullCreator> launcher;
	#endif

        // Sets the log level of the framework
	launcher.setLogLevel( Logger::LogLevel::DEBUG );

        // Starts the administration bundle which implements the SOF console
	launcher.startAdministrationBundle();

	return 0;
}
}}}
Such a class is also provided by the SOF framework itself. Please look into class {{{sof_console.cpp}}} in source folder of //console// project. The {{{Launcher}}} is a template based class and requires the definition of two policies:
!! Threading policy 
By implementing the threading policy it can be defined whether the {{{Launcher}}} class is able to act in a multi-threaded environment or supports only a single-threaded environment. The //SOF// framework provides a default implementation of the threading policy called {{{sof::util::threading::SingleThreaded}}} which demands that framework calls (registering and unregistering listeners, services etc.) have to be done in a single thread and the calls don't have to be synchronized. 
If the user of the //SOF// framework wants to develop a multithreaded software which includes registering services and service listeners concurrently, the user ought to implement the threading policy in order to avoid race conditions due to concurrent modifications in the {{{sof::framework::IRegistry}}} class. 
!! Creation policy
The creation policy defines how bundle activator instances can be created from a DLL (=''D''ynamic ''L''ink ''L''ibrary). Standard C++ provides no support for loading dynamic link libraries. By implementing the creation policy the user of the //SOF// framework is able to adapt the DLL loading mechanism for different platforms. 
//SOF//  currently provides only an implementation of the creation policy for the windows platform (see {{{sof::instantiation::win::WinDllCreator}}}).
!! Startup
After starting your program (or the //sof_console.exe// of the //console\bin// directory), you see following output:

[img[http://farm3.static.flickr.com/2295/2323942752_44bd18e0d5_o.gif]]

The //SOF// console, which provides a text based user interface, is started and waits for user input.
If you are not interested in log messages of the framework, the log level of the framework can be changed or deactivated as follows:
{{{
#include <iostream>

#include "sof/framework/Launcher.h"
#include "sof/framework/Global.h"
#ifdef WIN
   #include "sof/instantiation/win/WinDllCreator.h"
#endif
#include "sof/instantiation/NullCreator.h"
#include "sof/util/threading/SingleThreaded.h"

using namespace std;
using namespace sof::framework;
using namespace sof::util::threading;
#ifdef WIN
    using namespace sof::instantiation::win;
#endif

int main(int argc, char* argv[])
{
	Logger::LogLevel logLevel = Logger::LogLevel::DEBUG;
	for ( int i=0; i<argc; i++ )
	{
		string arg(argv[i]);
		if ( arg == "-nolog" )
		{
			logLevel = Logger::LogLevel::NOLOG;
		}
		else if ( arg == "-errorlog" )
		{
			logLevel = Logger::LogLevel::ERROR_;
		}
		else if ( arg == "-debuglog" )
		{
			logLevel = Logger::LogLevel::DEBUG;
		}
	}

	#ifdef WIN
		Launcher<SingleThreaded,WinDllCreator> launcher;
	#else
		Launcher<SingleThreaded,NullCreator> launcher;
	#endif
	launcher.setLogLevel( logLevel );
	launcher.startAdministrationBundle();
	return 0;
}

}}}

For getting more information relating to the //SOF// console please click [[here|Console]].
!By //SOF// console
The //SOF// console provides following commands for stopping bundles:
* //spb//: Stops one bundle specified by name.
* //spab//: Stops all active bundles.
For precise explanation of the commands please look [[here|Console]]
!By administration interface


Tracking a service means that a bundle instructs the framework to watch over a registered or deregistered service. When the specified service is registered or deregistered the framework notifies the interested bundle about the registered or deregistered service.
For tracking a service the bundle has to create a {{{ServiceTracker}}} object. Tracking begins as soon as the {{{startTracking}}} method is called and ends when the {{{stopTracking}}} method is called. Only during the tracking is active the bundle is notified about lifetime changes of a service.
{{{
void BundleActivator::start( IBundleContext::ConstPtr context )
{
	LoggerFactory::getLogger( "Test" ).log( Logger::DEBUG, "[BundleActivator#start] Called." );
	this->tracker = new ServiceTracker( context, "ServiceA", this );
	this->tracker->startTracking();
}
}}}
The constructor of the tracker object requires three parameters:
* The bundle context object which allows the tracker object to communicate with the framework
* The name of the service which is tracked
* An object of type {{{IServiceTrackerCustomizer}}} which is notified about lifetime changes of the service object.
/***
Contains the stuff you need to use Tiddlyspot
Note you must also have UploadPlugin installed
***/
//{{{

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

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

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

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

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

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

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

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

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

});
//}}}
| !date | !user | !location | !storeUrl | !uploadDir | !toFilename | !backupdir | !origin |
| 03/05/2012 06:05:26 | YourName | [[/|http://sof.tiddlyspot.com/]] | [[store.cgi|http://sof.tiddlyspot.com/store.cgi]] | . | [[index.html | http://sof.tiddlyspot.com/index.html]] | . |
| 10/05/2012 22:25:19 | YourName | [[/|http://sof.tiddlyspot.com/]] | [[store.cgi|http://sof.tiddlyspot.com/store.cgi]] | . | [[index.html | http://sof.tiddlyspot.com/index.html]] | . |
| 11/10/2012 06:06:21 | YourName | [[/|http://sof.tiddlyspot.com/]] | [[store.cgi|http://sof.tiddlyspot.com/store.cgi]] | . | [[index.html | http://sof.tiddlyspot.com/index.html]] | . |
| 11/10/2012 06:07:50 | YourName | [[/|http://sof.tiddlyspot.com/]] | [[store.cgi|http://sof.tiddlyspot.com/store.cgi]] | . | [[index.html | http://sof.tiddlyspot.com/index.html]] | . | ok |
| 11/10/2012 06:09:04 | YourName | [[/|http://sof.tiddlyspot.com/]] | [[store.cgi|http://sof.tiddlyspot.com/store.cgi]] | . | [[index.html | http://sof.tiddlyspot.com/index.html]] | . |
| 15/10/2012 04:05:18 | YourName | [[/|http://sof.tiddlyspot.com/]] | [[store.cgi|http://sof.tiddlyspot.com/store.cgi]] | . | [[index.html | http://sof.tiddlyspot.com/index.html]] | . | failed |
| 15/10/2012 04:05:38 | YourName | [[/|http://sof.tiddlyspot.com/]] | [[store.cgi|http://sof.tiddlyspot.com/store.cgi]] | . | [[index.html | http://sof.tiddlyspot.com/index.html]] | . | ok |
| 15/10/2012 04:11:51 | YourName | [[/|http://sof.tiddlyspot.com/]] | [[store.cgi|http://sof.tiddlyspot.com/store.cgi]] | . | [[index.html | http://sof.tiddlyspot.com/index.html]] | . |
| 15/10/2012 04:25:41 | YourName | [[/|http://sof.tiddlyspot.com/]] | [[store.cgi|http://sof.tiddlyspot.com/store.cgi]] | . | [[index.html | http://sof.tiddlyspot.com/index.html]] | . |
| 15/10/2012 07:37:36 | YourName | [[/|http://sof.tiddlyspot.com/]] | [[store.cgi|http://sof.tiddlyspot.com/store.cgi]] | . | [[index.html | http://sof.tiddlyspot.com/index.html]] | . |
/***
|''Name:''|PasswordOptionPlugin|
|''Description:''|Extends TiddlyWiki options with non encrypted password option.|
|''Version:''|1.0.2|
|''Date:''|Apr 19, 2007|
|''Source:''|http://tiddlywiki.bidix.info/#PasswordOptionPlugin|
|''Author:''|BidiX (BidiX (at) bidix (dot) info)|
|''License:''|[[BSD open source license|http://tiddlywiki.bidix.info/#%5B%5BBSD%20open%20source%20license%5D%5D ]]|
|''~CoreVersion:''|2.2.0 (Beta 5)|
***/
//{{{
version.extensions.PasswordOptionPlugin = {
	major: 1, minor: 0, revision: 2, 
	date: new Date("Apr 19, 2007"),
	source: 'http://tiddlywiki.bidix.info/#PasswordOptionPlugin',
	author: 'BidiX (BidiX (at) bidix (dot) info',
	license: '[[BSD open source license|http://tiddlywiki.bidix.info/#%5B%5BBSD%20open%20source%20license%5D%5D]]',
	coreVersion: '2.2.0 (Beta 5)'
};

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

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

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

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

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

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

merge(config.optionsDesc,{
		pasPassword: "Test password"
	});
*/
//}}}

/***
|''Name:''|UploadPlugin|
|''Description:''|Save to web a TiddlyWiki|
|''Version:''|4.1.0|
|''Date:''|May 5, 2007|
|''Source:''|http://tiddlywiki.bidix.info/#UploadPlugin|
|''Documentation:''|http://tiddlywiki.bidix.info/#UploadPluginDoc|
|''Author:''|BidiX (BidiX (at) bidix (dot) info)|
|''License:''|[[BSD open source license|http://tiddlywiki.bidix.info/#%5B%5BBSD%20open%20source%20license%5D%5D ]]|
|''~CoreVersion:''|2.2.0 (#3125)|
|''Requires:''|PasswordOptionPlugin|
***/
//{{{
version.extensions.UploadPlugin = {
	major: 4, minor: 1, revision: 0,
	date: new Date("May 5, 2007"),
	source: 'http://tiddlywiki.bidix.info/#UploadPlugin',
	author: 'BidiX (BidiX (at) bidix (dot) info',
	coreVersion: '2.2.0 (#3125)'
};

//
// Environment
//

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

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

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

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

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

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

//
// uploadOptions Macro
//

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

//
// upload functions
//

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

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

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

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

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

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

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

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

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

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

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

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

//
// Utilities
// 

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

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

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

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

//
// Initializations
//

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

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

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

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


/* don't want this for tiddlyspot sites

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

*/


//}}}


For using SOF you only have to build the 'impl' project (see [[Project Structure]]) in the SOF directory. 
Please look [[here|http://www.codeproject.com/KB/library/Remote_SOF.aspx]] for a short introduction into Remote SOF.
!![[Running Remote SOF without CORBA Naming Service]]