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
<!--{{{-->
<div class='toolbar' macro='toolbar [[ToolbarCommands::EditToolbar]]'></div>
<div class='title' macro='view title'></div>
<div class='editor' macro='edit title'></div>
<div macro='annotations'></div>
<div class='editor' macro='edit text'></div>
<div class='editor' macro='edit tags'></div><div class='editorFooter'><span macro='message views.editor.tagPrompt'></span><span macro='tagChooser excludeLists'></span></div>
<!--}}}-->
To get started with this blank [[TiddlyWiki]], you'll need to modify the following tiddlers:
* [[SiteTitle]] & [[SiteSubtitle]]: The title and subtitle of the site, as shown above (after saving, they will also appear in the browser title bar)
* [[MainMenu]]: The menu (usually on the left)
* [[DefaultTiddlers]]: Contains the names of the tiddlers that you want to appear when the TiddlyWiki is opened
You'll also need to enter your username for signing your edits: <<option txtUserName>>
<<importTiddlers>>
<!--{{{-->
<link rel='alternate' type='application/rss+xml' title='RSS' href='index.xml' />
<!--}}}-->
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]]
<!--{{{-->
<div class='header' role='banner' 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' role='navigation' refresh='content' tiddler='MainMenu'></div>
<div id='sidebar'>
<div id='sidebarOptions' role='navigation' refresh='content' tiddler='SideBarOptions'></div>
<div id='sidebarTabs' role='complementary' refresh='content' force='true' tiddler='SideBarTabs'></div>
</div>
<div id='displayArea' role='main'>
<div id='messageArea'></div>
<div id='tiddlerDisplay'></div>
</div>
<!--}}}-->
/*{{{*/
body {background:[[ColorPalette::Background]]; color:[[ColorPalette::Foreground]];}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

.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]];}
.readOnly {background:[[ColorPalette::TertiaryPale]];}

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

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

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

hr {height:1px;}

a {text-decoration:none;}

dt {font-weight:bold;}

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

.txtOptionInput {width:11em;}

#contentWrapper .chkOptionInput {border:0;}

.externalLink {text-decoration:underline;}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

.whenBackstage {display:none;}
.backstageVisible .whenBackstage {display:block;}
/*}}}*/
/***
StyleSheet for use when a translation requires any css style changes.
This StyleSheet can be used directly by languages such as Chinese, Japanese and Korean which need larger font sizes.
***/
/*{{{*/
body {font-size:0.8em;}
#sidebarOptions {font-size:1.05em;}
#sidebarOptions a {font-style:normal;}
#sidebarOptions .sliderPanel {font-size:0.95em;}
.subtitle {font-size:0.8em;}
.viewer table.listView {font-size:0.95em;}
/*}}}*/
/*{{{*/
@media print {
#mainMenu, #sidebar, #messageArea, .toolbar, #backstageButton, #backstageArea {display: none !important;}
#displayArea {margin: 1em 1em 0em;}
noscript {display:none;} /* Fixes a feature in Firefox 1.5.0.2 where print preview displays the noscript content */
}
/*}}}*/
<!--{{{-->
<div class='toolbar' role='navigation' macro='toolbar [[ToolbarCommands::ViewToolbar]]'></div>
<div class='title' macro='view title'></div>
<div class='subtitle'><span macro='view modifier link'></span>, <span macro='view modified date'></span> (<span macro='message views.wikified.createdPrompt'></span> <span macro='view created date'></span>)</div>
<div class='tagging' macro='tagging'></div>
<div class='tagged' macro='tags'></div>
<div class='viewer' macro='view text wikified'></div>
<div class='tagClear'></div>
<!--}}}-->
/***
|''Name''|RefreshTiddlerCommand|
|''Version''|0.3.0|
***/
//{{{
(function($) {

var cmd = config.commands.refreshTiddler = {
	text: "refresh",
	locale: {
		refreshing: "Refreshing tiddler..."
	},
	tooltip: "refresh this tiddler to be the one on the server",
	handler: function(ev, src, title) {
		var tiddler = store.getTiddler(title);
		if(!tiddler) {
			tiddler = new Tiddler(title);
			merge(tiddler.fields, config.defaultCustomFields);
		}
		$(story.getTiddler(title)).find(".viewer").
			empty().text(cmd.locale.refreshing);
		var dirtyStatus = store.isDirty();
		story.loadMissingTiddler(title, {
			"server.workspace": tiddler.fields["server.recipe"]  ? "recipes/" + tiddler.fields["server.recipe"] :
				tiddler.fields["server.workspace"] || "bags/"+tiddler.fields["server.bag"],
			"server.host": tiddler.fields["server.host"],
			"server.type": tiddler.fields["server.type"]
		}, function() {
			store.setDirty(dirtyStatus);
		});
	}
};

})(jQuery);
//}}}
in reply to [[TiddlySpace WishList]]@developers:

# Suggestion and auto complete on link creation. Like Sharepoint Wiki.
# Make headers and sub-headers automatic anchors.
# --Allow for an invisible Description: slice--
## [[pmario|http://pmario.tiddlyspace.com/#InvisibleDescriptionSlice]] kindly gave me a perfect solution for this in  <<quote 'InvisibleDescriptionSlice' 'InvisibleDescriptionSlice@pmario'>>.
# --Allow default collapsed for sidebar when using HoverMenuPlugin.--

----
/%
@@color:#c4d6ed; ^^
Description: A wish list for ~TiddlyWiki plugins, macros and functionality. 
^^@@
%/
<<tScan>>

----
@@color:#c4d6ed; ^^
Description: TODO
^^@@
<!--{{{-->
<div class='toolbar' role='navigation' macro='toolbar [[ToolbarCommands::ViewToolbar]]'></div>
<div class='title' macro='view title'></div>
<div macro="view title replyLink"></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>
<!--}}}-->
A [[SiteIcon|SiteIcon tiddler]]@glossary helps provide some identity to your space.  Ideally it'd be a square and a minimum of 48*48 pixels size.  You can upload your site icon using the uploader below.

<<binaryUploadPublic title:SiteIcon>>
<<top>>
<<jump j '' top>>
<<toggleSideBar>><<renameButton '>' >>
<<fullscreen>><<renameButton ↕ 'Full Screen'>>
<<newTiddler>><<renameButton n>>
<<saveChanges>><<renameButton s 'Save TiddlyWiki'>>
"//''The hardest single part of building a software system is deciding precisely what to build. No other part of the conceptual work is so difficult as establishing the detailed technical requirements, including all the interfaces to people, to machines, and to other software systems. No other part of the work so cripples the resulting system if done wrong. No other part is more difficult to rectify later.''//"

[[The mythical man-month - essays on software engineering, 1975|http://ultra.pr.erau.edu/~jaffem/classes/se300/Supplemental%20materials/The_Mythical_Man-Month_Essays_on_Software_Engineering_Anniversary_Edition.pdf]]
[[Frederick P. Brooks|http://en.wikipedia.org/wiki/Fred_Brooks]]
page 199
----
/%
@@color:#c4d6ed; ^^
Description: Quote of Frederick P. Brooks on requirements relevance
^^@@
%/
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
Use Case diagrams may be done in a structured or unstructured way. We will focus here in the unstructured way as it is simpler and more adequate to the Inception phases of the projects.
Use Case diagrams shall be considered alongside with [[Data Flow Diagram]]s but from the perspective of identifying the user interactions with the system, that is, the functionalities that the system offers to its users. While we are focusing on data flows to and from our system in [[DFD]]s, on Use Cases we focus on functionality blocks the user expects to use. Its an exploring and validation tool that is easily understood by non technical stakeholders, hence its usefulness on inception stages. They are also an aid in determining the screens we need to prototype and the roles the application will need.


TODO: add example, describe usage
----
See also : [[Data Flow Diagram]]
----
@@color:#c4d6ed; ^^
Description: Use Case concept, usage and references
^^@@
/***
|''Name''|TiddlyFileImporter|
|''Version''|0.3.8|
|''Author''|Ben Gillies|
|''Type''|plugin|
|''Description''|Upload a TiddlyWiki file to TiddlyWeb, and import the tiddlers.|
!Usage
Upload a TiddlyWiki file to TiddlyWeb, and import the tiddlers.
!Requires
tiddlyweb
tiddlywebplugins.reflector
!Code
***/
//{{{
(function($){
if(!version.extensions.TiddlyFileImporter)
{ //# ensure that the plugin is only installed once
	version.extensions.TiddlyFileImporter = { installed: true };
}

config.macros.fileImport = {
	reflectorURI: '/reflector?csrf_token=%0',
	incorrectTypeError: 'Incorrect File Type. You must upload a TiddlyWiki',
	uploadLabel: 'Upload',
	uploadLabelPrompt: 'Import tiddlers from this TiddlyWiki',
	step1FileText: 'File:',
	step1PostText: 'In the next screen you will select the tiddlers to import.',
	step1Title: 'Step 1: Pick a TiddlyWiki to import',
	step1TypeChooser: 'Import From:',
	step3Html: ['<input type="hidden" name="markList" />',
		'<input type="hidden" checked="true" name="chkSync" />',
		'<input type="hidden" name="chkSave" />',
		'<input type="hidden" name="txtSaveTiddler" />'].join(),

	handler: function(place, macroName, params, wikifier, paramString) {
		var wizard = new Wizard();
		wizard.createWizard(place, 'Import a TiddlyWiki');
		this.restart(wizard);
	},

	restart: function(wizard) {
		var me = config.macros.fileImport;
		wizard.addStep(me.step1Title, ['<input type="hidden" ',
			'name="markList" />'].join(""));
		var markList = wizard.getElement('markList');
		var uploadWrapper = document.createElement('div');
		markList.parentNode.insertBefore(uploadWrapper, markList);
		uploadWrapper.setAttribute('refresh', 'macro');
		uploadWrapper.getAttribute('macroName', 'fileImport');
		var iframeName = 'reflectorImporter' + Math.random().toString();
		me.createForm(uploadWrapper, wizard, iframeName);
		$(uploadWrapper).append('<p>' + me.step1PostText + '</p>');
		wizard.setValue('serverType', 'tiddlyweb');
		wizard.setValue('adaptor', new config.adaptors.file());
		wizard.setValue('host', config.defaultCustomFields['server.host']);
		wizard.setValue('context', {});
		var iframe = $(['<iframe name="' + iframeName + '" ',
			'style="display: none" />'].join("")).appendTo(uploadWrapper);
		var onSubmit = function(ev) {
			var uploadType = $('select[name=uploadtype]', wizard.formElem).val();
			if (uploadType == "file") {
				// set an onload ready to hijack the form
				me.setOnLoad(uploadWrapper, wizard, iframe[0]);
				wizard.importType = 'file';
				wizard.formElem.submit();
			} else {
				var csrf_token = config.extensions.tiddlyspace.getCSRFToken();
				$.ajax({
					url: "%0/reflector?csrf_token=%1".format(
						config.defaultCustomFields["server.host"], csrf_token),
					type: "POST",
					dataType: "text",
					data: {
						uri: $("input", ".importFrom", wizard.formElem).val()
					},
					success: function(data, txtStatus, xhr) {
						wizard.POSTResponse = data;
						me.importTiddlers(uploadWrapper, wizard);
					},
					error: function(xhr, txtStatus, error) {
						displayMessage(["There was an error fetching the ",
							'url: ', txtStatus].join(""));
						me.restart(wizard);
					}
				});
				return false;
			}
		};
		wizard.setButtons([{
			caption: me.uploadLabel,
			tooltip: me.uploadLabelPrompt,
			onClick: onSubmit
		}]);
		$(wizard.formElem).submit(function(ev) {
			onSubmit(ev);
			ev.preventDefault();
		});
	},

	createForm: function(place, wizard, iframeName) {
		var form = wizard.formElem;
		var me = config.macros.fileImport;
		form.action = me.reflectorURI.format(
			config.extensions.tiddlyspace.getCSRFToken());
		form.enctype = 'multipart/form-data';
		form.encoding = 'multipart/form-data';
		form.method = 'POST';
		form.target = iframeName;
		onSelectChange = function(e) {
			var changeTo = $(this).val();
			if (changeTo == "file") {
				$(".importFrom").html('%0 <input type="file" name="file" />'.
					format(me.step1FileText));
			} else {
				$(".importFrom").html('URL: <input type="text" name="uri" />'
					+ ' Do you want <a target="_blank" href="http://faq.tiddlyspace.com/How%20do%20I%20include%2Fexclude%20spaces%3F">inclusion</a> instead?');
			}
		};
		$(place).append('<span>%0</span>'.format(me.step1TypeChooser)).
			append($(['<select name="uploadtype"><option value="file" selected="selected">file',
				'<option value="uri">url</select>'].join("")).change(onSelectChange)).
			append('<div class="importFrom">%0<input type="file" name="file" /></div>'.
					format(me.step1FileText));
	},

	setOnLoad: function(place, wizard, iframe) {
		var me = config.macros.fileImport;
		var loadHandler = function() {
			me.importTiddlers.apply(this, [place, wizard, iframe]);
		};
		iframe.onload = loadHandler;
		completeReadyStateChanges = 0;
		iframe.onreadystatechange = function() {
			if (++(completeReadyStateChanges) == 5) {
				loadHandler();
			}
		};
	},

	importTiddlers: function(place, wizard, iframe) {
		var tmpStore = new TiddlyWiki();
		var POSTedWiki = "";
		if (wizard.importType == "file") {
			try {
				POSTedWiki= iframe.contentWindow
					.document.documentElement.innerHTML;
			} catch(e) {
				displayMessage(config.macros.fileImport.incorrectTypeError);
				config.macros.fileImport.restart(wizard);
				return;
			}
			// now we are done, so remove the iframe
			$(iframe).remove();
		} else {
			POSTedWiki = wizard.POSTResponse;
		}

		tmpStore.importTiddlyWiki(POSTedWiki);
		var newTiddlers = tmpStore.getTiddlers();
		var workspace = config.defaultCustomFields['server.workspace'];
		var context = {
			status: true,
			statusText: 'OK',
			httpStatus: 200,
			adaptor: wizard.getValue('adaptor'),
			tiddlers: newTiddlers
		};
		context.adaptor.store = tmpStore;
		wizard.setValue('context', context);
		wizard.setValue('workspace', workspace);
		wizard.setValue('inFileImport', true);
		config.macros.importTiddlers.onGetTiddlerList(context, wizard);
	}
};

var _onGetTiddler = config.macros.importTiddlers.onGetTiddler;
config.macros.importTiddlers.onGetTiddler = function(context, wizard) {
	if (wizard.getValue('inFileImport')) {
		var me = config.macros.importTiddlers;
		if(!context.status)
			displayMessage("Error in importTiddlers.onGetTiddler: " + context.statusText);
		var tiddler = context.tiddler;
		var fields = tiddler.fields;
		merge(fields, config.defaultCustomFields);
		fields["server.workspace"] = wizard.getValue('workspace');
		delete fields['server.permissions'];
		delete fields['server.bag'];
		fields['server.page.revision'] = 'false';
		delete fields['server.recipe'];
		fields.changecount = 1;
		store.suspendNotifications();
		store.saveTiddler(tiddler.title, tiddler.title, tiddler.text,
			tiddler.modifier, tiddler.modified, tiddler.tags, tiddler.fields,
			false, tiddler.created);
		store.resumeNotifications();
		var remainingImports = wizard.getValue("remainingImports")-1;
		wizard.setValue("remainingImports",remainingImports);
		if(remainingImports === 0) {
			if(context.isSynchronous) {
				store.notifyAll();
				refreshDisplay();
			}
			wizard.setButtons([
					{caption: me.doneLabel, tooltip: me.donePrompt, onClick: me.onClose}
				],me.statusDoneImport);
			autoSaveChanges();
		}
	} else {
		_onGetTiddler.apply(this, arguments);
	}
};

var _onCancel = config.macros.importTiddlers.onCancel;
config.macros.importTiddlers.onCancel = function(e)
{
	var wizard = new Wizard(this);
	if (!wizard.getValue('inFileImport')) {
		return _onCancel.apply(this, arguments);
	}
	var place = wizard.clear();
	config.macros.fileImport.restart(wizard);
	return false;
};

var _step3Html = config.macros.importTiddlers.step3Html;
var _onGetTiddlerList = config.macros.importTiddlers.onGetTiddlerList;
config.macros.importTiddlers.onGetTiddlerList = function(context, wizard) {
	var fileImport = config.macros.fileImport;
	var importTiddlers = config.macros.importTiddlers;
	if (wizard.getValue('inFileImport')) {
		importTiddlers.step3Html = fileImport.step3Html;
	} else {
		importTiddlers.step3Html = _step3Html;
	}
	_onGetTiddlerList.apply(this, arguments);
};
})(jQuery);
//}}}
/***
|!''Name:''|!''E''asily ''A''daptable ''S''ource ''E''ditor|
|''Description:''|this framework allows you to easily create commands that work on the current tiddler text selection in edit mode|
|''Version:''|0.1.0|
|''Date:''|13/01/2007|
|''Source:''|http://yann.perrin.googlepages.com/twkd.html#E.A.S.E|
|''Author:''|[[Yann Perrin|YannPerrin]]|
|''License:''|[[BSD open source license]]|
|''~CoreVersion:''|2.x|
|''Browser:''|Firefox 1.0.4+; Firefox 1.5; InternetExplorer 6.0|

See [[easyFormat]] and [[easyInsert]] for menu building examples. You must add the menu to [[EditTemplate]] as
{{{<div macro='toolbar format insert'></div>}}}

***/
////Messages Definition
//{{{
config.messages.Ease = {
noselection:"nothing selected",
asktitle:"enter the new tiddler title",
exists:" already exists, please enter another title",
askForTagsLabel:"enter the new tiddler tags",
tiddlercreated:" tiddler created"
}
//}}}
////
//{{{
if (!window.TWkd) window.TWkd={context:{}};
if (!TWkd.Ease)
 TWkd.Ease = function (text,tooltip){
 this.text = text;
 this.tooltip = tooltip;
 this.modes = [];
 this.addMode = function(modeDefinition) {this.modes.push(modeDefinition);};
 this.handler = function(event,src,title) {
 TWkd.context.command = this;
 TWkd.context.selection=this.getSelection(title);
 if (this.modes.length==1) {
 this.modes[0].operation();
 }
 else {
 var popup = Popup.create(src);
 if(popup) {
 for (var i=0; i<this.modes.length; i++) {
 createTiddlyButton(createTiddlyElement(popup,"li"), this.modes[i].name, this.modes[i].tooltip, this.OperateFromButton, null, 'id'+i, null);
 }
 Popup.show(popup,false);
 event.cancelBubble = true;
 if (event.stopPropagation) event.stopPropagation();
 return false;
 }
 }
 };
 };

TWkd.Ease.prototype.OperateFromButton = function(e){
 var commandMode=this.getAttribute('Id').replace('id','');
 TWkd.context.command.modes[commandMode].operation();
};

TWkd.Ease.prototype.getTiddlerEditField = function(title,field){
 var tiddler = document.getElementById(story.idPrefix + title);
 if(tiddler != null){
 var children = tiddler.getElementsByTagName("*")
 var e = null;
 for (var t=0; t<children.length; t++){
 var c = children[t];
 if(c.tagName.toLowerCase() == "input" || c.tagName.toLowerCase() == "textarea"){
 if(!e) {e = c;}
 if(c.getAttribute("edit") == field){e = c;}
 }
 }
 if(e){return e;}
 }
} // closes getTiddlerEditField function definition
 
TWkd.Ease.prototype.getSelection = function(title,quiet) {
 var tiddlerTextArea = this.getTiddlerEditField(title,"text");
 var result = {};
 if (document.selection != null && tiddlerTextArea.selectionStart == null) {
 tiddlerTextArea.focus();
 var range = document.selection.createRange();
 var bookmark = range.getBookmark();
 var contents = tiddlerTextArea.value;
 var originalContents = contents;
 var marker = "##SELECTION_MARKER_" + Math.random() + "##";
 while(contents.indexOf(marker) != -1) {
 marker = "##SELECTION_MARKER_" + Math.random() + "##";
 }
 var selection = range.text;
 range.text = marker + range.text + marker;
 contents = tiddlerTextArea.value;
 result.start = contents.indexOf(marker);
 contents = contents.replace(marker, "");
 result.end = contents.indexOf(marker);
 tiddlerTextArea.value = originalContents;
 range.moveToBookmark(bookmark);
 range.select();
 }
 else {
 result.start=tiddlerTextArea.selectionStart;
 result.end=tiddlerTextArea.selectionEnd;
 }
 result.content=tiddlerTextArea.value.substring(result.start,result.end);
 result.source=title;
 if (!result.content&&!quiet) displayMessage(config.messages.Ease.noselection);
 return(result);
}//closes getSelection function definition

// replace selection or insert new content
TWkd.Ease.prototype.putInPlace=function(content,workplace) {
 var tiddlerText = this.getTiddlerEditField(workplace.source,"text");
 tiddlerText.value = tiddlerText.value.substring(0,workplace.start)+content+tiddlerText.value.substring(workplace.end);
}

// asking for title
TWkd.Ease.prototype.askForTitle = function(suggestion) {
 if (!suggestion)
 suggestion = "";
 var newtitle;
 while (!newtitle||store.tiddlerExists(newtitle))
 {
 if (store.tiddlerExists(newtitle))
 displayMessage(newtitle+config.messages.Ease.exists);
 newtitle = prompt(config.messages.Ease.asktitle,suggestion);
 if (newtitle==null)
 {
 displayMessage(config.messages.Ease.titlecancel);
 return(false);
 }
 }
 return(newtitle);
}//closes askForTitle function definition

// creation of a new tiddler
TWkd.Ease.prototype.newTWkdLibTiddler = function(title,content,from,askForTags){
 var tiddler = new Tiddler();
 tiddler.title = title;
 tiddler.modifier = config.options.txtUserName;
 tiddler.text = content;
 (from) ? tiddler.tags = [from] : tiddler.tags=[];
 if (askForTags)
 tiddler.tags = prompt(config.messages.Ease.askForTagsLabel,'[['+from+']]').readBracketedList();
 store.addTiddler(tiddler);
 //store.notifyAll();
 displayMessage(title+config.messages.Ease.tiddlercreated);
}

if (!TWkd.Mode)
 TWkd.Mode = function (name,tooltip,ask,operation) {
 this.name = name;
 this.tooltip = tooltip;
 this.ask = ask;
 this.operation = operation;
 };
//}}}
The term Software Development Model (SDM) is used to address [[Software Development Process]] (SDP) realization sequence.

SDM concept is used as Software Development Process Model to identify different sequence approaches to the development process like [[Waterfall|http://en.wikipedia.org/wiki/Waterfall_model]], [[Spiral|http://en.wikipedia.org/wiki/Spiral_model]], etc.

Although there are many development models one must acknowledge that we can not ''do'' before we know ''how'' to do and we can not choose how to do before knowing ''what'' to do and also that knowing ''why'' to do is very useful to know what to do. This implies that, ultimately, all models are little more than sequences of waterfalls.

----
See also : [[Software Development Pattern]]
----
@@color:#c4d6ed; ^^
Description: Software Development Model (SDM) concept as used here
^^@@
!!Friends
* [[Development with a Dot|http://weblogs.asp.net/ricardoperes/default.aspx]] - Ricardo Peres .Net technical blog with lots of enlightened information.

----
<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
	<title>Reply</title>
	<link rel="stylesheet" href="//tiddlyspace.com/bags/benspa_public/tiddlers/bootvelcro.css">
	<style>
		html,
		body {
			overflow: hidden;
			background-color: transparent;
		}

		#container {
			/* prevent a fouc if no images present */
			display: none;
		}

		.modal-header {
			border-bottom: none;
			padding: 5px 0 0;
			position: absolute;
			width: 100%;
			background-color: #e0e0e0;
			-webkit-border-radius: 6px 6px 0 0;
			-moz-border-radius: 6px 6px 0 0;
			border-radius: 6px 6px 0 0;
			cursor: move;
		}

		.form-actions {
			position: absolute;
			bottom: 0;
			box-sizing: border-box;
			-moz-box-sizing: border-box;
			width: 100%;
			margin: 0;
			border-radius: 0 0 6px 6px;
			background-color: #e0e0e0;
			border-top: 1px solid gray;
		}

		.form-actions input.btn {
			width: auto;
			float: right;
			margin: 0 0.2em;
		}

		.closeBtn {
			background-color: #DCE7F1 !important;
		}

		.primary {
			background-color: #09F !important;
		}

		h1 {
			margin-bottom: 9px;
			margin-top: 9px;
		}

		body {
			width: 100%;
			height: 100%;
			position: absolute;
		}

		.modal {
			margin: 10px;
			top: 0;
			left: 0;
			bottom: 0;
			width: 510px;
			position: absolute;
			box-shadow: #444 0px 0px 10px 2px;
			border-radius: 6px;
			background-color: white;
			border: 1px solid gray;
			background-color: #F0F4F8;
		}

		label em {
			cursor: pointer;
		}

		.modal-body {
			overflow: auto;
			position: absolute;
			top: 0;
			bottom: 0;
			left: 0;
			right: 0;
			margin: 65px 20px 67px;
			background-color: transparent;
		}

		.nav-tabs {
			padding-left: 1%;
			margin: 0;
			width: 99%;
			border-color: gray;
		}

		.nav-tabs > li {
			cursor: pointer;
		}

		.nav-tabs > li > a {
			line-height: 2.4em;
			font-weight: bold;
			font-size: 100%;
		}

		.nav-tabs > li.active > a{
			background-color: #F0F4F8;
			border-color: gray;
			border-bottom-color: #F0F4F8;
		}

		.active {
			display: block;
		}

		input,
		textarea,
		select,
		.uneditable-input {
			color: #606060;
		}

		.imagePicker {
			-moz-box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.1);
			-webkit-box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.1);
			box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.1);
			border: 1px solid #CCC;
			height: 110px;
			overflow: auto;
			-webkit-border-radius: 3px;
			-moz-border-radius: 3px;
			border-radius: 3px;
			margin-left: 0;
		}

		.imagePicker img {
			margin: 5px;
			border: 2px solid transparent;
		}

		.imagePicker .current {
			border: 2px dotted #555;
		}

		label {
			font-weight: bold;
		}

		.form-actions label {
			float: left;
			margin-top: 0.75em;
		}

		fieldset input,
		fieldset textarea {
			width: 90%;
			border-color: gray;
		}

		@media all and (max-width: 550px) {
			.modal {
				width: 95%;
			}
		}

		#help {
			position: absolute;
			border: 0;
			right: 4px;
			top: 5px;
			text-indent: -9999px;
			color: transparent;
			height: 16px;
			width: 16px;
			background: none;
			background-image: url(/bags/common/tiddlers/help.png);
			background-repeat: no-repeat;
			background-color: white;
			z-index: 2;
			border-radius: 10px;
		}

		#help-info {
			padding: 0;
			border: 1px solid gray;
			width: 60%;
			height: 50px;
			color: #404040;
			background-color: white;
			position: absolute;
			top: 5px;
			right: 5px;
			z-index: 1;
			cursor: auto;
			border-radius: 5px;

		}

		#help-info p {
			padding: 10px 25px;
			margin-bottom: 0;
		}
	</style>
</head>
<body>
	<div id="container">
		<form action="#" class="modal">
			<div class="modal-header">
				<button id="help">help</button>
				<div id="help-info" style="display:none;"><p>
				Found something interesting? Write about it in your own space. <a href="//docs.tiddlyspace.com/Reply to this Tiddler" target="_blank">Find out more</a>
				</p></div>
				<ul class="nav nav-tabs" data-tabs="tabs">
					<li class="active" data-tab-name="post"><a href="#postForm">Reply</a></li>
				</ul>
			</div>


			<fieldset id="postForm" class="modal-body">
				<label>Title
					<input type="text" name="title">
				</label>
				<input type="hidden" name="url">
				<label>Post
					<textarea name="text" rows="8"></textarea>
				</label>
				<label>Tags
					<input type="text" name="tags" value="">
				</label>
			</fieldset>


			<div class="form-actions">
				<label class="checkbox">
					<input type="checkbox" name="private" val="private">
					keep private
				</label>
				<input type="submit" class="btn primary btn-large" value="Done">
				<input type="button" class="btn btn-large closeBtn" value="Cancel">
			</div>
		</form>
	</div>

	<script type="text/javascript"
            src="/bags/common/tiddlers/jquery.js"></script>
	<script type="text/javascript" src="/bags/tiddlyspace/tiddlers/chrjs"></script>
	<script type="text/javascript" src="/bags/common/tiddlers/_reply.js"></script>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
	<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
	<title>Account</title>
	<link href="/bags/common/tiddlers/profile.css" type='text/css' rel='stylesheet' >
	<link href="/bags/common/tiddlers/admin.css" type='text/css' rel='stylesheet' >
	<link href="/bags/common/tiddlers/jquery-ui.custom.css" type='text/css' rel='stylesheet' >
</head>
<body>

<div id="container">
	<div class="main section">
		<a class="app" href="/">home</a>
		<div class="left">
		<div id="siteiconArea">
		<h2>User Icon</h2>
		<div>
			<img id="siteicon" class="siteicon">
			<form id="upload" method="POST" enctype="multipart/form-data">
				<input type="hidden" name="title" value="SiteIcon" />
				<input type="hidden" name="tags" value="excludeLists">
				<input type="hidden" name="csrf_token" class="csrf" />
				<input type="file" name="file" accept="image/*" />
				<input type="submit" value="upload" />
			</form>
			<div id="dropzone">Drop file here
				<img class="notloading" src="/bags/common/tiddlers/ajax-loader.gif" alt="submitting SiteIcon" />
			</div>
		</div>
		</div>
		<h2>Find Space</h2>
		<form class="spaceSearch">
			<input class="inputBox" type="text" placeholder="find space" />
			<a href="http://docs.tiddlyspace.com/What%20is%20a%20Space%3F" class="help"
				title="What is a space?">What is a space?</a>
			<button>view all</button>
		</form>
		<div class='list-container'>
			You are a member of the following spaces:
			<ul class='ts-space-search'>
			</ul>
		</div>
		<h2>Create New Space</h2>
		<form class="ts-spaces">
			<input class="inputBox" type="text" name="spacename" placeholder="space name"><span class="hostSuffix">.tiddlyspace.com</span>
			<input type="submit" value="Create Space" />
		</form>
		</div>
		<div class="right">
		<h2>Change Password</h2>
		<form class="ts-password">
			<input class="inputBox" placeholder="existing password" type="password" name="password">
			<input class="inputBox" placeholder="new password" type="password" name="new_password">
			<input class="inputBox" placeholder="new password"	type="password" name="new_password_confirm">
			<input type="submit" value="Change password">
		</form>
		<h2>OpenID</h2>
		<h3>Why OpenID?</h3>
		<a href="http://openid.net/"><img src="/bags/common/tiddlers/openid.png" alt="openid" ></a><br />
		Use just one username and password across hundreds of OpenID-enabled sites.<br />
		It's an open standard.<br />
		<a href="http://openid.net/what/">learn more</a>
		<ul class="ts-identities"></ul>
		<form class="ts-openid" target="_top">
			<div>
				Add an openid:
			</div>
			<input class="inputBox" type="text" name="openid" placeholder="your openid" />
			<input type="submit" value="Register" />
			<a href="http://openid.net/get-an-openid/" class="help"
			title="What is an open id?">What is an open id?</a>
		</form>
		</div>
		<div class="clear"></div>
	</div>
</div>
<script src="/bags/common/tiddlers/backstage.js"></script>
<script src='/bags/common/tiddlers/jquery.js'></script>
<script src='/bags/tiddlyspace/tiddlers/chrjs'></script>
<script src='/bags/common/tiddlers/chrjs.space'></script>
<script src='/bags/common/tiddlers/chrjs.users'></script>
<script src='/bags/common/tiddlers/chrjs.identities'></script>
<script src="/bags/common/tiddlers/jquery-ui.custom.js"></script>
<script src='/bags/common/tiddlers/jquery-form.js'></script>
<script src="/bags/common/tiddlers/siteiconupload.js"></script>
<script src='/bags/common/tiddlers/ts.js'></script>
<script src="/status.js"></script>
<script type="text/javascript">
/*
 * jQuery UI Autocomplete HTML Extension
 *
 * Copyright 2010, Scott González (http://scottgonzalez.com)
 * Dual licensed under the MIT or GPL Version 2 licenses.
 *
 * http://github.com/scottgonzalez/jquery-ui-extensions
 */
(function( $ ) {

var proto = $.ui.autocomplete.prototype,
	initSource = proto._initSource;

function filter( array, term ) {
	var matcher = new RegExp( $.ui.autocomplete.escapeRegex(term), "i" );
	return $.grep( array, function(value) {
		return matcher.test( $( "<div>" ).html( value.label || value.value || value ).text() );
	});
}

$.extend( proto, {
	_initSource: function() {
		if ( this.options.html && $.isArray(this.options.source) ) {
			this.source = function( request, response ) {
				response( filter( this.options.source, request.term ) );
			};
		} else {
			initSource.call( this );
		}
	},

	_renderItem: function( ul, item) {
		return $( "<li></li>" )
			.data( "item.autocomplete", item )
			.append( $( "<a></a>" )[ this.options.html ? "html" : "text" ]( item.label ) )
			.appendTo( ul );
	}
});

})( jQuery );

/***
_accounts application specific javascript
***/
var link;
ts.init(function(ts) {
	if(ts.user.anon) { // redirect to homepage when user not logged in
		window.location = ts.getHost();
	} else if(ts.user.name === ts.currentSpace){
		initSiteIconUpload(ts.user.name);
	} else {
		link = $("<a />").attr("href", ts.getHost(ts.user.name) + "/_account").text("Change User Icon");
		$("#siteiconArea div").empty().append(link);
	}
	$(".hostSuffix").text("." + ts.getHost("").split("//")[1]);
	ts.getSpaces(function(spaces) {
		$("<div class='info' />").text("You have " + spaces.length + " spaces.").insertBefore($(".spaceSearch")[0]);
		$("form.spaceSearch input").autocomplete({
			html: true,
			source: function(req, response) {
				ts.getSpaces(function(spaces) {
					var selected = [];
					for(var i = 0; i < spaces.length; i++) {
						var space = spaces[i];
						if(space.name.indexOf(req.term) > -1) {
							var host = ts.getHost(space.name) ;
							var img = host + "/SiteIcon";
							selected.push({
								value: space.name,
								label: '<a href="' + host + '" target="_parent" class="autocompleteLink"><img src="' + img + '" style="height:24px;width:auto;max-height:24px;max-width:24px;"/>' + space.name + '</a>'
							});
						}
					}
					response(selected);
				});
			},
			select: function(event, ui) {
				window.top.location = ts.getHost(ui.item.value);
			}
		});

		var $ul = $('.ts-space-search');
		$.each(spaces, function(i, space) {
			$ul.append($('<li/>').html($('<a/>').attr('href', space.uri)
				.text(space.name)));
		});

		$('form.spaceSearch button').click(function(ev) {
			$('.list-container').slideToggle('fast');
			ev.preventDefault();
			return false;
		});
	});
});

if(window != window.top) {
	$("html").addClass("iframeMode");
	$("a").live("click",function(ev) {
		$(ev.target).attr("target", "_parent");
	});
}
</script>
<!--[if lt IE 8]>
<script type="text/javascript" src="/bags/common/tiddlers/json2.js"></script>
<![endif]-->
</body>
</html>
<<TiddlyTagMindMap filter:[tag[Reuse]] vizType:rgraph id:Reuse nodeSize:10 nodeType:ellipse nodeHoverColor:'#ee00ff' nodeColor:"#ff0000" edgeColor:'#ccc' edgeWidth:2 width:750 height:480 template:NodeTemplate>>

----
/%
@@color:#c4d6ed; ^^
Description: Tag for reuse matters
^^@@
%/
/***
|Name|HoverMenuPlugin|
|Created by|SaqImtiaz|
|Location|http://tw.lewcid.org/#HoverMenuPlugin|
|Version|1.11|
|Requires|~TW2.x|
!Description:
Provides a hovering menu on the edge of the screen for commonly used commands, that scrolls with the page.

!Demo:
Observe the hovering menu on the right edge of the screen.

!Installation:
Copy the contents of this tiddler to your TW, tag with systemConfig, save and reload your TW.
To customize your HoverMenu, edit the HoverMenu shadow tiddler.

To customize whether the menu sticks to the right or left edge of the screen, and its start position, edit the HoverMenu configuration settings part of the code below. It's well documented, so don't be scared!

The menu has an id of hoverMenu, in case you want to style the buttons in it using css.

!Notes:
Since the default HoverMenu contains buttons for toggling the side bar and jumping to the top of the screen and to open tiddlers, the ToggleSideBarMacro, JumpMacro and the JumpToTopMacro are included in this tiddler, so you dont need to install them separately. Having them installed separately as well could lead to complications.

If you dont intend to use these three macros at all, feel free to remove those sections of code in this tiddler.

!To Do:
* rework code to allow multiple hovering menus in different positions, horizontal etc.
* incorporate code for keyboard shortcuts that correspond to the buttons in the hovermenu

!History:
*03-08-06, ver 1.1.2: compatibility fix with SelectThemePlugin
*03-08-06,  ver 1.11: fixed error with button tooltips
*27-07-06, ver 1.1 : added JumpMacro to hoverMenu
*23-07-06

!Code
***/

/***
start HoverMenu plugin code
***/
//{{{
config.hoverMenu={};
//}}}

/***
HoverMenu configuration settings
***/
//{{{
config.hoverMenu.settings={
               align: 'right',    //align menu to right or left side of screen, possible values are 'right' and 'left'               
               x: 1,              // horizontal distance of menu from side of screen, increase to your liking.
               y: 158            //vertical distance of menu from top of screen at start, increase or decrease to your liking
               };
//}}}

//{{{
//continue HoverMenu plugin code
config.hoverMenu.handler=function()
{              
               if (!document.getElementById("hoverMenu"))
               {
               var theMenu = createTiddlyElement(document.getElementById("contentWrapper"), "div","hoverMenu");
               theMenu.setAttribute("refresh","content");
               theMenu.setAttribute("tiddler","HoverMenu");
               var menuContent = store.getTiddlerText("HoverMenu");
               wikify(menuContent,theMenu);
              }

	       var Xloc = this.settings.x;
	       Yloc =this.settings.y;
	       var ns = (navigator.appName.indexOf("Netscape") != -1);
	       function SetMenu(id)
                        {
		        var GetElements=document.getElementById?document.getElementById(id):document.all?document.all[id]:document.layers[id];
		        if(document.layers)GetElements.style=GetElements;
		        GetElements.sP=function(x,y){this.style[config.hoverMenu.settings.align]=x +"px";this.style.top=y +"px";};
		        GetElements.x = Xloc;
		        GetElements.y = findScrollY();
		        GetElements.y += Yloc;
		        return GetElements;
	                }
               window.LoCate_XY=function()
                        {
		        var pY =  findScrollY();
                        ftlObj.y += (pY + Yloc - ftlObj.y)/15;
		        ftlObj.sP(ftlObj.x, ftlObj.y);
		        setTimeout("LoCate_XY()", 10);
	                }
               ftlObj = SetMenu("hoverMenu");
	       LoCate_XY();
};

window.old_lewcid_hovermenu_restart = restart;
restart = function()
{
               window.old_lewcid_hovermenu_restart();
               config.hoverMenu.handler();
};

setStylesheet(
"#hoverMenu .imgLink, #hoverMenu .imgLink:hover {border:none; padding:0px; float:right; margin-bottom:2px; margin-top:0px;}\n"+
"#hoverMenu  .button, #hoverMenu  .tiddlyLink {border:none; font-weight:bold; background:#18f; color:#FFF; padding:0 5px; float:right; margin-bottom:4px;}\n"+
"#hoverMenu .button:hover, #hoverMenu .tiddlyLink:hover {font-weight:bold; border:none; color:#fff; background:#000; padding:0 5px; float:right; margin-bottom:4px;}\n"+
"#hoverMenu .button {width:100%; text-align:center}"+
"#hoverMenu { position:absolute; width:7px;}\n"+
"\n","hoverMenuStyles");


config.macros.renameButton={};
config.macros.renameButton.handler = function(place,macroName,params,wikifier,paramString,tiddler)
{

               if (place.lastChild.tagName!="BR")
                     {
                      place.lastChild.firstChild.data = params[0];
                      if (params[1]) {place.lastChild.title = params[1];}
                     }
};

config.shadowTiddlers["HoverMenu"]="<<top>>\n<<toggleSideBar>><<renameButton '>' >>\n<<jump j '' top>>\n<<saveChanges>><<renameButton s 'Save TiddlyWiki'>>\n<<newTiddler>><<renameButton n>>\n";
//}}}
//end HoverMenu plugin code

//Start ToggleSideBarMacro code
//{{{
config.macros.toggleSideBar={};

config.macros.toggleSideBar.settings={
         styleHide :  "#sidebar { display: none;}\n"+"#contentWrapper #displayArea { margin-right: 1em;}\n"+"",
         styleShow : " ",
         arrow1: "«",
         arrow2: "»"
};

config.macros.toggleSideBar.handler=function (place,macroName,params,wikifier,paramString,tiddler)
{
          var tooltip= params[1]||'toggle sidebar';
          var mode = (params[2] && params[2]=="hide")? "hide":"show";
          if (!params[2])
              mode = "hide";
          var arrow = (mode == "hide")? this.settings.arrow1:this.settings.arrow2;
          var label= (params[0]&&params[0]!='.')?params[0]+" "+arrow:arrow;
          var theBtn = createTiddlyButton(place,label,tooltip,this.onToggleSideBar,"button HideSideBarButton");
          if (mode == "hide")
             { 
             (document.getElementById("sidebar")).setAttribute("toggle","hide");
              setStylesheet(this.settings.styleHide,"ToggleSideBarStyles");
             }
};

config.macros.toggleSideBar.onToggleSideBar = function(){
          var sidebar = document.getElementById("sidebar");
          var settings = config.macros.toggleSideBar.settings;
          if (sidebar.getAttribute("toggle")=='hide')
             {
              setStylesheet(settings.styleShow,"ToggleSideBarStyles");
              sidebar.setAttribute("toggle","show");
              this.firstChild.data= (this.firstChild.data).replace(settings.arrow1,settings.arrow2);
              }
          else
              {    
               setStylesheet(settings.styleHide,"ToggleSideBarStyles");
               sidebar.setAttribute("toggle","hide");
               this.firstChild.data= (this.firstChild.data).replace(settings.arrow2,settings.arrow1);
              }

     return false;
}

setStylesheet(".HideSideBarButton .button {font-weight:bold; padding: 0 5px;}\n","ToggleSideBarButtonStyles");
//}}}
//end ToggleSideBarMacro code

//start JumpToTopMacro code
//{{{
config.macros.top={};
config.macros.top.handler=function(place,macroName)
{
               createTiddlyButton(place,"^","jump to top",this.onclick);
}
config.macros.top.onclick=function()
{
               window.scrollTo(0,0);
};

config.commands.top =
{
               text:" ^ ",
               tooltip:"jump to top"
};

config.commands.top.handler = function(event,src,title)
{
               window.scrollTo(0,0);
}
//}}}
//end JumpToStartMacro code

//start JumpMacro code
//{{{
config.macros.jump= {};
config.macros.jump.handler = function (place,macroName,params,wikifier,paramString,tiddler)
{
        var label = (params[0] && params[0]!=".")? params[0]: 'jump';
        var tooltip = (params[1] && params[1]!=".")? params[1]: 'jump to an open tiddler';
        var top = (params[2] && params[2]=='top') ? true: false;        

        var btn =createTiddlyButton(place,label,tooltip,this.onclick);
        if (top==true)
              btn.setAttribute("top","true")
}

config.macros.jump.onclick = function(e)
{
        if (!e) var e = window.event;
        var theTarget = resolveTarget(e);
        var top = theTarget.getAttribute("top");
	var popup = Popup.create(this);
	if(popup)
		{
                 if(top=="true")
                                {createTiddlyButton(createTiddlyElement(popup,"li"),'Top ↑','Top of TW',config.macros.jump.top);
                                 createTiddlyElement(popup,"hr");}
		
		story.forEachTiddler(function(title,element) {
			createTiddlyLink(createTiddlyElement(popup,"li"),title,true);
			});
                }
	Popup.show(popup,false);
	e.cancelBubble = true;
	if (e.stopPropagation) e.stopPropagation();
	return false;
}

config.macros.jump.top = function()
{
       window.scrollTo(0,0);
}
//}}}
//end JumpMacro code

//utility functions
//{{{
Popup.show = function(unused,slowly)
{
	var curr = Popup.stack[Popup.stack.length-1];
	var rootLeft = findPosX(curr.root);
	var rootTop = findPosY(curr.root);
	var rootHeight = curr.root.offsetHeight;
	var popupLeft = rootLeft;
	var popupTop = rootTop + rootHeight;
	var popupWidth = curr.popup.offsetWidth;
	var winWidth = findWindowWidth();
        if (isChild(curr.root,'hoverMenu'))
              var x = config.hoverMenu.settings.x;
        else
              var x = 0;
	if(popupLeft + popupWidth+x > winWidth)
		popupLeft = winWidth - popupWidth -x;
        if (isChild(curr.root,'hoverMenu'))
  	        {curr.popup.style.right = x + "px";}
        else
                curr.popup.style.left = popupLeft + "px";
	curr.popup.style.top = popupTop + "px";
	curr.popup.style.display = "block";
	addClass(curr.root,"highlight");
	if(config.options.chkAnimate)
		anim.startAnimating(new Scroller(curr.popup,slowly));
	else
		window.scrollTo(0,ensureVisible(curr.popup));
}

window.isChild = function(e,parentId) {
        while (e != null) {
                var parent = document.getElementById(parentId);
                if (parent == e) return true;
                e = e.parentNode;
                }
        return false;
};
//}}}


!Upload an icon
<<tiddler spaceIcon>>
!Describe your space
If you haven't already done so, you should provide a brief decscription of yourself and what you're using this space for. To do this, just edit the [[SiteInfo]] tiddler (keeping the title the same of course).

!Change the title
<<tiddler spaceTitle>>
!Change the theme
<<tiddler colorScheme>>
!Change the menu
If you'd like to change the menu items along the top, you can edit the [[MainMenu]] tiddler.

!Change the default tiddlers
<<tiddler setDefaultTiddlers>>
!More Advanced customisations
If you know HTML and CSS, you can edit some or all of the following tiddlers to customise your space further:
* PageTemplate
* EditTemplate
* ViewTemplate
* StyleSheet
//The second (and better) scenario is modularized based on "design decisions." Parnas observes, "We propose instead that one begins with a list of difficult design decisions or design decisions which are likely to change. Each module is then designed to hide such a decision from the others." //

* Edward V. Berard - Abstraction, Encapsulation and Information Hiding	[[[Berard]|BibliographyPage##Berard]]
* D.L. Parnas  - On the Criteria To Be Used in Decomposing Systems Into Modules, 1972 [[[Parnas 1972]|BibliographyPage##Parnas 1972]]
----
!! Why do you need Filesystem and Namespace Guidelines
Filesystem and Namespace Guidelines shall be a mandatory (and reusable) part of your [[Meta-architecture]]. These are strategic decisions that will affect all of your project in very important qualities like reusability, maintainability, modularization and team work efficiency. You can survive without them in a single man small project, but will need them as a roadmap for design and implementation and as an enforcing mechanism for your [[Application Archetype]] among your team.

!! Filesystem, namespaces and packaging
First of all, filesystem, namespaces and packaging shall be equivalent. This is important for search ability on the code and avoids incoherence and naming clashes when reusing.
{{{
Filesystem :
C:\source\AdacSoft\ProjectX\Server\DAO
shall contain namespace :
AdacSoft.ProjectX.Server.DAO
that is packaged in DLL :
AdacSoft.ProjectX.Server.DAO.dll
}}}
This simple rule will save you a lot of trouble when developing and maintaining your code on a team. With this you define packaging, placement and conceptual [[modularization|Modularization]] at the same time. The binary naming also plays an important role when you need to dynamically discover and load ~DLLs based on a namespace. DLL name may be shorter than namespace, that is, {{{AdacSoft.ProjectX.Server.DAO.SQLite}}} may be contained in {{{AdacSoft.ProjectX.Server.DAO.dll}}}.

!! Filesystem definition
You shall have a standard base filesystem structure that you reuse and follow in every one of your projects. And you shall, definitely, use a [[CVS]] system. See [[Promoting Reuse by Reference]] guideline for a detailed filesystem and reuse structure proposal.

!! Namespace definition
For defining namespace you shall also follow defined and well understood rules.

First you want it to be different to avoid conflicts and to promote your brand so you should use your company name as root. You shall also consider using third-party components and also to segregate your own reusable components, so you may have two other root level items : 
*''[~YourCompanyName]'' : for your project's root. 
*''[~YourCompanyAcronym]'' : for your own reusable modules. 
*''[~ThirdParties]'' : for external, off-the-shelf components. The second level shall be producer name and the third product name for instance {{{ThirdParties.Apache.Log4Net}}}
These guidelines have an huge impact in management and maintenance of your [[CVS]] repository and also help in preventing [[reuse by copy|Reuse by Reference]].

Then you want to distinguish your different projects so the second level shall be project name.
At the third level you shall be concerned with coupling control and tier segregation to handle strict n-tier scenarios.
You shall stick to this organization even if your code is single tier. Think about it being reused in a n-tier scenario or if you want to reuse n-tier code. Also this encourages good [[modularization|Modularization]] and thus [[coupling control|Namespace Coupling Guidelines]].

The fourth level shall represent your conceptual modules (Components or archetype parts). This shall be a technical (Architectural) criterion.

From the fourth level onwards common sense applies, don't go too deep, divide if you have to, you may use technical, business or any other criteria but be coherent and explicit.


Your namespaces shall then be built according to : 
{{{
{Root level}.{Project/Product level}.{Tier level}.{Module level}
}}}
* ''Root level''
** Root level shall reflect ownership.
*** ''[~YourCompanyName]'' for specific project/product resources
*** ''[~YourCompanyAcronym]'' for reusable, shared among projects, resources
*** ''[~ThirdParties]'' for third-party resources. You may choose to use third party company name at this level but it will clutter root.
* ''Project/Product level''
** This second level is dependant on the previous one and shall reflect domain or coupling layer separation.
** For ''[~YourCompanyName]'' root :
*** [Project Code] - for "normal" projects
*** [Product Name] - for products
** For ''[~YourCompanyAcronym]'' root :
*** ''CMP'' is intended to hold reusable modules that are independent from particular architectures but that may be strongly coupled to other CMP modules.
*** ''FRW'' is intended to hold reusable modules that are strongly coupled and that require a specific architecture. This layer encourages strong automation.
*** ''SYS'' is intended to hold reusable modules that are loosely coupled and that shall be seen as autonomous subsystems.
** For ''[~ThirdParties]'' root :
*** This shall be manufacturer name followed by the item namespace
*** The ~ThirdParties root level has no further guidelines after 2nd level and shall conform to producer specifications. Example {{{Apache.log4net}}}
* ''Tier level''
** ''Client'' : client side code, may depend on Common, interacts with user.
** ''Common'' : common code, may not depend on any of the others, may not interact with user.
** ''Server'' : server side code, may depend on Common, may not interact with user.
* ''Module level''
** From module level onwards common sense rules apply.
** You may use Business Domain or sub-Domain criteria or Technical Domain or both.

----
See also : [[Namespace Coupling Guidelines]], [[Namespace Code Placement Guidelines]] and [[Promoting Reuse by Reference]]
----
@@color:#c4d6ed; ^^
Description: An example Filesystem and Namespace Guideline for .Net projects.
^^@@
in reply to [[SearchShortcomings]]@cdent:

About Google searches it would be nice that not only bags and recipes be indexed by it. Tiddlers would be the most interesting. Any way the bag page should, at least have always a clear link to the tiddler's permalink.

A lot of people gets to the bag content from Google and do not realise there is a TiddlyWiki beneath it.

 
/***
|''Name''|TiddlySpaceConfig|
|''Version''|0.7.7|
|''Description''|TiddlySpace configuration|
|''Status''|stable|
|''Source''|http://github.com/TiddlySpace/tiddlyspace/raw/master/src/plugins/TiddlySpaceConfig.js|
|''CoreVersion''|2.6.1|
|''Requires''|TiddlyWebConfig ServerSideSavingPlugin TiddlyFileImporter|
!Code
***/
//{{{
(function($) {

var tweb = config.extensions.tiddlyweb;

var recipe = config.defaultCustomFields["server.workspace"].split("recipes/")[1];
var currentSpace; // assigned later

var disabledTabs = [];

var coreBags = ["system", "tiddlyspace"];
var systemSpaces = ["plugins", "info", "images", "theme"];
systemSpaces = $.map(systemSpaces, function(item, i) {
	return "system-%0_public".format(item);
});

// hijack search macro to add custom attributes for mobile devices
var _search = config.macros.search.handler;
config.macros.search.handler = function(place, macroName, params) {
	_search.apply(this, arguments);
	$(".searchField:input", place).
		attr({ autocapitalize: "off", autocorrect: "off" });
};

// arg is either a container name or a tiddler object
// if fuzzy is truthy, space may be inferred from workspace (for new tiddlers)
// returns space object or false
var determineSpace = function(arg, fuzzy) {
	if(typeof arg == "string") { // container name
		var space = split(arg, "_", "r");
		return ["public", "private"].contains(space.type) ? space : false;
	} else if(arg) { // tiddler
		var container = determineContainer(arg, fuzzy);
		return container ? determineSpace(container.name, fuzzy) : false;
	} else {
		return false;
	}
};

// if fuzzy is truthy, container may be inferred from workspace for new tiddlers
// returns container object or false
var determineContainer = function(tiddler, fuzzy) { // TODO: expose?
	var bag = tiddler.fields["server.bag"];
	var recipe = tiddler.fields["server.recipe"]; // XXX: unused/irrelevant/redundant!?
	if(bag) {
		return { type: "bag", name: bag };
	} else if(recipe) {
		return { type: "recipe", name: recipe };
	} else if(fuzzy) { // new tiddler
		var workspace = tiddler.fields["server.workspace"];
		if(workspace) {
			var container = split(workspace, "/", "l");
			return ["bags", "recipes"].contains(container.type) ? container : false;
		} else {
			return false;
		}
	} else {
		return false;
	}
};

// hijack removeTiddlerCallback to restore tiddler from recipe cascade -- TODO: move into TiddlyWebWiki?
var sssp = config.extensions.ServerSideSavingPlugin;
var _removeTiddlerCallback = sssp.removeTiddlerCallback;
sssp.removeTiddlerCallback = function(context, userParams) {
	var title = context.tiddler.title;
	var recipe = context.tiddler.fields["server.recipe"];
	_removeTiddlerCallback.apply(this, arguments);
	if(recipe) {
		context.workspace = "recipes/" + recipe;
		var callback = function(context, userParams) {
			if(context.status) {
				var dirty = store.isDirty();
				store.saveTiddler(context.tiddler).clearChangeCount();
				store.setDirty(dirty);
			} else {
				store.notify(title, true);
			}
		};
		context.adaptor.getTiddler(title, context, null, callback);
	}
};

// splits a string once using delimiter
// mode "l" splits at the first, "r" at the last occurrence
// returns an object with members type and name
var split = function(str, sep, mode) {
	mode = mode == "r" ? "pop" : "shift"; // TODO: use +/-1 instead of "l"/"r"?
	var arr = str.split(sep);
	var type = arr.length > 1 ? arr[mode]() : null;
	return { type: type, name: arr.join(sep) };
};

var plugin = config.extensions.tiddlyspace = {
	currentSpace: determineSpace(recipe),
	coreBags: coreBags.concat(systemSpaces),

	determineSpace: determineSpace,
	isValidSpaceName: function(name) {
		return name.match(/^[a-z][0-9a-z\-]*[0-9a-z]$/) ? true : false;
	},
	getCurrentBag: function(type) {
		return "%0_%1".format(currentSpace, type);
	},
	getCurrentWorkspace: function(type) {
		return "bags/" + this.getCurrentBag(type);
	},
	// returns the URL for a space's avatar (SiteIcon) based on a server_host
	// object and an optional space name
	// optional nocors argument prevents cross-domain URLs from being generated
	getAvatar: function(host, space, nocors) {
		if(space && typeof space != "string") { // backwards compatibility -- XXX: deprecated
			space = space.name;
		}
		var subdomain = nocors ? currentSpace : space;
		host = host ? this.getHost(host, subdomain) : "";
		var bag = space ? "%0_public".format(space) : "tiddlyspace";
		return "%0/bags/%1/tiddlers/SiteIcon".format(host, bag);
	},
	// returns the URL based on a server_host object (scheme, host, port) and an
	// optional subdomain
	getHost: function(host, subdomain) {
		if(host === undefined) { // offline
			tweb.status.server_host = {}; // prevents exceptions further down the stack -- XXX: hacky workaround, breaks encapsulation
			return null;
		}
		subdomain = subdomain ? subdomain + "." : "";
		var url = "%0://%1%2".format(host.scheme, subdomain, host.host);
		var port = host.port;
		if(port && !["80", "443"].contains(port)) {
			url += ":" + port;
		}
		return url;
	},
	disableTab: function(tabTiddler) {
		if(typeof(tabTiddler) == "string") {
			disabledTabs.push(tabTiddler);
		} else {
			for(var i = 0; i < tabTiddler.length; i++) {
				plugin.disableTab(tabTiddler[i]);
			}
		}
	},
    checkSyncStatus: function(tiddler) {
		if(tiddler) {
			var title = typeof(tiddler) === "string" ? tiddler : tiddler.title;
			var el = story.getTiddler(title) || false;
			if(el) {
				refreshElements(el);
			}
		}
	},
	isDisabledTab: function(tabTitle) {
		var match = new RegExp("(?:\\[\\[([^\\]]+)\\]\\])", "mg").exec(tabTitle);
		var tabIdentifier = match ? match[1] : tabTitle;
		return disabledTabs.contains(tabIdentifier);
	},
	getCSRFToken: window.getCSRFToken || null // this may not have been processed yet
};

currentSpace = plugin.currentSpace.name;

tweb.serverPrefix = tweb.host.split("/")[3] || ""; // XXX: assumes root handler
tweb.getStatus(function(status) {
	var url = plugin.getHost(status.server_host);
	tweb.status.server_host.url = url;
	config.messages.tsVersion = status.version;
});

if(window.location.protocol == "file:") {
	// enable AutoSave by default
	config.options.chkAutoSave = config.options.chkAutoSave === undefined ?
		true : config.options.chkAutoSave;
} else {
	// set global read-only mode based on membership heuristics
	var indicator = store.getTiddler("SiteTitle") || tiddler;
	readOnly = !(recipe.split("_").pop() == "private" ||
		tweb.hasPermission("write", indicator));
	// replace TiddlyWiki's ImportTiddlers due to cross-domain restrictions
	if(config.macros.fileImport) {
		$.extend(config.macros.importTiddlers, config.macros.fileImport);
	}
}

// hijack saveChanges to ensure SystemSettings is private by default
var _saveChanges = saveChanges;
saveChanges = function(onlyIfDirty, tiddlers) {
	if(tiddlers && tiddlers.length == 1 &&
			tiddlers[0] && tiddlers[0].title == "SystemSettings") {
		var fields = tiddlers[0].fields;
		delete fields["server.recipe"];
		fields["server.bag"] = plugin.getCurrentBag("private");
		fields["server.workspace"] = plugin.getCurrentWorkspace("private");
	}
	return _saveChanges.apply(this, arguments);
};

// ensure backstage is always initialized
// required to circumvent TiddlyWiki's read-only based handling
config.macros.backstageInit = {
	init: function() {
		showBackstage = true;
	}
};

// disable evaluated macro parameters for security reasons
config.evaluateMacroParameters = "none";
var _parseParams = String.prototype.parseParams;
String.prototype.parseParams = function(defaultName, defaultValue, allowEval,
		noNames, cascadeDefaults) {
	if(config.evaluateMacroParameters == "none") {
		arguments[2] = false;
	}
	return _parseParams.apply(this, arguments);
};

var _tabsMacro = config.macros.tabs.handler;
config.macros.tabs.handler = function(place, macroName, params) {
	var newParams = [params[0]]; // keep cookie name
	for(var i = 1; i < params.length; i += 3) {
		var tabTitle = params[i + 2];
		if(!plugin.isDisabledTab(tabTitle)){
			newParams = newParams.concat(params[i], params[i + 1], tabTitle);
		}
	}
	_tabsMacro.apply(this, [place, macroName, newParams]);
};

// disable ControlView for XHRs by default
$.ajaxSetup({
	beforeSend: function(xhr) {
		xhr.setRequestHeader("X-ControlView", "false");
	}
});
// TiddlyWeb adaptor currently still uses httpReq, which needs extra magic -- XXX: obsolete this!
var _httpReq = httpReq;
httpReq = function(type, url, callback, params, headers, data, contentType,
		username, password, allowCache) {
	headers = headers || {};
	headers["X-ControlView"] = "false";
	_httpReq.apply(this, arguments);
};

// register style sheet for backstage separately (important)
store.addNotification("StyleSheetBackstage", refreshStyles);

// option for default privacy setting
config.optionsDesc.chkPrivateMode = "Set your default privacy mode to private";
config.optionsSource.chkPrivateMode = "setting";
config.options.chkPrivateMode = config.options.chkPrivateMode || false;
saveSystemSetting("chkPrivateMode", true);
config.defaultCustomFields["server.workspace"] = plugin.
	getCurrentWorkspace(config.options.chkPrivateMode ? "private" : "public");

config.paramifiers.follow = {
	onstart: function(v) {
		if(!readOnly) {
			var bag = "%0_public".format(currentSpace);
			story.displayTiddler(null, v, DEFAULT_EDIT_TEMPLATE, null, null,
				"server.bag:%0 server.workspace:bags/%0".format(bag));
			story.setTiddlerTag(v, "follow", 1);
			story.focusTiddler(v, "text");
		}
	}
};

var fImport = config.macros.fileImport;
if(fImport) {
	fImport.uploadTo = "Upload to: ";
	var _createForm = config.macros.fileImport.createForm;
	config.macros.fileImport.createForm = function(place, wizard, iframeName) {
		var container = $("<div />").text(fImport.uploadTo).appendTo(place);
		var select = $('<select name="mode" />').appendTo(container)[0];
		$('<option value="private" selected>private</a>').appendTo(select);
		$('<option value="public">public</a>').appendTo(select);
		wizard.setValue("importmode", select);
		_createForm.apply(this, [place, wizard, iframeName]);
	};

	var _onGet = config.macros.importTiddlers.onGetTiddler;
	config.macros.importTiddlers.onGetTiddler = function(context, wizard) {
		var type = $(wizard.getValue("importmode")).val();
		var ws =  plugin.getCurrentWorkspace(type);
		wizard.setValue("workspace", ws);
		_onGet.apply(this, [context, wizard]);
	};
}

config.extensions.ServerSideSavingPlugin.reportSuccess = function(msg, tiddler) {
	plugin.checkSyncStatus(tiddler);
	msg = config.extensions.ServerSideSavingPlugin.locale[msg];
	var link = "/" + encodeURIComponent(tiddler.title);
	displayMessage(msg.format([tiddler.title]), link);
};


})(jQuery);
//}}}
/***
|''Name''|TiddlyWebAdaptor|
|''Description''|adaptor for interacting with TiddlyWeb|
|''Author:''|FND|
|''Contributors''|Chris Dent, Martin Budden|
|''Version''|1.4.10|
|''Status''|stable|
|''Source''|http://svn.tiddlywiki.org/Trunk/association/adaptors/TiddlyWebAdaptor.js|
|''CodeRepository''|http://svn.tiddlywiki.org/Trunk/association/|
|''License''|[[BSD|http://www.opensource.org/licenses/bsd-license.php]]|
|''CoreVersion''|2.5|
|''Keywords''|serverSide TiddlyWeb|
!Notes
This plugin includes [[jQuery JSON|http://code.google.com/p/jquery-json/]].
!To Do
* createWorkspace
* document custom/optional context attributes (e.g. filters, query, revision) and tiddler fields (e.g. server.title, origin)
!Code
***/
//{{{
(function($) {

var adaptor = config.adaptors.tiddlyweb = function() {};

adaptor.prototype = new AdaptorBase();
adaptor.serverType = "tiddlyweb";
adaptor.serverLabel = "TiddlyWeb";
adaptor.mimeType = "application/json";

adaptor.parsingErrorMessage = "Error parsing result from server";
adaptor.noBagErrorMessage = "no bag specified for tiddler";
adaptor.locationIDErrorMessage = "no bag or recipe specified for tiddler"; // TODO: rename

// retrieve current status (requires TiddlyWeb status plugin)
adaptor.prototype.getStatus = function(context, userParams, callback) {
	context = this.setContext(context, userParams, callback);
	var uriTemplate = "%0/status";
	var uri = uriTemplate.format([context.host]);
	var req = httpReq("GET", uri, adaptor.getStatusCallback, context,
		null, null, null, null, null, true);
	return typeof req == "string" ? req : true;
};

adaptor.getStatusCallback = function(status, context, responseText, uri, xhr) {
	context.status = responseText ? status : false;
	try {
		context.statusText = xhr.statusText;
	} catch(exc) { // offline (Firefox)
		context.status = false;
		context.statusText = null;
	}
	context.httpStatus = xhr.status;
	if(context.status) {
		context.serverStatus = $.evalJSON(responseText); // XXX: error handling!?
	}
	if(context.callback) {
		context.callback(context, context.userParams);
	}
};

// retrieve a list of workspaces
adaptor.prototype.getWorkspaceList = function(context, userParams, callback) {
	context = this.setContext(context, userParams, callback);
	context.workspaces = [];
	var uriTemplate = "%0/recipes"; // XXX: bags?
	var uri = uriTemplate.format([context.host]);
	var req = httpReq("GET", uri, adaptor.getWorkspaceListCallback,
		context, { accept: adaptor.mimeType }, null, null, null, null, true);
	return typeof req == "string" ? req : true;
};

adaptor.getWorkspaceListCallback = function(status, context, responseText, uri, xhr) {
	context.status = status;
	context.statusText = xhr.statusText;
	context.httpStatus = xhr.status;
	if(status) {
		try {
			var workspaces = $.evalJSON(responseText);
		} catch(ex) {
			context.status = false; // XXX: correct?
			context.statusText = exceptionText(ex, adaptor.parsingErrorMessage);
			if(context.callback) {
				context.callback(context, context.userParams);
			}
			return;
		}
		context.workspaces = workspaces.map(function(itm) { return { title: itm }; });
	}
	if(context.callback) {
		context.callback(context, context.userParams);
	}
};

// retrieve a list of tiddlers
adaptor.prototype.getTiddlerList = function(context, userParams, callback) {
	context = this.setContext(context, userParams, callback);
	var uriTemplate = "%0/%1/%2/tiddlers%3";
	var params = context.filters ? "?" + context.filters : "";
	if(context.format) {
		params = context.format + params;
	}
	var workspace = adaptor.resolveWorkspace(context.workspace);
	var uri = uriTemplate.format([context.host, workspace.type + "s",
		adaptor.normalizeTitle(workspace.name), params]);
	var req = httpReq("GET", uri, adaptor.getTiddlerListCallback,
		context, merge({ accept: adaptor.mimeType }, context.headers), null, null, null, null, true);
	return typeof req == "string" ? req : true;
};

adaptor.getTiddlerListCallback = function(status, context, responseText, uri, xhr) {
	context.status = status;
	context.statusText = xhr.statusText;
	context.httpStatus = xhr.status;
	if(status) {
		context.tiddlers = [];
		try {
			var tiddlers = $.evalJSON(responseText); //# NB: not actual tiddler instances
		} catch(ex) {
			context.status = false; // XXX: correct?
			context.statusText = exceptionText(ex, adaptor.parsingErrorMessage);
			if(context.callback) {
				context.callback(context, context.userParams);
			}
			return;
		}
		for(var i = 0; i < tiddlers.length; i++) {
			var tiddler = adaptor.toTiddler(tiddlers[i], context.host);
			context.tiddlers.push(tiddler);
		}
	}
	if(context.callback) {
		context.callback(context, context.userParams);
	}
};

// perform global search
adaptor.prototype.getSearchResults = function(context, userParams, callback) {
	context = this.setContext(context, userParams, callback);
	var uriTemplate = "%0/search?q=%1%2";
	var filterString = context.filters ? ";" + context.filters : "";
	var uri = uriTemplate.format([context.host, context.query, filterString]); // XXX: parameters need escaping?
	var req = httpReq("GET", uri, adaptor.getSearchResultsCallback,
		context, { accept: adaptor.mimeType }, null, null, null, null, true);
	return typeof req == "string" ? req : true;
};

adaptor.getSearchResultsCallback = function(status, context, responseText, uri, xhr) {
	adaptor.getTiddlerListCallback(status, context, responseText, uri, xhr); // XXX: use apply?
};

// retrieve a particular tiddler's revisions
adaptor.prototype.getTiddlerRevisionList = function(title, limit, context, userParams, callback) {
	context = this.setContext(context, userParams, callback);
	var uriTemplate = "%0/%1/%2/tiddlers/%3/revisions";
	var workspace = adaptor.resolveWorkspace(context.workspace);
	var uri = uriTemplate.format([context.host, workspace.type + "s",
		adaptor.normalizeTitle(workspace.name), adaptor.normalizeTitle(title)]);
	var req = httpReq("GET", uri, adaptor.getTiddlerRevisionListCallback,
		context, merge({ accept: adaptor.mimeType }, context.headers), null, null, null, null, true);
	return typeof req == "string" ? req : true;
};

adaptor.getTiddlerRevisionListCallback = function(status, context, responseText, uri, xhr) {
	context.status = status;
	context.statusText = xhr.statusText;
	context.httpStatus = xhr.status;
	if(status) {
		context.revisions = [];
		try {
			var tiddlers = $.evalJSON(responseText); //# NB: not actual tiddler instances
		} catch(ex) {
			context.status = false; // XXX: correct?
			context.statusText = exceptionText(ex, adaptor.parsingErrorMessage);
			if(context.callback) {
				context.callback(context, context.userParams);
			}
			return;
		}
		for(var i = 0; i < tiddlers.length; i++) {
			var tiddler = adaptor.toTiddler(tiddlers[i], context.host);
			context.revisions.push(tiddler);
		}
		var sortField = "server.page.revision";
		context.revisions.sort(function(a, b) {
			return a.fields[sortField] < b.fields[sortField] ? 1 :
				(a.fields[sortField] == b.fields[sortField] ? 0 : -1);
		});
	}
	if(context.callback) {
		context.callback(context, context.userParams);
	}
};

// retrieve an individual tiddler revision -- XXX: breaks with standard arguments list -- XXX: convenience function; simply use getTiddler?
adaptor.prototype.getTiddlerRevision = function(title, revision, context, userParams, callback) {
	context = this.setContext(context, userParams, callback);
	context.revision = revision;
	return this.getTiddler(title, context, userParams, callback);
};

// retrieve an individual tiddler
//# context is an object with members host and workspace
//# callback is passed the new context and userParams
adaptor.prototype.getTiddler = function(title, context, userParams, callback) {
	context = this.setContext(context, userParams, callback);
	context.title = title;
	if(context.revision) {
		var uriTemplate = "%0/%1/%2/tiddlers/%3/revisions/%4";
	} else {
		uriTemplate = "%0/%1/%2/tiddlers/%3";
	}
	if(!context.tiddler) {
		context.tiddler = new Tiddler(title);
	}
	context.tiddler.fields["server.type"] = adaptor.serverType;
	context.tiddler.fields["server.host"] = AdaptorBase.minHostName(context.host);
	context.tiddler.fields["server.workspace"] = context.workspace;
	var workspace = adaptor.resolveWorkspace(context.workspace);
	var uri = uriTemplate.format([context.host, workspace.type + "s",
		adaptor.normalizeTitle(workspace.name), adaptor.normalizeTitle(title),
		context.revision]);
	var req = httpReq("GET", uri, adaptor.getTiddlerCallback, context,
		merge({ accept: adaptor.mimeType }, context.headers), null, null, null, null, true);
	return typeof req == "string" ? req : true;
};

adaptor.getTiddlerCallback = function(status, context, responseText, uri, xhr) {
	context.status = status;
	context.statusText = xhr.statusText;
	context.httpStatus = xhr.status;
	if(status) {
		try {
			var tid = $.evalJSON(responseText);
		} catch(ex) {
			context.status = false;
			context.statusText = exceptionText(ex, adaptor.parsingErrorMessage);
			if(context.callback) {
				context.callback(context, context.userParams);
			}
			return;
		}
		var tiddler = adaptor.toTiddler(tid, context.host);
		tiddler.title = context.tiddler.title;
		tiddler.fields["server.etag"] = xhr.getResponseHeader("Etag");
		// normally we'd assign context.tiddler = tiddler here - but we can't do
		// that because of IE, which triggers getTiddler in putTiddlerCallback,
		// and since ServerSideSavingPlugin foolishly relies on persistent
		// object references, we need to merge the data into the existing object
		$.extend(context.tiddler, tiddler);
	}
	if(context.callback) {
		context.callback(context, context.userParams);
	}
};

// retrieve tiddler chronicle (all revisions)
adaptor.prototype.getTiddlerChronicle = function(title, context, userParams, callback) {
	context = this.setContext(context, userParams, callback);
	context.title = title;
	var uriTemplate = "%0/%1/%2/tiddlers/%3/revisions?fat=1";
	var workspace = adaptor.resolveWorkspace(context.workspace);
	var uri = uriTemplate.format([context.host, workspace.type + "s",
		adaptor.normalizeTitle(workspace.name), adaptor.normalizeTitle(title)]);
	var req = httpReq("GET", uri, adaptor.getTiddlerChronicleCallback,
		context, { accept: adaptor.mimeType }, null, null, null, null, true);
	return typeof req == "string" ? req : true;
};

adaptor.getTiddlerChronicleCallback = function(status, context, responseText, uri, xhr) {
	context.status = status;
	context.statusText = xhr.statusText;
	context.httpStatus = xhr.status;
	if(status) {
		context.responseText = responseText;
	}
	if(context.callback) {
		context.callback(context, context.userParams);
	}
};

// store an individual tiddler
adaptor.prototype.putTiddler = function(tiddler, context, userParams, callback) {
	context = this.setContext(context, userParams, callback);
	context.title = tiddler.title;
	context.tiddler = tiddler;
	context.host = context.host || this.fullHostName(tiddler.fields["server.host"]);
	var uriTemplate = "%0/%1/%2/tiddlers/%3";
	try {
		context.workspace = context.workspace || tiddler.fields["server.workspace"];
		var workspace = adaptor.resolveWorkspace(context.workspace);
	} catch(ex) {
		return adaptor.locationIDErrorMessage;
	}
	var uri = uriTemplate.format([context.host, workspace.type + "s",
		adaptor.normalizeTitle(workspace.name),
		adaptor.normalizeTitle(tiddler.title)]);
	var etag = adaptor.generateETag(workspace, tiddler);
	var headers = etag ? { "If-Match": etag } : null;
	var payload = {
		type: tiddler.fields["server.content-type"] || null,
		text: tiddler.text,
		tags: tiddler.tags,
		fields: $.extend({}, tiddler.fields)
	};
	delete payload.fields.changecount;
	$.each(payload.fields, function(key, value) {
		if(key.indexOf("server.") == 0) {
			delete payload.fields[key];
		}
	});
	payload = $.toJSON(payload);
	var req = httpReq("PUT", uri, adaptor.putTiddlerCallback,
		context, headers, payload, adaptor.mimeType, null, null, true);
	return typeof req == "string" ? req : true;
};

adaptor.putTiddlerCallback = function(status, context, responseText, uri, xhr) {
	context.status = [204, 1223].contains(xhr.status);
	context.statusText = xhr.statusText;
	context.httpStatus = xhr.status;
	if(context.status) {
		var loc = xhr.getResponseHeader("Location");
		var etag = xhr.getResponseHeader("Etag");
		if(loc && etag) {
			var bag = loc.split("/bags/").pop().split("/")[0];
			context.tiddler.fields["server.bag"] = bag;
			context.tiddler.fields["server.workspace"] = "bags/" + bag;
			var rev = etag.split("/").pop().split(/;|:/)[0];
			context.tiddler.fields["server.page.revision"] = rev;
			context.tiddler.fields["server.etag"] = etag;
			if(context.callback) {
				context.callback(context, context.userParams);
			}
		} else { // IE
			context.adaptor.getTiddler(context.tiddler.title, context,
				context.userParams, context.callback);
		}
	} else if(context.callback) {
		context.callback(context, context.userParams);
	}
};

// store a tiddler chronicle
adaptor.prototype.putTiddlerChronicle = function(revisions, context, userParams, callback) {
	context = this.setContext(context, userParams, callback);
	context.title = revisions[0].title;
	var headers = null;
	var uriTemplate = "%0/%1/%2/tiddlers/%3/revisions";
	var host = context.host || this.fullHostName(tiddler.fields["server.host"]);
	var workspace = adaptor.resolveWorkspace(context.workspace);
	var uri = uriTemplate.format([host, workspace.type + "s",
		adaptor.normalizeTitle(workspace.name),
		adaptor.normalizeTitle(context.title)]);
	if(workspace.type == "bag") { // generate ETag
		var etag = [adaptor.normalizeTitle(workspace.name),
			adaptor.normalizeTitle(context.title), 0].join("/"); //# zero-revision prevents overwriting existing contents
		headers = { "If-Match": '"' + etag + '"' };
	}
	var payload = $.toJSON(revisions);
	var req = httpReq("POST", uri, adaptor.putTiddlerChronicleCallback,
		context, headers, payload, adaptor.mimeType, null, null, true);
	return typeof req == "string" ? req : true;
};

adaptor.putTiddlerChronicleCallback = function(status, context, responseText, uri, xhr) {
	context.status = [204, 1223].contains(xhr.status);
	context.statusText = xhr.statusText;
	context.httpStatus = xhr.status;
	if(context.callback) {
		context.callback(context, context.userParams);
	}
};

// store a collection of tiddlers (import TiddlyWiki HTML store)
adaptor.prototype.putTiddlerStore = function(store, context, userParams, callback) {
	context = this.setContext(context, userParams, callback);
	var uriTemplate = "%0/%1/%2/tiddlers";
	var host = context.host;
	var workspace = adaptor.resolveWorkspace(context.workspace);
	var uri = uriTemplate.format([host, workspace.type + "s",
		adaptor.normalizeTitle(workspace.name)]);
	var req = httpReq("POST", uri, adaptor.putTiddlerStoreCallback,
		context, null, store, "text/x-tiddlywiki", null, null, true);
	return typeof req == "string" ? req : true;
};

adaptor.putTiddlerStoreCallback = function(status, context, responseText, uri, xhr) {
	context.status = [204, 1223].contains(xhr.status);
	context.statusText = xhr.statusText;
	context.httpStatus = xhr.status;
	if(context.callback) {
		context.callback(context, context.userParams);
	}
};

// rename an individual tiddler or move it to a different workspace -- TODO: make {from|to}.title optional
//# from and to are objects with members title and workspace (bag; optional),
//# representing source and target tiddler, respectively
adaptor.prototype.moveTiddler = function(from, to, context, userParams, callback) { // XXX: rename parameters (old/new)?
	var self = this;
	var newTiddler = store.getTiddler(from.title) || store.getTiddler(to.title); //# local rename might already have occurred
	var oldTiddler = $.extend(true, {}, newTiddler); //# required for eventual deletion
	oldTiddler.title = from.title; //# required for original tiddler's ETag
	var _getTiddlerChronicle = function(title, context, userParams, callback) {
		return self.getTiddlerChronicle(title, context, userParams, callback);
	};
	var _putTiddlerChronicle = function(context, userParams) {
		if(!context.status) {
			return callback(context, userParams);
		}
		var revisions = $.evalJSON(context.responseText); // XXX: error handling?
		// change current title while retaining previous location
		for(var i = 0; i < revisions.length; i++) {
			delete revisions[i].revision;
			if(!revisions[i].fields.origin) { // NB: origin = "<workspace>/<title>"
				revisions[i].fields.origin = ["bags", revisions[i].bag, revisions[i].title].join("/");
			}
			revisions[i].title = to.title;
		}
		// add new revision
		var rev = $.extend({}, revisions[0]);
		$.each(newTiddler, function(i, item) {
			if(!$.isFunction(item)) {
				rev[i] = item;
			}
		});
		rev.title = to.title;
		rev.created = rev.created.convertToYYYYMMDDHHMM();
		rev.modified = new Date().convertToYYYYMMDDHHMM();
		delete rev.fields.changecount;
		revisions.unshift(rev);
		if(to.workspace) {
			context.workspace = to.workspace;
		} else if(context.workspace.substring(0, 4) != "bags") { // NB: target workspace must be a bag
			context.workspace = "bags/" + rev.bag;
		}
		var subCallback = function(context, userParams) {
			if(!context.status) {
				return callback(context, userParams);
			}
			context.adaptor.getTiddler(newTiddler.title, context, userParams, _deleteTiddler);
		};
		return self.putTiddlerChronicle(revisions, context, context.userParams, subCallback);
	};
	var _deleteTiddler = function(context, userParams) {
		if(!context.status) {
			return callback(context, userParams);
		}
		$.extend(true, newTiddler, context.tiddler);
		context.callback = null;
		return self.deleteTiddler(oldTiddler, context, context.userParams, callback);
	};
	callback = callback || function() {};
	context = this.setContext(context, userParams);
	context.host = context.host || oldTiddler.fields["server.host"];
	context.workspace = from.workspace || oldTiddler.fields["server.workspace"];
	return _getTiddlerChronicle(from.title, context, userParams, _putTiddlerChronicle);
};

// delete an individual tiddler
adaptor.prototype.deleteTiddler = function(tiddler, context, userParams, callback) {
	context = this.setContext(context, userParams, callback);
	context.title = tiddler.title; // XXX: not required!?
	var uriTemplate = "%0/bags/%1/tiddlers/%2";
	var host = context.host || this.fullHostName(tiddler.fields["server.host"]);
	var bag = tiddler.fields["server.bag"];
	if(!bag) {
		return adaptor.noBagErrorMessage;
	}
	var uri = uriTemplate.format([host, adaptor.normalizeTitle(bag),
		adaptor.normalizeTitle(tiddler.title)]);
	var etag = adaptor.generateETag({ type: "bag", name: bag }, tiddler);
	var headers = etag ? { "If-Match": etag } : null;
	var req = httpReq("DELETE", uri, adaptor.deleteTiddlerCallback, context, headers,
		null, null, null, null, true);
	return typeof req == "string" ? req : true;
};

adaptor.deleteTiddlerCallback = function(status, context, responseText, uri, xhr) {
	context.status = [204, 1223].contains(xhr.status);
	context.statusText = xhr.statusText;
	context.httpStatus = xhr.status;
	if(context.callback) {
		context.callback(context, context.userParams);
	}
};

// compare two revisions of a tiddler (requires TiddlyWeb differ plugin)
//# if context.rev1 is not specified, the latest revision will be used for comparison
//# if context.rev2 is not specified, the local revision will be sent for comparison
//# context.format is a string as determined by the TiddlyWeb differ plugin
adaptor.prototype.getTiddlerDiff = function(title, context, userParams, callback) {
	context = this.setContext(context, userParams, callback);
	context.title = title;

	var tiddler = store.getTiddler(title);
	try {
		var workspace = adaptor.resolveWorkspace(tiddler.fields["server.workspace"]);
	} catch(ex) {
		return adaptor.locationIDErrorMessage;
	}
	var tiddlerRef = [workspace.type + "s", workspace.name, tiddler.title].join("/");

	var rev1 = context.rev1 ? [tiddlerRef, context.rev1].join("/") : tiddlerRef;
	var rev2 = context.rev2 ? [tiddlerRef, context.rev2].join("/") : null;

	var uriTemplate = "%0/diff?rev1=%1";
	if(rev2) {
		uriTemplate += "&rev2=%2";
	}
	if(context.format) {
		uriTemplate += "&format=%3";
	}
	var host = context.host || this.fullHostName(tiddler.fields["server.host"]);
	var uri = uriTemplate.format([host, adaptor.normalizeTitle(rev1),
		adaptor.normalizeTitle(rev2), context.format]);

	if(rev2) {
		var req = httpReq("GET", uri, adaptor.getTiddlerDiffCallback, context, null,
			null, null, null, null, true);
	} else {
		var payload = {
			title: tiddler.title,
			text: tiddler.text,
			modifier: tiddler.modifier,
			tags: tiddler.tags,
			fields: $.extend({}, tiddler.fields)
		}; // XXX: missing attributes!?
		payload = $.toJSON(payload);
		req = httpReq("POST", uri, adaptor.getTiddlerDiffCallback, context,
			null, payload, adaptor.mimeType, null, null, true);
	}
	return typeof req == "string" ? req : true;
};

adaptor.getTiddlerDiffCallback = function(status, context, responseText, uri, xhr) {
	context.status = status;
	context.statusText = xhr.statusText;
	context.httpStatus = xhr.status;
	context.uri = uri;
	if(status) {
		context.diff = responseText;
	}
	if(context.callback) {
		context.callback(context, context.userParams);
	}
};

// generate tiddler information
adaptor.prototype.generateTiddlerInfo = function(tiddler) {
	var info = {};
	var uriTemplate = "%0/%1/%2/tiddlers/%3";
	var host = this.host || tiddler.fields["server.host"]; // XXX: this.host obsolete?
	host = this.fullHostName(host);
	var workspace = adaptor.resolveWorkspace(tiddler.fields["server.workspace"]);
	info.uri = uriTemplate.format([host, workspace.type + "s",
		adaptor.normalizeTitle(workspace.name),
		adaptor.normalizeTitle(tiddler.title)]);
	return info;
};

// create Tiddler instance from TiddlyWeb tiddler JSON
adaptor.toTiddler = function(json, host) {
	var created = Date.convertFromYYYYMMDDHHMM(json.created);
	var modified = Date.convertFromYYYYMMDDHHMM(json.modified);
	var fields = json.fields;
	fields["server.type"] = adaptor.serverType;
	fields["server.host"] = AdaptorBase.minHostName(host);
	fields["server.bag"] = json.bag;
	fields["server.title"] = json.title;
	if(json.recipe) {
		fields["server.recipe"] = json.recipe;
	}
	if(json.type && json.type != "None") {
		fields["server.content-type"] = json.type;
	}
	fields["server.permissions"] = json.permissions.join(", ");
	fields["server.page.revision"] = json.revision;
	fields["server.workspace"] = "bags/" + json.bag;
	var tiddler = new Tiddler(json.title);
	tiddler.assign(tiddler.title, json.text, json.modifier, modified, json.tags,
		created, json.fields, json.creator);
	return tiddler;
};

adaptor.resolveWorkspace = function(workspace) {
	var components = workspace.split("/");
	return {
		type: components[0] == "bags" ? "bag" : "recipe",
		name: components[1] || components[0]
	};
};

adaptor.generateETag = function(workspace, tiddler) {
	var revision = tiddler.fields["server.page.revision"];
	var etag = revision == "false" ? null : tiddler.fields["server.etag"];
	if(!etag && workspace.type == "bag") {
		if(typeof revision == "undefined") {
			revision = "0";
		} else if(revision == "false") {
			return null;
		}
		etag = [adaptor.normalizeTitle(workspace.name),
			adaptor.normalizeTitle(tiddler.title), revision].join("/");
		etag = '"' + etag + '"';
	}
	return etag;
};

adaptor.normalizeTitle = function(title) {
	return encodeURIComponent(title);
};

})(jQuery);


/*
 * jQuery JSON Plugin
 * version: 1.3
 * source: http://code.google.com/p/jquery-json/
 * license: MIT (http://www.opensource.org/licenses/mit-license.php)
 */
(function($){function toIntegersAtLease(n)
{return n<10?'0'+n:n;}
Date.prototype.toJSON=function(date)
{return this.getUTCFullYear()+'-'+
toIntegersAtLease(this.getUTCMonth())+'-'+
toIntegersAtLease(this.getUTCDate());};var escapeable=/["\\\x00-\x1f\x7f-\x9f]/g;var meta={'\b':'\\b','\t':'\\t','\n':'\\n','\f':'\\f','\r':'\\r','"':'\\"','\\':'\\\\'};$.quoteString=function(string)
{if(escapeable.test(string))
{return'"'+string.replace(escapeable,function(a)
{var c=meta[a];if(typeof c==='string'){return c;}
c=a.charCodeAt();return'\\u00'+Math.floor(c/16).toString(16)+(c%16).toString(16);})+'"';}
return'"'+string+'"';};$.toJSON=function(o,compact)
{var type=typeof(o);if(type=="undefined")
return"undefined";else if(type=="number"||type=="boolean")
return o+"";else if(o===null)
return"null";if(type=="string")
{return $.quoteString(o);}
if(type=="object"&&typeof o.toJSON=="function")
return o.toJSON(compact);if(type!="function"&&typeof(o.length)=="number")
{var ret=[];for(var i=0;i<o.length;i++){ret.push($.toJSON(o[i],compact));}
if(compact)
return"["+ret.join(",")+"]";else
return"["+ret.join(", ")+"]";}
if(type=="function"){throw new TypeError("Unable to convert object of type 'function' to json.");}
var ret=[];for(var k in o){var name;type=typeof(k);if(type=="number")
name='"'+k+'"';else if(type=="string")
name=$.quoteString(k);else
continue;var val=$.toJSON(o[k],compact);if(typeof(val)!="string"){continue;}
if(compact)
ret.push(name+":"+val);else
ret.push(name+": "+val);}
return"{"+ret.join(", ")+"}";};$.compactJSON=function(o)
{return $.toJSON(o,true);};$.evalJSON=function(src)
{return eval("("+src+")");};$.secureEvalJSON=function(src)
{var filtered=src;filtered=filtered.replace(/\\["\\\/bfnrtu]/g,'@');filtered=filtered.replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,']');filtered=filtered.replace(/(?:^|:|,)(?:\s*\[)+/g,'');if(/^[\],:{}\s]*$/.test(filtered))
return eval("("+src+")");else
throw new SyntaxError("Error parsing JSON, source is not valid.");};})(jQuery);
//}}}
R0lGODlhWwAkAPf7AAAAAAgICBAQEBgQEBgQGCEYMSEpISEpMSkYISkpITEhMTEpKTEpMTEpOTEpSjExQjFSUjkhITkpMTkxOTkxSjk5Yzlac0IpIUIxMUI5KUJCUkJKa0JSY0JaY0JahEoxIUo5MUo5OUpCIUpjhEpjjEprc0pznFJCMVJCQlJSWlJSa1JaY1Jaa1JjWloxKVo5MVo5QlpCQlpCUlpCY1qEpVqMrWNKQmNKY2NSa2Naa2Nae2Nrc2NrhGN7jGsxOWs5OWtSKWtSOWtSQmtaSmtjOWuMe2uMhGuMnGuUrXM5UnNCWnNKa3NSc3NaWnNae3NjKXNrSnNze3N7jHtKUntjhHtrY3t7lHuEnHulvYRCOYRaWoRac4RjWoRje4Rra4RrjIR7Y4R7jIR7lISMa4SMjISMnISUpYxjQox7Qox7e4yMOYyMUoyMe4ylrZRzc5R7Y5R7lJSEe5SMnJSUa5xzc5yEe5yElJyMe5yUjJycnJycpaVKY6V7UqWEjKWUY6WcjKWle61zc62Ee62MSq2lY7WcnLWtrbW1pb21rb3GtcalSsalnMa1a861StaEjNbGWtbGa9bOe97Wa97We/fnSvfve////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////wAAAL8AAAC/AL+/AAAAv78AvwC/v8DAwICAgP8AAAD/AP//AAAA//8A/wD//////wAAAAAAAAAAAAAAACH5BAEAAPsALAAAAABbACQABwj8APcJHEiwoMGDCAtSyLFjB5MqKxJKnEixosWEKnhQoSJGTh49cEKKgSNGTI4UOyhcXMmyZUEYcOyIlMJDhw4VOHI6ofLlCxw9UVwKHYrwQh89Yr5IkULFiRObOnKqUDEhQAAC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
PERT - Program (or Project) Evaluation and Review Technique
//PERT is a method to analyze the involved tasks in completing a given project, especially the time needed to complete each task, and to identify the minimum time needed to complete the total project.

PERT was developed primarily to simplify the planning and scheduling of large and complex projects. It was developed for the U.S. Navy Special Projects Office in 1957 to support the U.S. Navy's Polaris nuclear submarine project. It was able to incorporate uncertainty by making it possible to schedule a project while not knowing precisely the details and durations of all the activities.
(...)
Through an electronic computer, the PERT technique processes data representing the major, finite accomplishments (events) essential to achieve end-objectives; the inter-dependence of those events; and estimates of time and range of time necessary to complete each activity between two successive events. Such time expectations include estimates of ''"most likely time"'', ''"optimistic time"'', and ''"pessimistic time"'' for each activity.
//
From [[Wikipedia|http://en.wikipedia.org/wiki/Program_Evaluation_and_Review_Technique]]
----
/%
@@color:#c4d6ed; ^^
Description: Program (or Project) Evaluation and Review Technique
^^@@
%/
Software Architecture Specification
----
@@color:#c4d6ed; ^^
Description: Software Architecture Specification
^^@@
//Like [[abstraction|Abstraction]], the word "encapsulation" can be used to describe either a process or an entity. As a process, encapsulation means the act of enclosing one or more items within a (physical or logical) container. Encapsulation, as an entity, refers to a package or an enclosure that holds (contains, encloses) one or more items. It is extremely important to note that nothing is said about "the walls of the enclosure." Specifically, they may be "transparent," "translucent," or even "opaque." //

* Edward V. Berard - Abstraction, Encapsulation and Information Hiding	[[[Berard]|BibliographyPage##Berard]]
----
@@color:#c4d6ed; ^^
Description: Encapsulation concept and references.
^^@@
/***
|Name|TagCloudPlugin|
|Source|http://www.TiddlyTools.com/#TagCloudPlugin|
|Version|1.7.0|
|Author|Eric Shulman|
|Original Author|Clint Checketts|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|present a 'cloud' of tags (or links) using proportional font display|
!Usage
<<<
{{{
<<cloud type action:... limit:... tag tag tag ...>>
<<cloud type action:... limit:... +TiddlerName>>
<<cloud type action:... limit:... -TiddlerName>>
<<cloud type action:... limit:... =tagvalue>>
}}}
where:
* //type// is a keyword, one of:
** ''tags'' (default) - displays a cloud of tags, based on frequency of use
** ''links'' - displays a cloud of tiddlers, based on number of links //from// each tiddler
** ''references'' - displays a cloud of tiddlers, based on number of links //to// each tiddler
* ''action:popup'' (default) - clicking a cloud item shows a popup with links to related tiddlers<br>//or//<br> ''action:goto'' - clicking a cloud item immediately opens the tiddler corresponding to that item
* ''limit:N'' (optional) - restricts the cloud display to only show the N most popular tags/links
* ''tag tag tag...'' (or ''title title title'' if ''links''/''references'' is used)<br>shows all tags/links in the document //except// for those listed as macro parameters
* ''+TiddlerName''<br>show only tags/links read from a space-separated, bracketed list stored in a separate tiddler.
* ''-TiddlerName''<br>show all tags/links //except// those read from a space-separated, bracketed list stored in a separate tiddler.
* ''=tagvalue'' (//only if type=''tags''//)<br>shows only tags that are themselves tagged with the indicated tag value (i.e., ~TagglyTagging usage)
//note: for backward-compatibility, you can also use the macro {{{<<tagCloud ...>>}}} in place of {{{<<cloud ...>>}}}//
<<<
!Examples
<<<
//all tags excluding<<tag systemConfig>>, <<tag excludeMissing>> and <<tag script>>//
{{{<<cloud systemConfig excludeMissing script>>}}}
{{groupbox{<<cloud systemConfig excludeMissing script>>}}}
//top 10 tags excluding<<tag systemConfig>>, <<tag excludeMissing>> and <<tag script>>//
{{{<<cloud limit:10 systemConfig excludeMissing script>>}}}
{{groupbox{<<cloud limit:10 systemConfig excludeMissing script>>}}}
//tags listed in// [[FavoriteTags]]
{{{<<cloud +FavoriteTags>>}}}
{{groupbox{<<cloud +FavoriteTags>>}}}
//tags NOT listed in// [[FavoriteTags]]
{{{<<cloud -FavoriteTags>>}}}
{{groupbox{<<cloud -FavoriteTags>>}}}
//links to tiddlers tagged with 'package'//
{{{<<cloud action:goto =package>>}}}
{{groupbox{<<cloud action:goto =package>>}}}
//top 20 most referenced tiddlers//
{{{<<cloud references limit:20>>}}}
{{groupbox{<<cloud references limit:20>>}}}
//top 20 tiddlers that contain the most links//
{{{<<cloud links limit:20>>}}}
{{groupbox{<<cloud links limit:20>>}}}
<<<
!Revisions
<<<
2009.07.17 [1.7.0] added {{{-TiddlerName}}} parameter to exclude tags that are listed in the indicated tiddler
2009.02.26 [1.6.0] added {{{action:...}}} parameter to apply popup vs. goto action when clicking cloud items
2009.02.05 [1.5.0] added ability to show links or back-links (references) instead of tags and renamed macro to {{{<<cloud>>}}} to reflect more generalized usage.
2008.12.16 [1.4.2] corrected group calculation to prevent 'group=0' error
2008.12.16 [1.4.1] revised tag filtering so excluded tags don't affect calculations
2008.12.15 [1.4.0] added {{{limit:...}}} parameter to restrict the number of tags displayed to the top N most popular
2008.11.15 [1.3.0] added {{{+TiddlerName}}} parameter to include only tags that are listed in the indicated tiddler
2008.09.05 [1.2.0] added '=tagname' parameter to include only tags that are themselves tagged with the specified value (i.e., ~TagglyTagging usage)
2008.07.03 [1.1.0] added 'segments' property to macro object.  Extensive code cleanup
<<<
!Code
***/
//{{{
version.extensions.TagCloudPlugin= {major: 1, minor: 7 , revision: 0, date: new Date(2009,7,17)};
//Originally created by Clint Checketts, contributions by Jonny Leroy and Eric Shulman
//Currently maintained and enhanced by Eric Shulman
//}}}
//{{{
config.macros.cloud = {
	tagstip: "%1 tiddlers tagged with '%0'",
	refslabel: " (%0 references)",
	refstip: "%1 tiddlers have links to '%0'",
	linkslabel: " (%0 links)",
	linkstip: "'%0' has links to %1 other tiddlers",
	groups: 9,
	init: function() {
		config.macros.tagCloud=config.macros.cloud; // for backward-compatibility
		config.shadowTiddlers.TagCloud='<<cloud>>';
		config.shadowTiddlers.StyleSheetTagCloud=
			'/*{{{*/\n'
			+'.tagCloud span {line-height: 3.5em; margin:3px;}\n'
			+'.tagCloud1{font-size: 80%;}\n'
			+'.tagCloud2{font-size: 100%;}\n'
			+'.tagCloud3{font-size: 120%;}\n'
			+'.tagCloud4{font-size: 140%;}\n'
			+'.tagCloud5{font-size: 160%;}\n'
			+'.tagCloud6{font-size: 180%;}\n'
			+'.tagCloud7{font-size: 200%;}\n'
			+'.tagCloud8{font-size: 220%;}\n'
			+'.tagCloud9{font-size: 240%;}\n'
			+'/*}}}*/\n';
		setStylesheet(store.getTiddlerText('StyleSheetTagCloud'),'tagCloudsStyles');
	},
	getLinks: function(tiddler) { // get list of links to existing tiddlers and shadows
		if (!tiddler.linksUpdated) tiddler.changed();
		var list=[]; for (var i=0; i<tiddler.links.length; i++) {
			var title=tiddler.links[i];
			if (store.isShadowTiddler(title)||store.tiddlerExists(title))
				list.push(title);
		}
		return list;
	},
	handler: function(place,macroName,params) {
		// unpack params
		var inc=[]; var ex=[]; var limit=0; var action='popup';
		var links=(params[0]&&params[0].toLowerCase()=='links'); if (links) params.shift();
		var refs=(params[0]&&params[0].toLowerCase()=='references'); if (refs) params.shift();
		if (params[0]&&params[0].substr(0,7).toLowerCase()=='action:')
			action=params.shift().substr(7).toLowerCase();
		if (params[0]&&params[0].substr(0,6).toLowerCase()=='limit:')
			limit=parseInt(params.shift().substr(6));
		while (params.length) {
			if (params[0].substr(0,1)=='+') { // read taglist from tiddler
				inc=inc.concat(store.getTiddlerText(params[0].substr(1),'').readBracketedList());
			} else if (params[0].substr(0,1)=='-') { // exclude taglist from tiddler
				ex=ex.concat(store.getTiddlerText(params[0].substr(1),'').readBracketedList());
			} else if (params[0].substr(0,1)=='=') { // get tag list using tagged tags
				var tagged=store.getTaggedTiddlers(params[0].substr(1));
				for (var t=0; t<tagged.length; t++) inc.push(tagged[t].title);
			} else ex.push(params[0]); // exclude params
			params.shift();
		}
		// get all items, include/exclude specific items
		var items=[];
		var list=(links||refs)?store.getTiddlers('title','excludeLists'):store.getTags();
		for (var t=0; t<list.length; t++) {
			var title=(links||refs)?list[t].title:list[t][0];
			if (links)	var count=this.getLinks(list[t]).length;
			else if (refs)	var count=store.getReferringTiddlers(title).length;
			else 		var count=list[t][1];
			if ((!inc.length||inc.contains(title))&&(!ex.length||!ex.contains(title)))
				items.push({ title:title, count:count });
		}
		if(!items.length) return;
		// sort by decending count, limit results (optional)
		items=items.sort(function(a,b){return(a.count==b.count)?0:(a.count>b.count?-1:1);});
		while (limit && items.length>limit) items.pop();
		// find min/max and group size
		var most=items[0].count;
		var least=items[items.length-1].count;
		var groupSize=(most-least+1)/this.groups;
		// sort by title and draw the cloud of items
		items=items.sort(function(a,b){return(a.title==b.title)?0:(a.title>b.title?1:-1);});
		var cloudWrapper = createTiddlyElement(place,'div',null,'tagCloud',null);
		for (var t=0; t<items.length; t++) {
			cloudWrapper.appendChild(document.createTextNode(' '));
			var group=Math.ceil((items[t].count-least)/groupSize)||1;
			var className='tagCloudtag tagCloud'+group;
			var tip=refs?this.refstip:links?this.linkstip:this.tagstip;
			tip=tip.format([items[t].title,items[t].count]);
			if (action=='goto') { // TAG/LINK/REFERENCES GOTO
				var btn=createTiddlyLink(cloudWrapper,items[t].title,true,className);
				btn.title=tip;
				btn.style.fontWeight='normal';
			} else if (!links&&!refs) { // TAG POPUP
				var btn=createTiddlyButton(cloudWrapper,items[t].title,tip,onClickTag,className);
				btn.setAttribute('tag',items[t].title);
			} else { // LINK/REFERENCES POPUP
				var btn=createTiddlyButton(cloudWrapper,items[t].title,tip,
					function(ev) { var e=ev||window.event; var cmt=config.macros.cloud;
						var popup = Popup.create(this);
						var title = this.getAttribute('tiddler');
						var count = this.getAttribute('count');
						var refs  = this.getAttribute('refs')=='T';
						var links = this.getAttribute('links')=='T';
						var label = (refs?cmt.refslabel:cmt.linkslabel).format([count]);
						createTiddlyLink(popup,title,true);
						createTiddlyText(popup,label);
						createTiddlyElement(popup,'hr');
						if (refs) {
							popup.setAttribute('tiddler',title);
							config.commands.references.handlePopup(popup,title);
						}
						if (links) {
							var tiddler = store.fetchTiddler(title);
							var links=config.macros.cloud.getLinks(tiddler);
							for(var i=0;i<links.length;i++)
								createTiddlyLink(createTiddlyElement(popup,'li'),
									links[i],true);
						}
						Popup.show();
						e.cancelBubble=true; if(e.stopPropagation) e.stopPropagation();
						return false;
					}, className);
				btn.setAttribute('tiddler',items[t].title);
				btn.setAttribute('count',items[t].count);
				btn.setAttribute('refs',refs?'T':'F');
				btn.setAttribute('links',links?'T':'F');
				btn.title=tip;
			}
		}
	}
};
//}}}
ColorPalette
StyleSheet
SiteSubtitle
GettingStarted
SiteTitle
MainMenu
SiteIcon
DefaultTiddlers
ViewTemplate
PageTemplate
SideBarOptions
EditTemplate
SiteInfo
SideBarTabs
ToolbarCommands
!First things first

// __''@@color(red):If you do not know or understand the problem how can you expect to give it a solution?@@''__//

From the perspective of a software development company, the initial phase of a software project is the ''Inception'' and comprises Pre-sales, Request for Proposal (or Statement of Work) Analysis and Technical Proposal Production.
<<Image "FR" "" "RUP-Inception.PNG" "https://dl.dropbox.com/" "s/diywxcpbvpp0f3d/" "?dl=1" "This is the RUP vision of the Development Process.">>

One important aspect to notice is that many high maturity software development companies do not include the Inception phase on their Software Development Processes ( [[SDP]] ) but start them at Software Requirements Specification. This might be explained by the fact that such [[SDP]]s were developed taking into consideration very formal and mature scenarios, like aero-space, where this phase is fully performed by the Customer and to an high maturity level. The problem is that, in "less critical" scenarios, this crucial phase is detached from the development process and its results may not be the best to properly feed it. In these scenarios you risk to engage in a "garbage in, garbage out" spiral if proper measures are not taken.

We are not "process and formalism fanatics", and are aware of agility needs on nowadays development, but experience has taught us that "//''you may build a bad solution over a good specification but you will never build a good solution over a bad specification''//". To engage in a legally bounding contract, like the Proposal, that is ambiguous, superficial, incomplete and poorly estimated is, at least, childish and is, for sure, to ask for trouble.

The role of business and software analyst is more and more important nowadays to the success of any software project. This as been acknowledged by top thinkers in the domain from quite some time now.
<<quote 'Frederick P. Brooks on analysis relevance' 'Frederick P. Brooks on analysis relevance'>>
<<quote 'Tom DeMarco on the Software Analyst role' 'Tom DeMarco on the Software Analyst role'>>

!!Pre-sales
''Pre-sales'' is a very important step in a project and encompasses all the initial steps of a (would be) software project. Identification of the business needs is initiated at this stage, see <<BibRef "BABOK 2008">> //Chapter 4: Enterprise Analysis//.
At this stage a lot of information is produced and vision starts to be established. This is, typically, a Customer internal phase, but, often, involves some participation of the software development partners. The important note here is that software development personnel involved preserve information and do not "close doors" by jumping to superficial restrictive solutions before more detailed information is gathered and organized. These "initial" solutions often, artificially (because they do not correspond to Customer needs nor they are solid technical choices), create technical and architectural "requirements" that may impair the pursue of the "best possible" software solution later.
The paradigmatic example is "//it must be a web browser application//" when an automated deployment, n-tier [[ClickOnce|http://msdn.microsoft.com/en-us/library/t71a733d%28v=vs.100%29.aspx]] application would do the job much better for the Customer.

!!Request for Proposal Analysis
Imagine a "not so good scenario".
Pre-sales information will be, mostly, "talk", maybe a ~PowerPoint if you are lucky. [[RFP]], if you have one, will have lots of requirements but they will not be [[SMART|SMART Requirements]] and will be spread all along a one hundred pages document.

As with any other problem analysis you should consider [[Rene Descartes' |http://www.marxists.org/reference/archive/descartes/1635/discourse-method.htm]] second principle "//''The second, to divide each of the difficulties under examination into as many parts as possible, and as might be necessary for its adequate solution.''//" and not forget the fourth "//''And the last, in every case to make enumerations so complete, and reviews so general, that I might be assured that nothing was omitted.''//"

You need tools! You need to break down, normalize, make specific, structure and [[trace|Traceability]] __ALL__ the Customer requirements. You also need to understand the business needs and the goals of the requested solution. You need to identify the data flows and the integration environment and to understand the business processes. You need tools, a check list and method, that's what will make you [[agile|Agile Methodologies]] and no, the proper tool is not MS Word nor even MS Excel.

<<Image "FR" "" "RFP-Analysis-Structure.PNG" "https://dl.dropbox.com/" "s/dwefsm068yfz2w0/" "?dl=1" "RFP Analysis Structure">>
[[RFP]]s came in a variety of formats and structures, your first consideration shall be how to make the information [[traceable|Traceability]] and not redundant. How? Using a relational database, you are talking about Software Engineering aren't you? The first task is, then, to input all the information in a software tool with a known structure that works as a completeness check list, a normalization structure and a road map for analysis. [[Sparx Enterprise Architect]] is a very good tool. But don't forget "''known structure''", that is, you will not take the full potential if you do not have a known, tested and proved structure template.

The image on the right gives an idea of what that structure can be in [[EA|Sparx Enterprise Architect]].
Details about it can be seen at [[RFP Analysis Guidelines]].

Notice that this is a fall-back approach, that is, what you can not get from RFP you must produce on Technical Proposal, what you can't produce on Technical Proposal you will have to do on Requirements Specification and so on. The later you do it the greater the risk...

!!Technical Proposal Production
<<Image "FR" "" "Technical-Proposal-Structure.PNG" "https://dl.dropbox.com/" "s/1ao4mpykaidyynt/" "?dl=1" "Technical Proposal Structure">>
If you structured and normalized the Customer request you have gain a lot of insight on his needs and goals. Also very important you have established the basis for a true [[traceability|Traceability]]. You will see this is essential to keep focus and scope and to assure coverage.
Now it is time to propose him a solution that is solid, competitive and adequate.

Again you shall use a known structure if you want to take all the tool potential.
The image on the right gives an idea of what that structure can be in [[EA|Sparx Enterprise Architect]].
Details about it can be seen at [[Technical Proposal Production Guidelines]].


----
See also [[Development Links|Development Links##BusinessAnalysis]]
Back to [[Software Development Pattern]]
----
/***
|Name|BreadcrumbsPluginInfo|
|Author|Eric Shulman|
|Source|http://www.TiddlyTools.com/#BreadcrumbsPlugin|
|Documentation|http://www.TiddlyTools.com/#BreadcrumbsPluginInfo|
|Version|2.1.5|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|documentation|
|Description|Documentation for BreadcrumbsPlugin|
This plugin provides a list of links to all tiddlers opened during the session, creating a "trail of breadcrumbs" from one tiddler to the next, allowing you to quickly navigate to any previously viewed tiddler, or select 'home' to reset the display to the initial set of tiddlers that were open at the start of the session (i.e., when the document was loaded into the browser).
!!!!!Usage
<<<
{{{
<<breadcrumbs homeSeparator crumbSeparator>>
}}}
By default, the breadcrumbs are displayed as a continuous, //horizontal// word-wrapped line of text, using default character sequences for ''homeSeparator'' (" | ") and ''crumbSeparator'' (" > ").  The //optional// ''homeSeparator'' and ''crumbSeparator'' macro parameters allow you to specify alternative separators.  For example, to display the breadcrumbs //vertically// (in a stack, rather than a row), set the separator values to use {{{[[<br>]]}}}... and, to display a horizontal line as the home separator, use {{{[[<html><hr></html>]]}}}.
{{{
<<previousTiddler>>
}}}
This macro embeds a 'back' button in your content.  Clicking the button opens/scrolls to the most recent previously viewed tiddler.  You can also add the {{{previousTiddler}}} keyword to the ~ViewToolbar slice definition in ToolbarCommands.  This adds a 'back' button directly to the toolbar of each tiddler that is displayed.
<<<
!!!!!Examples:
<<<
{{{
<<breadcrumbs>>
}}}
<<breadcrumbs>>
{{{
<<breadcrumbs [[<html><hr></html>]] [[<br>]]>>
}}}
<<breadcrumbs [[<html><hr></html>]] [[<br>]]>>
<<<
!!!!!Customization
<<<
Using CSS and a few of the plugin configuration options (see below), you can make the breadcrumbs display resemble browser tabs by adding the following to your [[StyleSheet]]:
{{{
.breadCrumbs { border-bottom:1px solid; }
.breadCrumbs a {
	border: 1px solid; padding: 0px 1em;
	-moz-border-radius-topleft:.5em; -moz-border-radius-topright:.5em;
	-webkit-border-top-left-radius:.5em; -webkit-border-top-right-radius:.5em;
}
}}}
and this in [[ConfigTweaks]] (tagged with systemConfig, of course):
{{{
config.options.chkShowStartupBreadcrumbs=true;
config.options.chkBreadcrumbsLimitOpenTiddlers=true;
config.options.txtBreadcrumbsLimitOpenTiddlers=1;
config.macros.breadcrumbs.homeSeparator=" ";
config.macros.breadcrumbs.crumbSeparator=" ";
}}}
<<<
!!!!!Configuration
<<<
__''display placement:''__
<<option chkCreateDefaultBreadcrumbs>> automatically create breadcrumbs display (if needed)
{{{<<option chkCreateDefaultBreadcrumbs>>}}}
>By default, the plugin automatically creates the "breadCrumbs" display element at the top of the story column, just above the tiddlerDisplay area.  To manually control the display and placement of the breadcrumbs display, you can define a DIV with class="breadCrumbs" in a custom [[PageTemplate]] or embed the {{{<<breadcrumbs>>}}} macro in specific tiddler content.
>
>For example, to add the breadcrumbs below the mainMenu, change this:
{{{
<div id='mainMenu' refresh='content' tiddler='MainMenu'></div>
}}}
>to:
{{{
<div id='mainMenu'>
	<div refresh='content' tiddler='MainMenu'></div>
	<div id='breadCrumbs' class='breadCrumbs'></div>
</div>
}}}
>You can also block automatic creation of the breadcrumbs display by setting
{{{
config.options.chkCreateDefaultBreadcrumbs=false;
}}}
>in a [[CookieJar]]/[[ConfigTweaks]] plugin tiddler.

__''other settings:''__
<<option chkShowBreadcrumbs>> show/hide breadcrumbs display
{{{<<option chkShowBreadcrumbs>>}}}
>This checkbox toggles the visibility of the breadcrumbs display.  However, the display is not updated until the next crumb is added (or a previous crumb is clicked on).  For immediate effect, you can use [[ToggleBreadcrumbs]] to synchronize the checkbox setting and the breadcrumbs display.
<<option chkReorderBreadcrumbs>> re-order breadcrumbs when visiting a previously viewed tiddler
{{{<<option chkReorderBreadcrumbs>>}}}
>When visiting a previously viewed tiddler, the title of the most-recently displayed tiddler is simply moved to the end of the list and individual breadcrumbs are not removed from the list unless the underlying tiddler is deleted.  When ''re-ordering'' is disabled, the breadcrumbs list is ''trimmed'' so that all crumbs following that tiddler are removed from the list.
<<option chkBreadcrumbsHideHomeLink>> omit 'Home' link from breadcrumbs display
{{{<<option chkBreadcrumbsHideHomeLink>>}}}
>Enabling this option suppresses the automatic display of the "Home" link (and home separator).  To manually add the home link elsewhere in your document, use the following HTML:
{{{
<html><a href="javascript:;" onclick="config.macros.breadcrumbs.home()">home</a></html>
}}}
<<option chkBreadcrumbsSave>> prompt to save breadcrumbs when 'Home' link is pressed
{{{<<option chkBreadcrumbsSave>>}}}
>Whenever you press the 'home' button, you can be prompted to save the current breadcrumbs in a tiddler as a space-separated list of tiddler links (default title="SavedBreadcrumbs").  
<<option chkShowStartupBreadcrumbs>> show breadcrumbs for 'startup' tiddlers
{{{<<option chkShowStartupBreadcrumbs>>}}}
>Breadcrumbs are usually only added for tiddlers that are opened after the document has been loaded, and not for tiddlers displayed during initial startup (e.g., [[DefaultTiddlers]]).  Enabling this option displays breadcrumbs for all viewed tiddlers, regardless of when they are opened.
<<option chkBreadcrumbsReverse>> show breadcrumbs in reverse order
{{{<<option chkBreadcrumbsReverse>>}}}
>As tiddlers are displayed, breadcrumbs are usually added to the //end// of the list.  Enabling this option displays breadcrumbs in reverse order, so that the most recently visited tiddlers are listed first.
<<option chkBreadcrumbsLimit>> limit breadcrumbs display to {{twochar{<<option txtBreadcrumbsLimit>>}}} items
{{{<<option chkBreadcrumbsLimit>>}}} and {{{<<option txtBreadcrumbsLimit>>}}}
>By default, breadcrumbs are displayed for all tiddlers that have been visited (unless the list is being 'trimmed' by disabling the chkReorderBreadcrumbs option above).  Enabling this option limits the display of the list to a maximum specified number of breadcrumbs.
<<option chkBreadcrumbsLimitOpenTiddlers>> limit open tiddlers to {{twochar{<<option txtBreadcrumbsLimitOpenTiddlers>>}}} items
{{{<<option chkBreadcrumbsLimitOpenTiddlers>>}}} and {{{<<option txtBreadcrumbsLimitOpenTiddlers>>}}}
>By default, tiddlers remain open (e.g., displayed in the story column) until you explicitly close them.  When this option is enabled, only the most recently opened tiddlers will remain open: ''any tiddlers in excess of the specified limit are automatically closed.''  //Note: for 'data safety', if a tiddler is being edited, you will be asked for permission to "save-and-close" that tiddler or leave it open (even if that would exceed the specified limit).//
<<<
!!!!!Revisions
<<<
2012.06.10 2.1.5 refactored default options to eliminate global variable and use init() handling
2011.02.16 2.1.4 in refresh(), use 'inline' instead of 'block' style (avoids unwanted linebreak).  In previousTiddler(), allow handling even if not in a tiddler so that back button can be placed in ~MainMenu or ~SidebarOptions.
2010.11.30 2.1.3 use story.getTiddler()
2009.10.19 2.1.2 code reduction
2009.03.22 2.1.0 added 'save breadcrumbs to tiddler' feature
2008.05.01 2.0.0 added 'limit open tiddlers' feature (with safety check for tiddler in edit mode)
2008.04.06 1.9.1 corrected 'limit' logic so that //last// N crumbs are shown instead of //first// N crumbs.  Also, added chkBreadcrumbsHideHomeLink
2008.04.04 1.9.0 added chkBreadcrumbsReverse and chk/txtBreadcrumbsLimit
2008.03.29 1.8.4 in displayTiddler(), get title from tiddler object (if needed).  Fixes errors caused when calling function passes a tiddler *object* instead of a tiddler *title*
2008.03.24 1.8.3 include shadow tiddlers in breadcrumbs list.  Also changed settings so that "reordering" breadcrumbs is the default, instead of "trimming" the list
2007.12.04 [*.*.*] update for TW2.3.0: replaced deprecated core functions, regexps, and macros
2007.10.26 1.8.2 documentation cleanup
2007.10.18 1.8.1 in GetAreas(), use try/catch to avoid "Bad NPObject as private data" fatal error caused when embedded QuickTime player element is accessed by hasClass() function.
2007.10.02 1.8.0 major documentation and code cleanup.  Moved config.breadCrumbs.* to config.macros.breadcrumbs.* to consolidate objects.  Also, fixed homeSeparator and crumbSeparator default handling.
2007.10.02 1.7.0 added config.options.chkShowStartupBreadcrumbs option
2007.09.16 1.6.1 in getAreas(), removed errant use of 'place' (was causing fatal error when creating default breadcrumbs display element).  Also, added chkCreateDefaultBreadcrumbs configuration setting to enable/disable automatic creation of a default breadcrumbs display.
2007.09.16 1.6.0 re-wrote refresh() to enable multiple display instances, by finding elements with "breadCrumbs" classname.  Fallback to fixed ID (="breadCrumbs") is still used for backward-compatibility.  move rendering code from refresh() to separate render() function, and added definition for {{{<<breadCrumbs>>}}} macro to support embedding breadcrumbs displays in tiddler content.
2007.09.15 [1.5.9.1] updated documentation
2007.09.15 1.5.9 defined homeSeparator (" | ") and crumbSeparator (" > ") as object properties so that they can be redefined as desired for different layouts (e.g., using 'newline' for the crumbSeparator will arrange crumbs in a column rather than a row.
2007.06.21 [1.5.8.1] in home(), return false to prevent IE from attempting to navigate away...
2007.05.26 1.5.8 added support for {{{<<option chkReorderBreadcrumbs>>}}} to toggle trim vs. re-order behavior when visiting previously viewed tiddlers
2007.05.25 1.5.7 added support for {{{<<option chkShowBreadcrumbs>>}}} to toggle //display// of breadcrumbs
2007.05.24 1.5.6 in refresh(), remove non-existing tiddler titles from crumb list.  Also, hijack removeTiddler() so crumbs can be updated after tiddler is deleted.
2007.04.11 1.5.5 added optional params to previousTiddler macro handler() to allow alternative label and tooltip text (instead of default "back")
2007.03.02 1.5.4 in refresh(), for TW2.2, look for "storyDisplay" instead of "tiddlerDisplay" but keep fallback to "tiddlerDisplay" for TW2.1 or earlier
2007.02.24 1.5.3 changed from hijack of onClickTiddlerLink to hijack of displayTiddler() so that ALL displayed tiddlers are recorded in the crumbs, including programmatically displayed tiddlers opened by macros, scripts, etc., (such as [[GotoPlugin]], among many others) in addition to those opened by clicks on links.
2007.02.24 [1.5.2.0] eliminated global space clutter by moving function and data declarations so they are contained inside config.breadCrumbs object.
2007.02.06 1.5.1 added "previousTiddler" macro (for use in sidebar)
2007.02.05 1.5.0 added "previousTiddler" toolbar command (aka, "back")
2006.08.04 [1.4.0.1] change spaces to tabs
2006.08.04 1.4.0 modified from 1.4.0 distro: in refresh(), set {{{display:none/block}}} instead of {{{visibility:hidden/visible}}}.  In home(), check for valid crumbArea before setting style.
2006.08.02 1.4.0 Fixed bug, the redefined onClickTiddlerLink_orig_breadCrumbs works incorrectly on IE
2006.07.20 1.3.0 Runs compatibly with TW 2.1.0 (rev #403+)
2006.02.07 1.2.0 change global array breadCrumbs to config.breadCrumbs by Eric's suggestion
2006.02.04 1.1.0 JSLint checked
2006.02.01 1.0.0 initial release
<<<
Configuration Management is a broad and important topic in [[Software Development]] 

#[[Concurrent Versioning System]] is, probably, your first concern in regard to CM.
## [[Reuse oriented CVS]] is a major factor to promote [[Systematic Reuse]]

----
/%
@@color:#c4d6ed; ^^
Description: Configuration Management topics, discussions and guidelines.
^^@@
%/
/***
|Name|BreadcrumbsPlugin|
|Author|Eric Shulman|
|Source|http://www.TiddlyTools.com/#BreadcrumbsPlugin|
|Documentation|http://www.TiddlyTools.com/#BreadcrumbsPluginInfo|
|Version|2.1.5|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|list/jump to tiddlers viewed during this session plus "back" button/macro|
This plugin provides a list of links to all tiddlers opened during the session, creating a "trail of breadcrumbs" from one tiddler to the next, allowing you to quickly navigate to any previously viewed tiddler, or select 'home' to reset the display to the initial set of tiddlers that were open at the start of the session (i.e., when the document was loaded into the browser).
!!!!!Documentation
<<<
see [[BreadcrumbsPluginInfo]]
<<<
!!!!!Configuration
<<<
<<option chkCreateDefaultBreadcrumbs>> automatically create breadcrumbs display (if needed)
<<option chkShowBreadcrumbs>> show/hide breadcrumbs display
<<option chkReorderBreadcrumbs>> re-order breadcrumbs when visiting a previously viewed tiddler
<<option chkBreadcrumbsHideHomeLink>> omit 'Home' link from breadcrumbs display
<<option chkBreadcrumbsSave>> prompt to save breadcrumbs when 'Home' link is pressed
<<option chkShowStartupBreadcrumbs>> show breadcrumbs for 'startup' tiddlers
<<option chkBreadcrumbsReverse>> show breadcrumbs in reverse order (most recent first)
<<option chkBreadcrumbsLimit>> limit breadcrumbs display to {{twochar{<<option txtBreadcrumbsLimit>>}}} items
<<option chkBreadcrumbsLimitOpenTiddlers>> limit open tiddlers to {{twochar{<<option txtBreadcrumbsLimitOpenTiddlers>>}}} items

<<<
!!!!!Revisions
<<<
2012.06.10 2.1.5 refactored default options to eliminate global variable and use init() handling
| Please see [[BreadcrumbsPluginInfo]] for previous revision details |
2006.02.01 1.0.0 initial release
<<<
!!!!!Code
***/
//{{{
version.extensions.BreadcrumbsPlugin = { major: 2, minor: 1, revision: 5, date: new Date(2012,6,10) };
config.macros.breadcrumbs = {
	crumbs: [], // the list of current breadcrumbs
	askMsg: "Save current breadcrumbs before clearing?\n"
		+"Press OK to save, or CANCEL to continue without saving.",
	saveMsg: 'Enter the name of a tiddler in which to save the current breadcrumbs',
	saveTitle: 'SavedBreadcrumbs',
	options: {
		chkShowBreadcrumbs:		true,
		chkReorderBreadcrumbs:		true,
		chkCreateDefaultBreadcrumbs:	true,
		chkShowStartupBreadcrumbs:	false,
		chkBreadcrumbsReverse:		false,
		chkBreadcrumbsLimit:		false,
		txtBreadcrumbsLimit:		5,
		chkBreadcrumbsLimitOpenTiddlers:false,
		txtBreadcrumbsLimitOpenTiddlers:5,
		chkBreadcrumbsHideHomeLink:	false,
		chkBreadcrumbsSave:		false,
		txtBreadcrumbsHomeSeparator:	' | ',
		txtBreadcrumbsCrumbSeparator:	' > '
	},
	init: function() {
		merge(config.options,this.options,true);
	},
	handler: function(place,macroName,params,wikifier,paramString,tiddler) {
		var area=createTiddlyElement(place,"span",null,"breadCrumbs",null);
		area.setAttribute("homeSep",params[0]||config.options.txtBreadcrumbsHomeSeparator);
		area.setAttribute("crumbSep",params[1]||config.options.txtBreadcrumbsCrumbSeparator);
		this.render(area);
	},
	add: function (title) {
		var thisCrumb = title;
		var ind = this.crumbs.indexOf(thisCrumb);
		if(ind === -1)
			this.crumbs.push(thisCrumb);
		else if (config.options.chkReorderBreadcrumbs)
			this.crumbs.push(this.crumbs.splice(ind,1)[0]); // reorder crumbs
		else
			this.crumbs=this.crumbs.slice(0,ind+1); // trim crumbs
		if (config.options.chkBreadcrumbsLimitOpenTiddlers)
			this.limitOpenTiddlers();
		this.refresh();
		return false;
	},
	getAreas: function() {
		var crumbAreas=[];
		// find all DIVs with classname=="breadCrumbs"
		var all=document.getElementsByTagName("*");
		for (var i=0; i<all.length; i++)
			try{ if (hasClass(all[i],"breadCrumbs")) crumbAreas.push(all[i]); } catch(e) {;}
		// or, find single DIV w/fixed ID (backward compatibility)
		var byID=document.getElementById("breadCrumbs")
		if (byID && !hasClass(byID,"breadCrumbs")) crumbAreas.push(byID);
		if (!crumbAreas.length && config.options.chkCreateDefaultBreadcrumbs) {
			// no crumbs display... create one
			var defaultArea = createTiddlyElement(null,"span",null,"breadCrumbs",null);
		 	defaultArea.style.display= "none";
			var targetArea= document.getElementById("tiddlerDisplay");
		 	targetArea.parentNode.insertBefore(defaultArea,targetArea);
			crumbAreas.push(defaultArea);
		}
		return crumbAreas;
	},
	refresh: function() {
		var crumbAreas=this.getAreas();
		for (var i=0; i<crumbAreas.length; i++) {
			crumbAreas[i].style.display = config.options.chkShowBreadcrumbs?"inline":"none";
			removeChildren(crumbAreas[i]);
			this.render(crumbAreas[i]);
		}
	},
	render: function(here) {
		var co=config.options; var out=""
		if (!co.chkBreadcrumbsHideHomeLink) {
			createTiddlyButton(here,"Home",null,this.home,"tiddlyLink tiddlyLinkExisting");
			out+=here.getAttribute("homeSep")||config.options.txtBreadcrumbsHomeSeparator;
		}
		for (c=0; c<this.crumbs.length; c++) // remove non-existing tiddlers from crumbs
			if (!store.tiddlerExists(this.crumbs[c]) && !store.isShadowTiddler(this.crumbs[c]))
				this.crumbs.splice(c,1);
		var count=this.crumbs.length;
		if (co.chkBreadcrumbsLimit && co.txtBreadcrumbsLimit<count) count=co.txtBreadcrumbsLimit;
		var list=[];
		for (c=this.crumbs.length-count; c<this.crumbs.length; c++) list.push('[['+this.crumbs[c]+']]');
		if (co.chkBreadcrumbsReverse) list.reverse();
		out+=list.join(here.getAttribute("crumbSep")||config.options.txtBreadcrumbsCrumbSeparator);
		wikify(out,here);
	},
	home: function() {
		var cmb=config.macros.breadcrumbs;
		if (config.options.chkBreadcrumbsSave && confirm(cmb.askMsg)) cmb.saveCrumbs();
		story.closeAllTiddlers(); restart();
		cmb.crumbs = []; var crumbAreas=cmb.getAreas();
		for (var i=0; i<crumbAreas.length; i++) crumbAreas[i].style.display = "none";
		return false;
	},
	saveCrumbs: function() {
		var tid=prompt(this.saveMsg,this.saveTitle); if (!tid||!tid.length) return; // cancelled by user
		var t=store.getTiddler(tid);
		if(t && !confirm(config.messages.overwriteWarning.format([tid]))) return;
		var who=config.options.txtUserName;
		var when=new Date();
		var text='[['+this.crumbs.join(']]\n[[')+']]';
		var tags=t?t.tags:[]; tags.pushUnique('story');
		var fields=t?t.fields:{};
		store.saveTiddler(tid,tid,text,who,when,tags,fields);
		story.displayTiddler(null,tid);
		story.refreshTiddler(tid,null,true);
		displayMessage(tid+' has been '+(t?'updated':'created'));
	},
	limitOpenTiddlers: function() {
		var limit=config.options.txtBreadcrumbsLimitOpenTiddlers; if (limit<1) limit=1;
		for (c=this.crumbs.length-1; c>=0; c--) {
			var tid=this.crumbs[c];
			var elem=story.getTiddler(tid);
			if (elem) { // tiddler is displayed
				if (limit <=0) { // display limit has been reached
					if (elem.getAttribute("dirty")=="true") { // tiddler is being edited
						var msg= "'"+tid+"' is currently being edited.\n\n"
							+"Press OK to save and close this tiddler\n"
							+"or press Cancel to leave it opened";
						if (confirm(msg)) {
							story.saveTiddler(tid);
							story.closeTiddler(tid);
						}
					}
					else story.closeTiddler(this.crumbs[c]);
				}
				limit--;
			}
		}
	}
};
//}}}
// // PreviousTiddler ('back') command and macro
//{{{
config.commands.previousTiddler = {
	text: 'back',
	tooltip: 'view the previous tiddler',
	handler: function(event,src,title) {
		var crumbs=config.macros.breadcrumbs.crumbs;
		if (crumbs.length<2) config.macros.breadcrumbs.home();
		else story.displayTiddler(story.findContainingTiddler(src),crumbs[crumbs.length-2]);
		return false;
	}
};
config.macros.previousTiddler= {
	label: 'back',
	prompt: 'view the previous tiddler',
	handler: function(place,macroName,params,wikifier,paramString,tiddler) {
		var label=params.shift(); if (!label) label=this.label;
		var prompt=params.shift(); if (!prompt) prompt=this.prompt;
		createTiddlyButton(place,label,prompt,function(ev){
			return config.commands.previousTiddler.handler(ev,this)
		});
	}
}
//}}}
// // HIJACKS
//{{{
// update crumbs when a tiddler is displayed
if (Story.prototype.breadCrumbs_coreDisplayTiddler==undefined)
	Story.prototype.breadCrumbs_coreDisplayTiddler=Story.prototype.displayTiddler;
Story.prototype.displayTiddler = function(srcElement,tiddler) {
	var title=(tiddler instanceof Tiddler)?tiddler.title:tiddler;
	this.breadCrumbs_coreDisplayTiddler.apply(this,arguments);
	if (!startingUp || config.options.chkShowStartupBreadcrumbs)
		config.macros.breadcrumbs.add(title);
}

// update crumbs when a tiddler is deleted
if (TiddlyWiki.prototype.breadCrumbs_coreRemoveTiddler==undefined)
	TiddlyWiki.prototype.breadCrumbs_coreRemoveTiddler=TiddlyWiki.prototype.removeTiddler;
TiddlyWiki.prototype.removeTiddler= function() {
	this.breadCrumbs_coreRemoveTiddler.apply(this,arguments);
	config.macros.breadcrumbs.refresh();
}
//}}}
The title and subtitle of your space are visible to visitors and are also displayed in your browser's tabs. Click on the SiteTitle and SiteSubtitle tiddler links below to make changes.
* [[SiteTitle]]
* [[SiteSubtitle]]
High Maturity Practices are one of the main factors to distinguish professional development from amateur one.

*[[Configuration Management]] is essential! No professional development may be carried out without it.
*[[Continuous Integration]] is important in any team with more than zero elements.
*[[Static Analysis]] is, probably, the simplest practice to implement and that can, immediately, have a big return on your code quality. Think about having one hundred of the best programmers inspecting your code... 
*[[Unit Testing]] overemphasised but nevertheless an excellent quality tool.
*[[Peer Review]] essential if a quality standard is to be maintained.
*[[Systematic Reuse]] is a major quality and productivity factor.
*[[Issue Management]] is essential to cope with complexity.

----
@@color:#c4d6ed; ^^
Description: Reference of practices that distinguish professional development from amateur one.
^^@@
<<image SiteIcon>> 
!!Personal site for Andre' de Carvalho's Software Development thoughts and more...

Most of the content will be Software Engineering related but other topics will emerge as well.
Hope you find it useful.

 
Strong cohesion and loose [[coupling|Coupling]] are a good thing in software design.
Functional cohesion (see <<BibRef "McConnell 2004">>) be it at routine, class or module level plays an essential role in reusability, maintainability and testability. If a module does a dozen different things, chances are that, in a different scenario, one of them is not done the way you need and, in that case, you will not reuse the entire module.

Cohesion is some times relegated in favour of automatizaton, that is, you extend your module responsibilities because that way you can provide more automatism to the programmers using the module. The trade-offs shall be carefully considered and segregation measures taken. See [[Namespace Code Placement Guidelines]].

TODO: check reference
"//the functional relatedness of the elements of a module//"
Structured Analysis and System Specification, Tom DeMarco, Yourdon Press Computing Series, 1979
The Practical Guide to Structured Systems Design, 2d. ed., Meilir Page-Jones, Yourdon Press Computing Series, 1988

Modern :
"//The Single Responsibility Principle
A class should have only one reason to change.//"
Agile Principles, Patterns, and Practices in C#
By Martin C. Robert, Martin Micah

----
See also : [[Application Archetype]] [[Modularization]] [[Coupling]]
@@color:#c4d6ed; ^^
Description: Cohesion concept explanation and references.
^^@@
<!DOCTYPE HTML>
<html>
<body style="display:none">
topics: <ul id="topics"></ul>
<button id='addtopic'>add topic</button>
stream:
<ul id="stream"></ul>
<script type='text/javascript' src='/bags/common/tiddlers/jquery.js'></script>
<script type='text/javascript' src='/bags/tiddlyspace/tiddlers/chrjs'></script>
<script src="/twikifier.js" type="text/javascript" charset="utf-8"></script>
<script type='text/javascript'>
	$.ajaxSetup({
		beforeSend: function(xhr) {
			xhr.setRequestHeader("X-ControlView", "false");
		}
	});
	function renderTopic(topic) {
		var item = $("<li />").appendTo("#topics");
		$("<button class='show' />").text(topic).appendTo(item);
		$("<button class='delete'>x</button>").appendTo(item);
		return item[0];
	}
	var host =  '/';
	var space = "jon";
	var active_topics = [];
	var current_topic, offset;
	function renderTopics() {
		var topics = active_topics;
		$("#topics").empty();
		for(var i = 0; i < topics.length; i++) {
			var topic = topics[i];
			if(topic) {
				renderTopic(topic);
			}
		}
		$("body").show();
	}
	// Array Remove - By John Resig (MIT Licensed)
	Array.prototype.remove = function(from, to) {
		var rest = this.slice((to || from) + 1 || this.length);
		this.length = from < 0 ? this.length + from : from;
		return this.push.apply(this, rest);
	};

	var topicList = new tiddlyweb.Tiddler("Topics", new tiddlyweb.Bag(space + "_public", host));
	topicList.get(function(tid) {
			active_topics = tid.text.split("\n");
			renderTopics(active_topics);
			$("#topics .show:first").trigger("click");
		},
		function() {
			active_topics = ["tiddlyspace"];
			renderTopics(active_topics)
		}
	);
	$("#addtopic").click(function(ev) {
		var text = prompt("What topic would you like to watch?");
		if(active_topics.indexOf(text) === -1) {
			active_topics.push(text);
		}
		var el = renderTopic(text);
		topicList.text = active_topics.join("\n");
		topicList.put(function() {
			$("button.show", el).trigger("click");
		}, function() {
			alert("eek!")
		});
	});
	$("#topics .delete").live("click",function(ev) {
		var topic = $(".show", this.parentNode).text();
		active_topics.remove(active_topics.indexOf(topic));
		renderTopics();
		topicList.text = active_topics.join("\n");
		topicList.put(function() {}, function() {
			alert("eek!")
		});
	});
	w = createWikifier(window, jQuery, { host: host, container: "recipes/" + space + "_public" });
	$("#topics .show").live("click",function(ev) {
		var tag = $(this).text();
		current_topic = tag;
		offset = 0;
		$("#stream").empty();
		var search = new tiddlyweb.Search('tag:"' + tag + '" &fat=y', host);
		search.get(function(tiddlers) {
			for(var i = 0; i < tiddlers.length; i++) {
				var tiddler = tiddlers[i];
				var item = $("<li />").appendTo("#stream")[0];
				$("<h2 />").text(tiddler.title + ": ").appendTo(item);
				
				$("<div class='text' />").text(tiddler.text).appendTo(item);
				$("<div class='author' />").text(tiddler.modifier).appendTo(item);
			}
		}, function() {
			$("<li>no topics :-(</li>").appendTo("#stream");
		});
	});
	$(window).scroll(function(){
		if($(window).scrollTop() == $(document).height() - $(window).height()) {
			offset += 10;
			// find a way to get all tiddlers created before the ones above
			console.log("loadMore();");
		}
	});
</script>
</body>
</html>
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
The first thing to consider when designing a [[CVS]] policy is file system structure. You must establish rules and standard file system structures to cope with complexity and allow for information location and retrieval. Also, if [[reuse|Systematic Reuse]] is, and it should be, a concern, a proper, standardized and followed, [[code file system|Namespace and Filesystem Guidelines]] is a major asset you can not afford to underestimate.
As said, [[Configuration Management]] encompasses much more than code and, as such, your file system structure shall reflect that.
For the code part you may look at [[Promoting Reuse by Reference]] and [[Namespace and Filesystem Guidelines]]. A good [[CVS]] tool and policy are essential on promoting [[Systematic Reuse]].

TODO:
----
Back to [[Concurrent Versioning System]] [[High Maturity Practices]]
See also [[Namespace and Filesystem Guidelines]] [[Promoting Reuse by Reference]]
----
/%
@@color:#c4d6ed; ^^
Description: Some guidelines for Concurrent Versioning Systems implementation and management.
^^@@
%/
[[HomePage]]
[[Static Analysis]] implementation in an enterprise wide fashion is not too expensive but presents several risks. You will have a machine telling people they made mistakes... the machine shall better be right or it will quickly be labelled as non functioning and ignored. Also one thousand warnings are no warning at all... You shall carefully select your Static Analysis rules and Severity levels in order to assure important things are noticed and unimportant ones don't clutter analysis. Credibility of the tool analysis shall be your first concern. Start by classifying all occurrences at Info or Minor level then analyse some projects and start promoting the level of the more important and trustworthy ones.

Coverage of the static analysis tool shall be progressive, that is, first it shall warn only on indisputable occurrences that constitute a clear defect or violation. This is a way to establish the tool and motivate adherence and recognition of its importance.

Consider some goals for Static Analysis:
*It shall be a tool for programmers to evolve in their code quality
*It shall be considered an useful "automated reviewer" by every programmer
*it shall promote an healthy competitive quality referential among teams and projects
*It shall be a trusted and respected warning system

!!Analysis Targets
|Type|Description|Sub-type|Description|h
|Defects||||
|Conformance||Documentation||
|~|~|Naming||
|Anti-pattern||Metrics||
|~|~|Security||
|~|~|Performance||
|~|~|Guideline||

!!Occurrence severity
|Level|Meaning|Action|Override|h
|''Blocker''|Refers to occurrences that, almost always, represent a very severe problem.|Immediate action required. Show stopper.|Non overrideable.|
|''Critical''|Refers to occurrences that, almost always, represent a severe problem.|Immediate action required.|Non overrideable.|
|''Major''|Refers to occurrences that, almost always, represent a problem.|Action advisable.|Overrideable only with a case-by-case analysis and justification.|
|''Minor''|Refers to occurrences that, normally, represent a deviation from the desirable pattern.|No immediate action required.|Globally overrideable with a justification.|
|''Info''|Refers to occurrences that may or may not be a problem depending on the specific context.|No immediate action required.|Project decision on the relevance of the pattern may be taken at a global level.|

----
@@color:#c4d6ed; ^^
Description: practical guidelines in implementing Static Analysis
^^@@
Validation & [[Verification]] (V&V) in software are the quality processes to assure that as system fulfils its intended purpose and performs as specified.
Validation is oriented to assure that "''we are building the right thing''". Verification gears towards assuring that "''we built it right''".

A very important quality attribute of any specification is its validation ability, that is, the degree to which it allows validation from your Customer and peers. This is achieved, mainly, through structure, context and clearness.  See [[Writing Good Requirements]] for more information.

Validation ability is an essential quality attribute of a [[Technical Proposal|Technical Proposal Production Guidelines]]. The ability you provide to your (prospective) Customer of judging the fitness of you understanding of his problem and the solution you propose to it is what will set you proposal apart from the rest.

Validation is also an essential step on other specification stages to prevent expensive mistakes and misunderstandings, that's why you want all of your specifications reviewed and approved by your Customer before you start developing.

----
@@color:#c4d6ed; ^^
Description: Software Validation concept
^^@@
/%

Hello,

If you choose to change this GettingStarted tiddler, you may wish to add the following to your new content if you expect you space to be included:

<<<
----
Hello,
''This ~GettingStarted tiddler has been customized.''
If you want to see the original system tiddler just click the following link: GettingStarted@system-info at system-info.
<<<
%/

Welcome to your brand new [[TiddlySpace|http://docs.tiddlyspace.com/TiddlySpace]].

You're almost ready to go, there are just a couple of things left to do.

!Customise your space
Go to [[SpaceSettings]] to finish customising  your space. When you're done, come back here (just scroll up). Don't worry though, this will still be open when you've finished.

!Further Customisation

For advanced options, the [[ServerSettings]] tiddler is used to enable the following features:

#index: The value is the name of a tiddler that will be presented when loading the space.  For example, when set to {{{Hello}}} for the space hello.tiddlyspace.com, navigating to that URL will present the Hello tiddler. If there is no {{{Hello}}} you will get an error.
#editor: The name of an [[editor application|http://docs.tiddlyspace.com/Example%20Tiddler%20Editors]] to edit tiddlers with.  Applications come from [[included spaces|http://docs.tiddlyspace.com/How%20do%20I%20include%2Fexclude%20spaces%3F]]

//If you do not need or understand these features there is no need to create a ServerSettings tiddler.//

To edit these options: 

* click [[here|ServerSettings]] to open the [[ServerSettings]] tiddler
* click on the edit button (the pencil icon)
* add the options you wish to set 
* click on the save button (the tick icon).

An example [[ServerSettings]] tiddler:
{{{
index: HelloThere
editor: /edit#{tiddler}
}}}

The additional text after /edit allows a tiddler to be opened in edit mode e.g:
{{{http://hello.tiddlyspace.com/edit#MyTiddler}}}

!!See Also

* [[ServerSettings shadow tiddler|http://docs.tiddlyspace.com/ServerSettings%20shadow%20tiddler]]
* [[Choosing a non-TiddlyWiki Default Application for your Space|http://docs.tiddlyspace.com/Choosing%20a%20non-TiddlyWiki%20Default%20Application%20for%20your%20Space]]

!Finished customising?
You can [[Start writing]] some [[tiddlers|http://docs.tiddlyspace.com/Tiddler]].
If you're not done tweaking yet though, you can always [[Customise this space|SpaceSettings]] a bit more.

You can also [[access and read other tiddlers in various ways|http://docs.tiddlyspace.com/Viewing%20Tiddlers]].

!Administration
If you'd like to change your password or create another space, visit "Your Account" from the [[Universal Backstage|http://docs.tiddlyspace.com/UniversalBackstage]] (the blue dot in the upper right of the page). If you'd like to add a member or [[include a space|http://docs.tiddlyspace.com/How%20do%20I%20include%2Fexclude%20spaces%3F]] visit "This Space" from the [[Universal Backstage|http://docs.tiddlyspace.com/UniversalBackstage]].

You can have as many spaces as you like and each space can have as many members as you or your group need.

!Stuck?
If you're stuck, and would like some help, please visit the [[help|http://help.tiddlyspace.com]] space, which can point you in the right direction.
/***
|''Name''|ActivityStreamPlugin|
|''Version''|0.5.4|
|''Description''|Provides a following macro|
|''Author''|Jon Robson|
|''Requires''|TiddlySpaceFollowingPlugin|
|''License''|[[BSD|http://www.opensource.org/licenses/bsd-license.php]]|
|''Source''|https://github.com/jdlrobson/TiddlyWiki/raw/master/plugins/TiddlySpaceInstaller/ActivityStreamPlugin.js|
!Usage
{{{<<activity>>}}}
!!Supressing activity
You can supress notifications by  id:
"plugin", "shadow", "standard", "follow", "followYou", "siteInfo", "siteIcon", "ownSiteIcon", "notify", "reply"
e.g. {{{ <<activity supress:siteIcon>> }}} will hide siteIcon activity from you.

!!Supressing people
{{{<<activity ignore:person}}} will ignore all activity where person is the subject of the activity. eg. person followed other-person will not appear in the feed.
!!Controlling displayed dates.
{{{<<activity timestampFormat:"<0hh o' clock>" headingFormat:"0DD/0MM" >>}}} will display date headings as date/month eg.
3rd of January would be displayed as 03/01. This particular timestamp example gives you the hour of the activity.

!!Even more content
{{{<<activity limit:no>>}}} will show you all possible activity in the last X days where X is set at a macro level (advanced developers should see config.macros.activity.RECENTNESS).
!StyleSheet

.activityStream .externalImage, .activityStream .image {
	display: inline;
}

.feedItem .siteIcon {
	display: inline;
}

.activityStream .error {
	background-color: red;
	color: white;
	font-weight: bold;
}

.activityStream .feedItem {
list-style: none;
}

.activityStream .notification {
	background-color: yellow;
	color: black;
}

.activityStream .activityGroupTitle {
	font-weight: bold;
	margin-top: 8px;
}
.activityStream .feedItem {
	margin-left: 8px;
}
!Code
***/
//{{{
(function($) {
var name = "StyleSheetActivityStream";
config.shadowTiddlers[name] = store.getTiddlerText(tiddler.title +
     "##StyleSheet");
store.addNotification(name, refreshStyles);

var followMacro = config.macros.followTiddlers;
var tweb = config.extensions.tiddlyweb;
var tiddlyspace = config.extensions.tiddlyspace;
var scanMacro = config.macros.tsScan;

var modifierSpaceLink = "<<view modifier spaceLink>>";
var spaceTiddlyLink = "<<view server.bag spaceLink server.title>>";
var bagSpaceLink = "<<view server.bag spaceLink>>";
var bagSiteIcon = "<<view server.bag SiteIcon width:24 height:24 label:no preserveAspectRatio:yes>>";
var modifierSiteIcon = "<<view modifier SiteIcon width:24 height:24 label:no preserveAspectRatio:yes>>";
var timestamp = "[<<view modified date '0hh:0mm'>>]";
var replyLink = "<<view server.title replyLink>>";
config.shadowTiddlers.ActivityStreamTemplates = [
	"!notify\n%3 {{notification{%0 %1 has modified %2 in %0 %1 and flagged it for your attention!}}} %8\n",
	"!reply\n%3 {{notification{%0 %1 replied with %2 to your %4 %5 post.}}} %8\n",
	"!userSiteIcon\n%3 %6 %7 has a new ~SiteIcon.\n",
	"!spaceSiteIcon\n%3 %6 %7 updated the SiteIcon for the %0 %1 space.\n",
	"!image\n%3 %6 %7 drew the image %2 in the %1 space.\n",
	"!plugin\n%3 %6 %7 modified a plugin called %2 in the %0 %1 space.\n",
	"!shadow\n%3 %6 %7 modified a shadow tiddler %2 in the %0 %1 space.\n",
	"!geo\n%3 %6 %7 modified a geo tiddler called %2 in the %0 %1 space <<view title maplink 'view on map'>>. %8\n",
	"!followYou\n%3 %0 %1 is now following you.\n",
	"!follow\n%3 %0 %1 is now following %4 %5 <<view server.title link follow>>\n",
	"!siteInfo\n%3 %6 %7 <<view server.bag spaceLink server.title label:described>> the %0 %1 space.\n",
	"!video\n%3 %6 %7 modified a video entitled %2 in the %0 %1 space. %8\n",
	"!standard\n%3 %6 %7 modified %2 in the %0 %1 space. %8\n"
	].join("").format(bagSiteIcon, bagSpaceLink, spaceTiddlyLink, timestamp,
		"<<view server.title SiteIcon width:24 height:24 label:no preserveAspectRatio:yes>>", "<<view server.title spaceLink>>",
		modifierSiteIcon, modifierSpaceLink, replyLink);
story.refreshTiddler("ActivityStreamTemplates", null, true);
config.annotations.ActivityStreamTemplates = "This is a special tiddler used by the ActivityStreamPlugin. It is used for templating notifications. Templates at the top have preference over templates at the bottom.";

var macro = config.macros.activity = {
	default_limit: 50,
	templates: [],
	init: function() {
		var templates = [];
		var regex = new RegExp(/^!(.*)\n/gm);
		var text = store.getTiddlerText("ActivityStreamTemplates");
		var match = regex.exec(text);
		while(match) {
			templates.push(match[1]);
			match = regex.exec(text);
		}
		macro.templates = templates;
	},
	// order matters - earlier templates override older ones
	RECENTNESS: 2, // in days
	TIMESTAMP_FORMAT: "<0hh:0mm>",
	info: {},
	locale: {
		pleaseWait: "please wait while we load your stream...",
		errorLoading: "The activity stream failed to load. Please make sure you have an internet connection and try again.",
		userHeading: "Below is the activity stream for spaces that this space follows with the follow tag. (%0/%1 spaces have been loaded)",
		emptyStream: "Activity stream currently empty. (%0/%1 loaded)"
	},
	getTimeStamp: function() {
		var today = new Date();
		macro._lastRun = today.getTime();
		var previous = new Date(today.setDate(today.getDate() - macro.RECENTNESS));
		return previous.convertToYYYYMMDDHHMM();
	},
	handler: function(place, macroName, params, wikifier, paramString, tiddler) {
		var container = $("<div />").text(macro.locale.pleaseWait).appendTo(place).
			attr("refresh", "macro").attr("macroName", macroName).attr("paramString", paramString);
		var space = tiddlyspace.currentSpace.name;
		var options = macro.getOptions(paramString);
		$(container).attr("activity-limit", options.limit);
		macro._session = Math.random();
		var activityType;
		var sourceActivity = function(user) {
			macro.CURRENT_USER = user.name;
			macro.USER_AT_TAG = "@%0".format(user.name);
			followMacro.getFollowers(function(users) {
				macro.getActivity(container, users, activityType, options);
			}, macro.CURRENT_USER);
			container.attr("activity-type", activityType);
			macro._renderStream(container, activityType, options);
		};

		if(options.user) {
			sourceActivity({name: options.user});
		} else {
			sourceActivity({ name: tiddlyspace.currentSpace.name });
		}
	},
	getOptions: function(paramString) {
		var options = {};
		var args = paramString.parseParams("name")[0];
		var toMap = ["timestampFormat", "headingFormat", "limit", "user"];
		var i;
		for(i = 0; i < toMap.length; i++) {
			var map = toMap[i];
			options[map] = args[map] ? args[map][0] : false;
		}
		var supress = args.supress || [];
		var templates = [];
		var show = args.show ? args.show : macro.templates;
		for(i = 0; i < show.length; i++) {
			var template = show[i];
			if(supress.indexOf(template) === -1) {
				templates.push(template);
			}
		}
		options.ignore = args.ignore || [];
		options.templates = templates;
		return options;
	},
	_getActivityQuery: function(user, timestamp) {
		timestamp = timestamp || macro.getTimeStamp();
		if(user) {
			return "/bags/%0_public/tiddlers?select=modified:>%1".format(user, timestamp);
		} else {
			return false;
		}
	},
	refresh: function(container) {
		var type = $(container).attr("activity-type");
		var limit = $(container).attr("activity-limit");
		var options = macro.getOptions($(container).attr("paramString"));
		options.limit = parseInt(limit, 10);
		macro.renderStream(container, type, options);
	},
	getActivity: function(place, users, type, options) {
		var i;
		var timestamp = macro.activityTimestamp;
		var firstRun =  timestamp ? false : true;
		macro.info.loaded = firstRun ? 0 : macro.info.loaded;
		var afterAjax = function(tiddlers) {
			if(firstRun) {
				macro.info.loaded += 1;
			}
			macro.updateStream(tiddlers, type, options);
			macro.renderStream(place, type, options);
		};
		var success = function(tiddlers) {
			afterAjax(tiddlers);
		};
		var error = function() {
			afterAjax([]);
		};
		if(macro._lastRun > new Date().getTime() - 300000) { // leave 5 minutes between calls
			afterAjax([]);
			return;
		}
		macro.info.queries = users.length;
		for(i = 0; i < users.length; i++) {
			var user = users[i];
			ajaxReq({
				url: macro._getActivityQuery(user, timestamp),
				dataType: "json", success: success, error: error
			});
		}
		macro.activityTimestamp = new Date().convertToYYYYMMDDHHMM();
	},
	reportError: function(place) {
		var error = $("<div />").addClass("error").text(locale.errorLoading);
		$(place).empty().append(error);
	},
	createFeedEntry: function(container, tiddler, options) {
		var item = $("<li />").addClass("feedItem");
		var content = $("<div />").appendTo(item);
		var wikifyPlace = $("<span />").appendTo(content)[0];
		var author = tiddler.modifier;
		if(author && !options.ignore.contains(author)) {
			$(container).append(item);
			config.macros.view.views.activityItem(null, wikifyPlace, null, null, null, tiddler);
			return item;
		}
		return false;
	},
	renderStream: function(place, type, options) {
		window.clearTimeout(macro._renderTimeout);
		macro._renderTimeout = window.setTimeout(function() {
			macro._renderStream(place, type, options);
		}, 100);
	},
	_renderStream: function(place, type, options) {
		$(place).empty();
		var limit = options.limit;
		var container = $("<ul />").addClass("activityStream").appendTo(place);
		var textHeading = macro.locale.userHeading.format(macro.info.loaded, macro.info.queries);
		$("<li />").addClass("listTitle").text(textHeading).appendTo(container);
		var tiddlers = store.sortTiddlers(store.filterTiddlers("[server.activity[true]]"), "-modified"); // TODO: sort headings instead if possible (conflicts with limit)
		var headings = [];
		var groups = {};
		var processed = 0, i, j;
		var atEndOfActivityFeed = true;
		for(i = 0; i < tiddlers.length; i++) {
			var tiddler = tiddlers[i];
			if(options.templates.contains(tiddler.fields["server.activity.type"])) {
				if(!limit || processed < limit) {
					var modified = tiddler.modified;
					if(modified) {
						// format date.
						var modifiedString = modified.formatString(options.headingFormat || config.macros.timeline.dateFormat);
						if(headings.contains(modifiedString)) {
							groups[modifiedString].push(tiddler);
						} else {
							headings.push(modifiedString);
							groups[modifiedString] = [ tiddler ];
						}
					}
					processed += 1;
				} else {
					atEndOfActivityFeed = false;
				}
			}
		}
		var somethingRendered;
		for(i = 0; i < headings.length; i++) {
			var heading = headings[i];
			var _tiddlers = store.sortTiddlers(groups[heading], "-modified");
			var headingEl;
			if(_tiddlers.length > 0) {
				headingEl = $("<li />").addClass("listTitle activityGroupTitle").text(heading).appendTo(container);
			}
			var rendered = [];
			for(j = 0; j < _tiddlers.length; j++) {
				var item = macro.createFeedEntry(container, _tiddlers[j], options);
				if(item) {
					rendered.push(item);
				}
			}
			if(rendered.length === 0) {
				headingEl.remove();
			} else {
				somethingRendered = true;
			}
		}
		if(!somethingRendered) {
			var msg;
			if(macro.gotActivity) { // it has been run before
				msg = macro.locale.emptyStream.format(macro.info.loaded, macro.info.queries);
			} else {
				msg = macro.locale.pleaseWait;
			}
			$(container).text(msg);
		}
		if(!atEndOfActivityFeed) { // show more button
			$("<input />").attr("type", "button").val("more").click(function(ev) {
				var currentLimit = $(place).attr("activity-limit");
				var newLimit = parseInt(currentLimit, 10) + 50;
				macro.default_limit = newLimit;
				$(place).attr("activity-limit", newLimit);
				macro.refresh(place);
			}).appendTo(place);
		}
		this.gotActivity = true;
	},
	updateStream: function(jstiddlers, type, options) {
		// assume already sorted.
		var tiddlers = scanMacro._tiddlerfy(jstiddlers, options);
		var _dirty = store.isDirty();
		$.each(tiddlers, function(i, tid) {
			var info = config.macros.view.activity.getActivityInfo(tid, options);
			tid.fields["server.activity.type"] = info.type;
			tid.fields["server.activity"] = "true";
			if(!tid.tags.contains("excludeLists")) {
				tid.title = tiddlyspace.getLocalTitle(tid.title, tid.fields["server.workspace"]);
				tid.tags = tid.tags.concat(["excludeLists", "excludeMissing", "excludeSearch"]);
				tid.fields.doNotSave = "true";
				store.addTiddler(tid); // save caused unsaved changes alert and slowdown
			}
		});
		store.setDirty(_dirty);
	}
};

config.macros.view.views.activityItem = function(value, place, params, wikifier,
	paramString, tiddler) {
	var info = config.macros.view.activity.getActivityInfo(tiddler, {});
	wikify(info.template, place, null, tiddler);
};

var helper = config.macros.view.activity = {
	_isNotification: function(tiddler) {
		return tiddler.tags.contains(macro.USER_AT_TAG) || tiddler.tags.contains("@all");
	},
	_repliesOn: function() {
		return tiddlyspace.currentSpace.name === macro.CURRENT_USER;
	},
	types: {
		video: function(tiddler) {
			return tiddler.tags.contains("video");
		},
		geo: function(tiddler) {
			return tiddler.fields["geo.lat"] && tiddler.fields["geo.long"];
		},
		siteInfo: function(tiddler) {
			var title = tiddler.fields["server.title"];
			return title === "SiteInfo";
		},
		userSiteIcon: function(tiddler) {
			var modifierBag = "%0_public".format(tiddler.modifier);
			var title = tiddler.fields["server.title"];
			return title === "SiteIcon" && modifierBag === tiddler.fields["server.bag"];
		},
		spaceSiteIcon: function(tiddler) {
			var title = tiddler.fields["server.title"];
			return title === "SiteIcon"; // note userSiteIcon above does the bag check
		},
		shadow: function(tiddler) {
			var title = tiddler.fields["server.title"];
			return title in config.shadowTiddlers;
		},
		plugin: function(tiddler) {
			return tiddler.tags.contains("systemConfig");
		},
		followYou: function(tiddler) {
			var title = tiddler.fields["server.title"];
			title = title.indexOf("@") === 0 ? title.substr(1) : title;
			return tiddler.tags.contains("follow") && title === macro.USER_AT_TAG;
		},
		follow: function(tiddler) {
			return tiddler.tags.contains("follow");
		},
		reply: function(tiddler) {
			var title = tiddler.fields["server.title"];
			var myTiddler = store.getTiddler(tiddler.title);
			var myTiddlerIsOlder = myTiddler && myTiddler.modified < tiddler.modified;
			return store.tiddlerExists(title) && myTiddlerIsOlder && helper._repliesOn(tiddler);
		},
		notify: function(tiddler) {
			var title = tiddler.fields["server.title"];
			var myTiddler = store.getTiddler(title);
			var myTiddlerIsNewer = myTiddler && myTiddler.modified > tiddler.modified;
			return helper._isNotification(tiddler) && helper._repliesOn(tiddler) && !myTiddlerIsNewer;
		},
		standard: function(tiddler) {
			return true;
		},
		image: function(tiddler) {
			return config.macros.image.isImageTiddler(tiddler);
		}
	},
	// each type should point to a slice in ActivityStreamTemplates tiddler
	getActivityInfo: function(tiddler, options) {
		var repliesOn = tiddlyspace.currentSpace.name === macro.CURRENT_USER;
		var activityType, i;
		if(tiddler) {
			for(i = 0; i < macro.templates.length; i++) {
				var type = macro.templates[i];
				if(!activityType && helper.types[type]) {
					if(helper.types[type](tiddler)) {
						activityType = type;
					}
				}
			}
		}
		template = store.getTiddlerText("ActivityStreamTemplates##" + activityType) || locale.standardTemplate;
		return activityType ? { template: template, type: activityType } : false;
	}
};

config.macros.view.views.link = function(value, place, params, wikifier,
		paramString, tiddler) {
		var el = createTiddlyLink(place,value,true);
		if(params[2]) {
			$(el).text(params[2]);
		}
};

config.macros.view.views.maplink = function(value, place, params, wikifier,
		paramString, tiddler) {
		var lat = tiddler.fields["geo.lat"];
		var lng = tiddler.fields["geo.long"];
		var label  = params[2] || value;
		if(lat && lng) {
			$("<a />").attr("href", "http://maps.google.com/maps?saddr=%0,%1".format(lat, lng)).text(label).appendTo(place);
		}
};

var _displayS = tiddlyspace.displayServerTiddler;
tiddlyspace.displayServerTiddler = function(src, title, workspace, callback) {
	var localTitle = tiddlyspace.getLocalTitle(title, workspace);
	var localTiddler = store.getTiddler(localTitle);

	var _callback = function(src, tiddler) {
		if(callback) {
			callback(src, tiddler);
		}
		if(localTiddler) {
			tiddler.fields["server.activity"] = "true";
			tiddler.fields["server.activity.type"] = localTiddler.fields["server.activity.type"];
		}
	};
	return _displayS.apply(this, [ src, title, workspace, _callback ]);
};
}(jQuery));
//}}}
/***
|''Name''|TiddlySpacePublishingCommands|
|''Version''|0.8.5|
|''Status''|@@beta@@|
|''Description''|toolbar commands for drafting and publishing|
|''Author''|Jon Robson|
|''Source''|http://github.com/TiddlySpace/tiddlyspace/raw/master/src/plugins/TiddlySpacePublishingCommands.js|
|''CoreVersion''|2.6.1|
|''Requires''|TiddlySpaceConfig TiddlySpaceFilters|
!Usage
Provides changeToPrivate, changeToPublic and saveDraft commands
Provides TiddlySpacePublisher macro.
{{{<<TiddlySpacePublisher type:private>>}}} make lots of private tiddlers public.
{{{<<TiddlySpacePublisher type:public>>}}} make lots of public tiddlers public.
!TODO
* add public argument?
!Code
***/
//{{{
(function($) {

var tiddlyspace = config.extensions.tiddlyspace;
var originMacro = config.macros.tiddlerOrigin;

tiddlyspace.getTiddlerStatusType = function(tiddler) {
	var isShadow = store.isShadowTiddler(tiddler.title);
	var exists = store.tiddlerExists(tiddler.title);
	if(isShadow && !exists) {
		return "shadow";
	} else if(!exists) {
		return "missing";
	} else {
		var types = ["private", "public"];
		var type = "external";
		for(var i = 0; i < types.length; i++) {
			var t = types[i];
			type = config.filterHelpers.is[t](tiddler) ? t : type;
		}
		if(config.filterHelpers.is.unsynced(tiddler)) {
			type = type == "private" ? "unsyncedPrivate" : "unsyncedPublic";
		}
		return type;
	}
};

var cmd = config.commands.publishTiddler = {
	text: "make public",
	tooltip: "Change this private tiddler into a public tiddler",
	errorMsg: "Error publishing %0: %1",

	isEnabled: function(tiddler) {
		return !readOnly && config.filterHelpers.is["private"](tiddler);
	},
	handler: function(ev, src, title) {
		var tiddler = store.getTiddler(title);
		if(tiddler) {
			var newBag = cmd.toggleBag(tiddler.fields["server.bag"]);
			this.moveTiddler(tiddler, {
				title: tiddler.fields["publish.name"] || tiddler.title,
				fields: { "server.bag": newBag }
			});
		}
	},
	toggleBag: function(bag, to) {
		var newBag;
		if(typeof bag != typeof "") {
			var tiddler = bag;
			bag = tiddler.fields["server.bag"];
		}
		if(bag.indexOf("_private") > -1) { // should make use of endsWith
			to = to ? to : "public";
			newBag = bag.replace("_private", "_" + to);
		} else {
			to = to ? to : "private";
			newBag = bag.replace("_public", "_" + to);
		}
		return newBag;
	},
	copyTiddler: function(title, newTitle, newBag, callback) {
		var original = store.getTiddler(title);
		newTitle = newTitle ? newTitle : title;
		var adaptor = original.getAdaptor();
		var publish = function(original, callback) {
			var tiddler = $.extend(new Tiddler(newTitle), original);
			tiddler.fields = $.extend({}, original.fields, {
				"server.bag": newBag,
				"server.workspace": "bags/%0".format(newBag),
				"server.page.revision": "false"
			});
			delete tiddler.fields["server.title"];
			tiddler.title = newTitle;
			adaptor.putTiddler(tiddler, null, null, callback);
		};
		publish(original, callback);
	},
	moveTiddler: function(tiddler, newTiddler, callback) {
			var info = {
			copyContext: {},
			deleteContext: {}
		};
		var _dirty = store.isDirty();
		var adaptor = tiddler.getAdaptor();
		var newTitle = newTiddler.title;
		var oldTitle = tiddler.title;
		delete tiddler.fields["server.workspace"];
		var oldBag = tiddler.fields["server.bag"];
		var newBag = newTiddler.fields["server.bag"];
		var newWorkspace = "bags/%0".format(newBag);
		cmd.copyTiddler(oldTitle, newTitle, newBag, function(ctx) {
				info.copyContext = ctx;
				var context = {
					tiddler: tiddler,
					workspace: newWorkspace
				};
				store.addTiddler(ctx.tiddler);
				tiddler.title = oldTitle; // for cases where a rename occurs
				if(ctx.status) { // only do if a success
					if(oldBag != newBag) {
						adaptor.deleteTiddler(tiddler, context, {}, function(ctx) {
							info.deleteContext = ctx;
							var el;
							if(tiddler) {
								tiddler.fields["server.workspace"] = newWorkspace;
								tiddler.fields["server.bag"] = newBag;
							}
							el = el ? el : story.refreshTiddler(oldTitle, null, true);
							if(oldTitle != newTitle) {
								store.deleteTiddler(oldTitle);
								store.notify(oldTitle, true);
							}
							if(el) {
								story.displayTiddler(el, newTitle);
							}
							if(oldTitle != newTitle) {
								story.closeTiddler(oldTitle);
							}
							if(callback) {
								callback(info);
							}
							store.setDirty(_dirty);
						});
					} else {
						if(callback) {
							callback(info);
						}
					}
					refreshDisplay();
				}
		});
	}
};

var changeToPrivate = config.commands.changeToPrivate = {
	text: "make private",
	tooltip: "turn this public tiddler into a private tiddler",
	isEnabled: function(tiddler) {
		return !readOnly && config.filterHelpers.is["public"](tiddler);
	},
	handler: function(event, src, title) {
		var tiddler = store.getTiddler(title);
		var newBag = cmd.toggleBag(tiddler, "private");
		var newTiddler = { title: title, fields: { "server.bag": newBag }};
		cmd.moveTiddler(tiddler, newTiddler);
	}
};
config.commands.changeToPublic = cmd;

/* Save as draft command */
var saveDraftCmd = config.commands.saveDraft = {
	text: "save draft",
	tooltip: "Save as a private draft",
	isEnabled: function(tiddler) {
		return changeToPrivate.isEnabled(tiddler);
	},
	getDraftTitle: function(title) {
		var draftTitle;
		var draftNum = "";
		while(!draftTitle) {
			var suggestedTitle = "%0 [draft%1]".format(title, draftNum);
			if(store.getTiddler(suggestedTitle)) {
				draftNum = !draftNum ? 2 : draftNum + 1;
			} else {
				draftTitle = suggestedTitle;
			}
		}
		return draftTitle;
	},
	createDraftTiddler: function(title, gatheredFields) {
		var tiddler = store.getTiddler(title);
		var draftTitle = saveDraftCmd.getDraftTitle(title);
		var draftTiddler = new Tiddler(draftTitle);
		if(tiddler) {
			$.extend(true, draftTiddler, tiddler);
		} else {
			$.extend(draftTiddler.fields, config.defaultCustomFields);
		}
		for(var fieldName in gatheredFields) {
			if(TiddlyWiki.isStandardField(fieldName)) {
				draftTiddler[fieldName] = gatheredFields[fieldName];
			} else {
				draftTiddler.fields[fieldName] = gatheredFields[fieldName];
			}
		}
		var privateBag = tiddlyspace.getCurrentBag("private");
		var privateWorkspace = tiddlyspace.getCurrentWorkspace("private");
		draftTiddler.title = draftTitle;
		draftTiddler.fields["publish.name"] = title;
		draftTiddler.fields["server.workspace"] = privateWorkspace;
		draftTiddler.fields["server.bag"] = privateBag;
		draftTiddler.fields["server.title"] = draftTitle;
		draftTiddler.fields["server.page.revision"] = "false";
		delete draftTiddler.fields["server.etag"];
		return draftTiddler;
	},
	handler: function(ev, src, title) {
		var tiddler = store.getTiddler(title); // original tiddler
		var tidEl = story.getTiddler(title);
		var uiFields = {};
		story.gatherSaveFields(tidEl, uiFields);
		var tid = saveDraftCmd.createDraftTiddler(title, uiFields);
		tid = store.saveTiddler(tid.title, tid.title, tid.text, tid.modifier,
			new Date(), tid.tags, tid.fields);
		autoSaveChanges(null, [tid]);
		story.closeTiddler(title);
		story.displayTiddler(src, title);
		story.displayTiddler(src, tid.title);
	}
};

var macro = config.macros.TiddlySpacePublisher = {
	locale: {
		title: "Batch Publisher",
		changeStatusLabel: "Make %0",
		noTiddlersText: "No tiddlers to publish",
		changeStatusPrompt: "Make all the selected tiddlers %0.",
		description: "Change tiddlers from %0 to %1 in this space"
	},

	listViewTemplate: {
		columns: [
			{ name: "Selected", field: "Selected", rowName: "title", type: "Selector" },
			{ name: "Tiddler", field: "tiddler", title: "Tiddler", type: "Tiddler" },
			{ name: "Status", field: "status", title: "Status", type: "WikiText" }
		],
		rowClasses: []
	},

	changeStatus: function(tiddlers, status, callback) { // this is what is called when you click the publish button
		var publicBag;
		for(var i = 0; i < tiddlers.length; i++) {
			var tiddler = tiddlers[i];
			var newTiddler = {
				title: tiddler.title,
				fields: { "server.bag": cmd.toggleBag(tiddler, status) }
			};
			cmd.moveTiddler(tiddler, newTiddler, callback);
		}
	},
	getMode: function(paramString) {
		var params = paramString.parseParams("anon")[0];
		var status = params.type ?
			(["public", "private"].contains(params.type[0]) ? params.type[0] : "private") :
			"private";
		var newStatus = status == "public" ? "private" : "public";
		return [status, newStatus];
	},
	handler: function(place, macroName, params, wikifier, paramString, tiddler) {
		var wizard = new Wizard();
		var locale = macro.locale;
		var status = macro.getMode(paramString);
		wizard.createWizard(place, locale.title);
		wizard.addStep(macro.locale.description.format(status[0], status[1]),
			'<input type="hidden" name="markList" />');
		var markList = wizard.getElement("markList");
		var listWrapper = $("<div />").addClass("batchPublisher").
			attr("refresh", "macro").attr("macroName", macroName).
			attr("params", paramString)[0];
		markList.parentNode.insertBefore(listWrapper, markList);
		$.data(listWrapper, "wizard", wizard);
		macro.refresh(listWrapper);
	},
	getCheckedTiddlers: function(listWrapper, titlesOnly) {
		var tiddlers = [];
		$(".chkOptionInput[rowName]:checked", listWrapper).each(function(i, el) {
			var title = $(el).attr("rowName");
			if(titlesOnly) {
				tiddlers.push(title);
			} else {
				tiddlers.push(store.getTiddler(title));
			}
		});
		return tiddlers;
	},
	refresh: function(listWrapper) {
		var checked = macro.getCheckedTiddlers(listWrapper, true);
		var paramString = $(listWrapper).empty().attr("params");
		var wizard = $.data(listWrapper, "wizard");
		var locale = macro.locale;
		var params = paramString.parseParams("anon")[0];
		var publishCandidates = [];
		var status = macro.getMode(paramString);
		var pubType = status[0];
		var newPubType = status[1];
		var tiddlers = params.filter ? store.filterTiddlers(params.filter[0]) :
			store.filterTiddlers("[is[%0]]".format(pubType));
		var enabled = [];
		for(var i = 0; i < tiddlers.length; i++) {
			var tiddler = tiddlers[i];
			var title = tiddler.title;
			if(!tiddler.tags.contains("excludePublisher") && title !== "SystemSettings") {
				publishCandidates.push({ title: title, tiddler: tiddler, status: pubType});
			}
			if(checked.contains(title)) {
				enabled.push("[rowname=%0]".format(title));
			}
		}

		if(publishCandidates.length === 0) {
			createTiddlyElement(listWrapper, "em", null, null, locale.noTiddlersText);
		} else {
			var listView = ListView.create(listWrapper, publishCandidates, macro.listViewTemplate);
			wizard.setValue("listView", listView);
			var btnHandler = function(ev) {
				var tiddlers = macro.getCheckedTiddlers(listWrapper);
				var callback = function(status) {
					$(".batchPublisher").each(function(i, el) {
						macro.refresh(el);
					});
				};
				macro.changeStatus(tiddlers, newPubType, callback);
			};
			wizard.setButtons([{
				caption: locale.changeStatusLabel.format(newPubType),
				tooltip: locale.changeStatusPrompt.format(newPubType),
				onClick: btnHandler
			}]);
			$(enabled.join(",")).attr("checked", true); // retain what was checked before
		}
	}
};

})(jQuery);
//}}}
/***
|''Name''|TiddlySpaceBackstage|
|''Version''|0.8.0|
|''Description''|Provides a TiddlySpace version of the backstage and a homeLink macro|
|''Status''|@@beta@@|
|''Contributors''|Jon Lister, Jon Robson, Colm Britton|
|''Source''|http://github.com/TiddlySpace/tiddlyspace/raw/master/src/plugins/TiddlySpaceBackstage.js|
|''Requires''|TiddlySpaceConfig ImageMacroPlugin TiddlySpaceViewTypes|
!StyleSheet
.tiddler .error.annotation .button{
	display: inline-block;
}

#backstageArea {
	z-index: 49;
	color: white;
	background-color: black;
	background: -webkit-gradient(linear,left bottom,left top,color-stop(0, #222),color-stop(0.5, #333),color-stop(1, #555));
	background: -moz-linear-gradient(center bottom,#222 0%, #333 50%, #555 100%);
	filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#ff555555, endColorstr=#ff222222);
	-ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr=#ff555555, endColorstr=#ff222222)";
	height: 25px;
	padding: 0;
}

#backstageButton {
	overflow: hidden;
}

#backstageButton #backstageShow,
#backstageButton #backstageHide {
	margin: 0px;
	padding: 0px;
}

#backstageButton #backstageShow:hover,
#backstageButton #backstageHide:hover {
	background: none;
	color: none;
}

#backstageButton img,
#backstageButton svg {
	width: 24px;
	height: 24px;
}

#messageArea {
	top: 50px;
}

#backstageToolbar {
	position: relative;
}

#backstageArea a {
	padding: 0px;
	margin-left: 0px;
	color: white;
	background: none;
}

#backstageArea a:hover {
	background-color: white;
}

#backstage ol,
#backstage ul {
	padding: auto;
}

#backstageButton a {
	margin: 0;
}

.backstagePanelBody ul {
	padding: 5px;
	margin: 5px;
}

#backstage #backstagePanel {
	margin-left: 5%;
	padding: 0em;
	margin-right: 5%;
}

#backstageToolbar a {
	position: relative;
}

#backstageArea a.backstageSelTab,
#backstageToolbar .backstageTask {
	line-height: 25px;
	color: #767676;
}

.backstageTask .externalImage,
.backstageTask .image {
	display: inline;
}

#backstageToolbar a span {
	z-index: 2;
}

a.backstageTask {
	display: inline;
        margin-left: 1em !important;
}

.backstagePanelBody .button {
	display: inline-block;
	margin-right: 10px;
}

.backstagePanelBody {
	margin: 0 0 0 0.6em;
	padding: 0.4em 0.5em 1px 0.5em;
}

#backstage table {
	margin: auto;
}

#backstage .wizard table {
	border: 0px;
	margin: 0;
}

#backstage div  li.listLink {
	border: 0px;
	width: 78%;
	font-size: 0.7em;
}

#backstage div li.listTitle {
	font-weight: bold;
	text-decoration: underline;
	font-size: 1em;
	background: #ccc;
	width: 100%;
}

#backstage fieldset {
	border: solid 1px [[ColorPalette::Background]];
}

#backstage .viewer table,#backstage table.twtable {
	border: 0px;
}

#backstageToolbar img {
	padding: 0;
}

#backstage .wizard,
#backstage .wizardFooter {
	background: none;
}

.viewer td, .viewer tr, .twtable td, .twtable tr {
	border: 1px solid #eee;
}

#backstage .inlineList ul li {
	background-color: [[ColorPalette::Background]];
	border: solid 1px [[ColorPalette::TertiaryMid]];
	display: block;
	float: left;
	list-style: none;
	margin-right: 1em;
	padding: 0.5em;
}

.backstageClear, .inlineList form {
	clear: both;
	display: block;
	margin-top: 3em;
}

.tiddlyspaceMenu {
	text-align: center;
}

span.chunkyButton {
	display: inline-block;
	padding: 0;
	margin: 0;
	border: solid 2px #000;
	background-color: #04b;
}

span.chunkyButton a.button, span.chunkyButton a:active.button {
	white-space: nowrap;
	font-weight: bold;
	font-size: 1.8em;
	color: #fff;
	text-align: center;
	padding: 0.5em 0.5em;
	margin: 0;
	border-style: none;
	display: block;
}

span.chunkyButton:hover {
	background-color: #014;
}

span.chunkyButton a.button:hover {
	border-style: none;
	background: none;
	color: #fff;
}

#backstage .unpluggedSpaceTab .wizard,
.unpluggedSpaceTab .wizard {
	background: white;
	border: 2px solid #CCC;
	padding: 5px;
}

.syncKey .keyItem {
	border: 1px solid black;
	display: inline-block;
	margin: 0.2em;
	padding: 0.1em 0.1em 0.1em 0.1em;
}

.keyHeading {
	font-size: 2em;
	font-weight: bold;
	margin: 0.4em 0em -0.2em;
}

.unpluggedSpaceTab .putToServer,
.unpluggedSpaceTab .notChanged {
	display: none;
}

.tiddlyspaceMenu ul {
	margin: 0;
	padding: 0;
}

.tiddlyspaceMenu ul li {
	list-style: none;
}

.unsyncedChanges .unsyncedList {
	display: block;
}

.unsyncedList {
	display: none;
}
!Code
***/
//{{{
(function ($) {
    var name = "StyleSheet" + tiddler.title;
    config.shadowTiddlers[name] = "/*{{{*/\n%0\n/*}}}*/".
        format(store.getTiddlerText(tiddler.title + "##StyleSheet")); // this accesses the StyleSheet section of the current tiddler (the plugin that contains it)
    store.addNotification(name, refreshStyles);

    if (!config.extensions.tiddlyweb.status.tiddlyspace_version) { // unplugged
        config.extensions.tiddlyweb.status.tiddlyspace_version = "<unknown>";
        config.extensions.tiddlyweb.status.server_host = {
            url:config.extensions.tiddlyweb.host }; // TiddlySpaceLinkPlugin expects this
    }
    var disabled_tasks_for_nonmembers = ["tiddlers", "plugins", "batch", "sync"];

    var tweb = config.extensions.tiddlyweb;
    var tiddlyspace = config.extensions.tiddlyspace;
    var currentSpace = tiddlyspace.currentSpace.name;
    var imageMacro = config.macros.image;

    if (config.options.chkBackstage === undefined) {
        config.options.chkBackstage = false;
    }

// Set up Backstage
    config.tasks = {};
    config.tasks.status = {
        text:"status",
        tooltip:"TiddlySpace Info",
        content:"<<tiddler Backstage##Menu>>"
    };
    config.tasks.tiddlers = {
        text:"tiddlers",
        tooltip:"tiddlers control panel",
        content:"<<tiddler Backstage##BackstageTiddlers>>"
    };
    config.tasks.plugins = {
        text:"plugins",
        tooltip:"Manage installed plugins",
        content:"<<tiddler Backstage##Plugins>>"
    };
    config.tasks.batch = {
        text:"batch",
        tooltip:"Batch manage public/private tiddlers",
        content:"<<tiddler Backstage##BatchOps>>"
    };
    config.tasks.tweaks = {
        text:"tweaks",
        tooltip:"Tweak TiddlyWiki behaviors",
        content:"<<tiddler Backstage##Tweaks>>"
    };
    config.tasks.exportTiddlers = {
        text:"import/export",
        tooltip:"Import/export tiddlers from/to a TiddlyWiki",
        content:"<<tiddler Backstage##ImportExport>>"
    };
    config.tasks.sync = {
        text:"sync",
        tooltip:"Check Sync status",
        content:"<<tiddler Backstage##SpaceUnplugged>>"
    };

    if (window.location.protocol === "file:") {
        config.unplugged = true;
    }

    config.backstageTasks = ["status", "tiddlers", "plugins",
        "batch", "tweaks", "exportTiddlers", "sync"];

    config.messages.backstage.prompt = "";
// initialize state
    var _show = backstage.show;
    backstage.show = function () {
        // selectively hide backstage tasks and tabs based on user status
        var tasks = $("#backstageToolbar .backstageTask").show();
        var bs = backstage.tiddlyspace;
        if (!config.unplugged) {
            tweb.getUserInfo(function (user) {
                if (user.anon) {
                    jQuery.each(disabled_tasks_for_nonmembers, function (i, task) {
                        var taskIndex = config.backstageTasks.indexOf(task);
                        if (taskIndex !== -1) {
                            config.backstageTasks.splice(taskIndex, 1);
                        }
                    });
                    config.messages.memberStatus = bs.locale.loggedout;
                } else {
                    config.messages.memberStatus = readOnly ?
                        bs.locale.nonmember : bs.locale.member;
                }
            });
        } else {
            config.messages.memberStatus = bs.locale.unplugged;
        }

        // display backstage
        return _show.apply(this, arguments);
    };
    if (readOnly) {
        jQuery.each(disabled_tasks_for_nonmembers, function (i, task) {
            var taskIndex = config.backstageTasks.indexOf(task);
            if (taskIndex !== -1) {
                config.backstageTasks.splice(taskIndex, 1);
            }
        });
    }

    var tasks = config.tasks;
    var commonUrl = "/bags/common/tiddlers/%0";

    backstage.tiddlyspace = {
        locale:{
            member:"You are a member of this space.",
            nonmember:"You are not a member of this space.",
            loggedout:"You are currently logged out of TiddlySpace.",
            unplugged:"You are unplugged."
        },
        showButton:function () {
            var showBtn = $("#backstageShow")[0];
            var altText = $(showBtn).text();
            $(showBtn).empty();
            imageMacro.renderImage(showBtn, "backstage.svg",
                { altImage:commonUrl.format("backstage.png"), alt:altText});
        },
        hideButton:function () {
            var hideBtn = $("#backstageHide")[0];
            var altText = $(hideBtn).text();
            $(hideBtn).empty();
            imageMacro.renderImage(hideBtn, "close.svg",
                { altImage:commonUrl.format("close.png"), alt:altText, width:24, height:24 });
        }
    };

    var _init = backstage.init;
    backstage.init = function () {
        _init.apply(this, arguments);
        var init = function (user) {
            var bs = backstage.tiddlyspace;
            bs.showButton();
            bs.hideButton();
        };
        tweb.getUserInfo(init);
    };

    var home = config.macros.homeLink = {
        locale:{
            linkText:"your home space"
        },
        handler:function (place) {
            var container = $("<span />").appendTo(place)[0];
            tweb.getUserInfo(function (user) {
                if (!user.anon && user.name !== currentSpace) {
                    createSpaceLink(container, user.name, null, home.locale.linkText);
                }
            });
        }
    };

    config.macros.exportSpace = {
        handler:function (place, macroName, params) {
            var filename = params[0] ||
                "/tiddlers.wiki?download=%0.html".format(currentSpace);
            $('<a class="button">download</a>').// XXX: i18n
                attr("href", filename).appendTo(place);
        }
    };

}(jQuery));
//}}}
/***
|''Name''|RevisionsCommandPlugin|
|''Description''|provides access to tiddler revisions|
|''Author''|FND|
|''Contributors''|Martin Budden|
|''Version''|0.3.3|
|''Status''|@@beta@@|
|''Source''|http://svn.tiddlywiki.org/Trunk/association/plugins/RevisionsCommandPlugin.js|
|''CodeRepository''|http://svn.tiddlywiki.org/Trunk/association/plugins/|
|''License''|[[BSD|http://www.opensource.org/licenses/bsd-license.php]]|
|''CoreVersion''|2.6.0|
|''Keywords''|serverSide|
!Usage
Extend [[ToolbarCommands]] with {{{revisions}}}.
!Revision History
!!v0.1 (2009-07-23)
* initial release (renamed from experimental ServerCommandsPlugin)
!!v0.2 (2010-03-04)
* suppressed wikification in diff view
!!v0.3 (2010-04-07)
* restored wikification in diff view
* added link to side-by-side diff view
!To Do
* strip server.* fields from revision tiddlers
* resolve naming conflicts
* i18n, l10n
* code sanitizing
* documentation
!Code
***/
//{{{
(function($) {

jQuery.twStylesheet(".diff { white-space: pre, font-family: monospace }",
	{ id: "diff" });

var cmd = config.commands.revisions = {
	type: "popup",
	hideShadow: true,
	text: "revisions",
	tooltip: "display tiddler revisions",
	revTooltip: "", // TODO: populate dynamically?
	loadLabel: "loading...",
	loadTooltip: "loading revision list",
	selectLabel: "select",
	selectTooltip: "select revision for comparison",
	selectedLabel: "selected",
	compareLabel: "compare",
	linkLabel: "side-by-side view",
	revSuffix: " [rev. #%0]",
	diffSuffix: " [diff: #%0 #%1]",
	dateFormat: "YYYY-0MM-0DD 0hh:0mm",
	listError: "revisions could not be retrieved",

	handlePopup: function(popup, title) {
		title = this.stripSuffix("rev", title);
		title = this.stripSuffix("diff", title);
		var tiddler = store.getTiddler(title);
		var type = _getField("server.type", tiddler);
		var adaptor = new config.adaptors[type]();
		var limit = null; // TODO: customizable
		var context = {
			host: _getField("server.host", tiddler),
			workspace: _getField("server.workspace", tiddler)
		};
		var loading = createTiddlyButton(popup, cmd.loadLabel, cmd.loadTooltip);
		var params = { popup: popup, loading: loading, origin: title };
		adaptor.getTiddlerRevisionList(title, limit, context, params, this.displayRevisions);
	},

	displayRevisions: function(context, userParams) {
		removeNode(userParams.loading);
		if(context.status) {
			var callback = function(ev) {
				var e = ev || window.event;
				var revision = resolveTarget(e).getAttribute("revision");
				context.adaptor.getTiddlerRevision(tiddler.title, revision, context,
					userParams, cmd.displayTiddlerRevision);
			};
			var table = createTiddlyElement(userParams.popup, "table");
			for(var i = 0; i < context.revisions.length; i++) {
				var tiddler = context.revisions[i];
				var row = createTiddlyElement(table, "tr");
				var timestamp = tiddler.modified.formatString(cmd.dateFormat);
				var revision = tiddler.fields["server.page.revision"];
				var cell = createTiddlyElement(row, "td");
				createTiddlyButton(cell, timestamp, cmd.revTooltip, callback, null,
					null, null, { revision: revision });
				cell = createTiddlyElement(row, "td", null, null, tiddler.modifier);
				cell = createTiddlyElement(row, "td");
				createTiddlyButton(cell, cmd.selectLabel, cmd.selectTooltip,
					cmd.revisionSelected, null, null, null,
					{ index:i, revision: revision, col: 2 });
				cmd.context = context; // XXX: unsafe (singleton)!?
			}
		} else {
			$("<li />").text(cmd.listError).appendTo(userParams.popup);
		}
	},

	revisionSelected: function(ev) {
		var e = ev || window.event;
		e.cancelBubble = true;
		if(e.stopPropagation) {
			e.stopPropagation();
		}
		var n = resolveTarget(e);
		var index = n.getAttribute("index");
		var col = n.getAttribute("col");
		while(!index || !col) {
			n = n.parentNode;
			index = n.getAttribute("index");
			col = n.getAttribute("col");
		}
		cmd.revision = n.getAttribute("revision");
		var table = n.parentNode.parentNode.parentNode;
		var rows = table.childNodes;
		for(var i = 0; i < rows.length; i++) {
			var c = rows[i].childNodes[col].firstChild;
			if(i == index) {
				if(c.textContent) {
					c.textContent = cmd.selectedLabel;
				} else {
					c.text = cmd.selectedLabel;
				}
			} else {
				if(c.textContent) {
					c.textContent = cmd.compareLabel;
				} else {
					c.text = cmd.compareLabel;
				}
				c.onclick = cmd.compareSelected;
			}
		}
	},

	compareSelected: function(ev) {
		var e = ev || window.event;
		var n = resolveTarget(e);
		var context = cmd.context;
		context.rev1 = n.getAttribute("revision");
		context.rev2 = cmd.revision;
		context.tiddler = context.revisions[n.getAttribute("index")];
		context.format = "unified";
		context.adaptor.getTiddlerDiff(context.tiddler.title, context,
			context.userParams, cmd.displayTiddlerDiffs);
	},

	displayTiddlerDiffs: function(context, userParams) {
		var tiddler = context.tiddler;
		tiddler.title += cmd.diffSuffix.format([context.rev1, context.rev2]);
		tiddler.text = "{{diff{\n" + context.diff + "\n}}}";
		tiddler.tags = ["diff"];
		tiddler.fields.doNotSave = "true"; // XXX: correct?
		if(!store.getTiddler(tiddler.title)) {
			store.addTiddler(tiddler);
		}
		var src = story.getTiddler(userParams.origin);
		var tiddlerEl = story.displayTiddler(src, tiddler);
		var uri = context.uri.replace("format=unified", "format=horizontal");
		var link = $('<a target="_blank" />').attr("href", uri).text(cmd.linkLabel);
		$(".viewer", tiddlerEl).prepend(link);
	},

	displayTiddlerRevision: function(context, userParams) {
		var tiddler = context.tiddler;
		tiddler.title += cmd.revSuffix.format([tiddler.fields["server.page.revision"]]);
		tiddler.fields.doNotSave = "true"; // XXX: correct?
		if(!store.getTiddler(tiddler.title)) {
			store.addTiddler(tiddler);
		}
		var src = story.getTiddler(userParams.origin);
		story.displayTiddler(src, tiddler);
	},

	stripSuffix: function(type, title) {
		var str = cmd[type + "Suffix"];
		var i = str.indexOf("%0");
		i = title.indexOf(str.substr(0, i));
		if(i != -1) {
			title = title.substr(0, i);
		}
		return title;
	}
};

var _getField = function(name, tiddler) {
	return tiddler.fields[name] || config.defaultCustomFields[name];
};

})(jQuery);
//}}}
/***
|''Description''|Sanitisation for dynamically pulling tiddlers into your space and displaying them|
!Notes
Works both inside and outside TiddlyWiki. Uses the HTML Sanitizer provided by the Google Caja project
(see http://code.google.com/p/google-caja/wiki/JsHtmlSanitizer for more on this), which is licensed under
an Apache License (see http://www.apache.org/licenses/LICENSE-2.0).
!Code
***/
//{{{
(function($) {

var cleanURL = function(url) {
	var regexp = /^(?:http|https|mailto|ftp|irc|news):\/\//;
	return (regexp.test(url)) ? url : null;
};

$.sanitize = function(html) {
	return html_sanitize(html, cleanURL);
};

/*
 * HTML Sanitizer, provided by Google Caja
 */

/* Copyright Google Inc.
 * Licensed under the Apache Licence Version 2.0
 * Autogenerated at Tue May 17 17:39:24 BST 2011
 * @provides html4
 */var html4={};html4.atype={NONE:0,URI:1,URI_FRAGMENT:11,SCRIPT:2,STYLE:3,ID:4,IDREF:5,IDREFS:6,GLOBAL_NAME:7,LOCAL_NAME:8,CLASSES:9,FRAME_TARGET:10},html4.ATTRIBS={"*::class":9,"*::dir":0,"*::id":4,"*::lang":0,"*::onclick":2,"*::ondblclick":2,"*::onkeydown":2,"*::onkeypress":2,"*::onkeyup":2,"*::onload":2,"*::onmousedown":2,"*::onmousemove":2,"*::onmouseout":2,"*::onmouseover":2,"*::onmouseup":2,"*::style":3,"*::title":0,"a::accesskey":0,"a::coords":0,"a::href":1,"a::hreflang":0,"a::name":7,"a::onblur":2,"a::onfocus":2,"a::rel":0,"a::rev":0,"a::shape":0,"a::tabindex":0,"a::target":10,"a::type":0,"area::accesskey":0,"area::alt":0,"area::coords":0,"area::href":1,"area::nohref":0,"area::onblur":2,"area::onfocus":2,"area::shape":0,"area::tabindex":0,"area::target":10,"bdo::dir":0,"blockquote::cite":1,"br::clear":0,"button::accesskey":0,"button::disabled":0,"button::name":8,"button::onblur":2,"button::onfocus":2,"button::tabindex":0,"button::type":0,"button::value":0,"canvas::height":0,"canvas::width":0,"caption::align":0,"col::align":0,"col::char":0,"col::charoff":0,"col::span":0,"col::valign":0,"col::width":0,"colgroup::align":0,"colgroup::char":0,"colgroup::charoff":0,"colgroup::span":0,"colgroup::valign":0,"colgroup::width":0,"del::cite":1,"del::datetime":0,"dir::compact":0,"div::align":0,"dl::compact":0,"font::color":0,"font::face":0,"font::size":0,"form::accept":0,"form::action":1,"form::autocomplete":0,"form::enctype":0,"form::method":0,"form::name":7,"form::onreset":2,"form::onsubmit":2,"form::target":10,"h1::align":0,"h2::align":0,"h3::align":0,"h4::align":0,"h5::align":0,"h6::align":0,"hr::align":0,"hr::noshade":0,"hr::size":0,"hr::width":0,"iframe::align":0,"iframe::frameborder":0,"iframe::height":0,"iframe::marginheight":0,"iframe::marginwidth":0,"iframe::width":0,"img::align":0,"img::alt":0,"img::border":0,"img::height":0,"img::hspace":0,"img::ismap":0,"img::name":7,"img::src":1,"img::usemap":11,"img::vspace":0,"img::width":0,"input::accept":0,"input::accesskey":0,"input::align":0,"input::alt":0,"input::autocomplete":0,"input::checked":0,"input::disabled":0,"input::ismap":0,"input::maxlength":0,"input::name":8,"input::onblur":2,"input::onchange":2,"input::onfocus":2,"input::onselect":2,"input::readonly":0,"input::size":0,"input::src":1,"input::tabindex":0,"input::type":0,"input::usemap":11,"input::value":0,"ins::cite":1,"ins::datetime":0,"label::accesskey":0,"label::for":5,"label::onblur":2,"label::onfocus":2,"legend::accesskey":0,"legend::align":0,"li::type":0,"li::value":0,"map::name":7,"menu::compact":0,"ol::compact":0,"ol::start":0,"ol::type":0,"optgroup::disabled":0,"optgroup::label":0,"option::disabled":0,"option::label":0,"option::selected":0,"option::value":0,"p::align":0,"pre::width":0,"q::cite":1,"select::disabled":0,"select::multiple":0,"select::name":8,"select::onblur":2,"select::onchange":2,"select::onfocus":2,"select::size":0,"select::tabindex":0,"table::align":0,"table::bgcolor":0,"table::border":0,"table::cellpadding":0,"table::cellspacing":0,"table::frame":0,"table::rules":0,"table::summary":0,"table::width":0,"tbody::align":0,"tbody::char":0,"tbody::charoff":0,"tbody::valign":0,"td::abbr":0,"td::align":0,"td::axis":0,"td::bgcolor":0,"td::char":0,"td::charoff":0,"td::colspan":0,"td::headers":6,"td::height":0,"td::nowrap":0,"td::rowspan":0,"td::scope":0,"td::valign":0,"td::width":0,"textarea::accesskey":0,"textarea::cols":0,"textarea::disabled":0,"textarea::name":8,"textarea::onblur":2,"textarea::onchange":2,"textarea::onfocus":2,"textarea::onselect":2,"textarea::readonly":0,"textarea::rows":0,"textarea::tabindex":0,"tfoot::align":0,"tfoot::char":0,"tfoot::charoff":0,"tfoot::valign":0,"th::abbr":0,"th::align":0,"th::axis":0,"th::bgcolor":0,"th::char":0,"th::charoff":0,"th::colspan":0,"th::headers":6,"th::height":0,"th::nowrap":0,"th::rowspan":0,"th::scope":0,"th::valign":0,"th::width":0,"thead::align":0,"thead::char":0,"thead::charoff":0,"thead::valign":0,"tr::align":0,"tr::bgcolor":0,"tr::char":0,"tr::charoff":0,"tr::valign":0,"ul::compact":0,"ul::type":0},html4.eflags={OPTIONAL_ENDTAG:1,EMPTY:2,CDATA:4,RCDATA:8,UNSAFE:16,FOLDABLE:32,SCRIPT:64,STYLE:128},html4.ELEMENTS={a:0,abbr:0,acronym:0,address:0,applet:16,area:2,b:0,base:18,basefont:18,bdo:0,big:0,blockquote:0,body:49,br:2,button:0,canvas:0,caption:0,center:0,cite:0,code:0,col:2,colgroup:1,dd:1,del:0,dfn:0,dir:0,div:0,dl:0,dt:1,em:0,fieldset:0,font:0,form:0,frame:18,frameset:16,h1:0,h2:0,h3:0,h4:0,h5:0,h6:0,head:49,hr:2,html:49,i:0,iframe:4,img:2,input:2,ins:0,isindex:18,kbd:0,label:0,legend:0,li:1,link:18,map:0,menu:0,meta:18,nobr:0,noframes:20,noscript:20,object:16,ol:0,optgroup:0,option:1,p:1,param:18,pre:0,q:0,s:0,samp:0,script:84,select:0,small:0,span:0,strike:0,strong:0,style:148,sub:0,sup:0,table:0,tbody:1,td:1,textarea:8,tfoot:1,th:1,thead:1,title:24,tr:1,tt:0,u:0,ul:0,"var":0},html4.ueffects={NOT_LOADED:0,SAME_DOCUMENT:1,NEW_DOCUMENT:2},html4.URIEFFECTS={"a::href":2,"area::href":2,"blockquote::cite":0,"body::background":1,"del::cite":0,"form::action":2,"img::src":1,"input::src":1,"ins::cite":0,"q::cite":0},html4.ltypes={UNSANDBOXED:2,SANDBOXED:1,DATA:0},html4.LOADERTYPES={"a::href":2,"area::href":2,"blockquote::cite":2,"body::background":1,"del::cite":2,"form::action":2,"img::src":1,"input::src":1,"ins::cite":2,"q::cite":2};var html=function(a){function x(b,c,d){var e=[];w(function(b,e){for(var f=0;f<e.length;f+=2){var g=e[f],h=e[f+1],i=null,j;if((j=b+"::"+g,a.ATTRIBS.hasOwnProperty(j))||(j="*::"+g,a.ATTRIBS.hasOwnProperty(j)))i=a.ATTRIBS[j];if(i!==null)switch(i){case a.atype.NONE:break;case a.atype.SCRIPT:case a.atype.STYLE:h=null;break;case a.atype.ID:case a.atype.IDREF:case a.atype.IDREFS:case a.atype.GLOBAL_NAME:case a.atype.LOCAL_NAME:case a.atype.CLASSES:h=d?d(h):h;break;case a.atype.URI:h=c&&c(h);break;case a.atype.URI_FRAGMENT:h&&"#"===h.charAt(0)?(h=d?d(h):h,h&&(h="#"+h)):h=null;break;default:h=null}else h=null;e[f+1]=h}return e})(b,e);return e.join("")}function w(b){var c,d;return v({startDoc:function(a){c=[],d=!1},startTag:function(e,f,g){if(!d){if(!a.ELEMENTS.hasOwnProperty(e))return;var h=a.ELEMENTS[e];if(h&a.eflags.FOLDABLE)return;if(h&a.eflags.UNSAFE){d=!(h&a.eflags.EMPTY);return}f=b(e,f);if(f){h&a.eflags.EMPTY||c.push(e),g.push("<",e);for(var i=0,j=f.length;i<j;i+=2){var k=f[i],l=f[i+1];l!==null&&l!==void 0&&g.push(" ",k,'="',r(l),'"')}g.push(">")}}},endTag:function(b,e){if(d)d=!1;else{if(!a.ELEMENTS.hasOwnProperty(b))return;var f=a.ELEMENTS[b];if(!(f&(a.eflags.UNSAFE|a.eflags.EMPTY|a.eflags.FOLDABLE))){var g;if(f&a.eflags.OPTIONAL_ENDTAG)for(g=c.length;--g>=0;){var h=c[g];if(h===b)break;if(!(a.ELEMENTS[h]&a.eflags.OPTIONAL_ENDTAG))return}else for(g=c.length;--g>=0;)if(c[g]===b)break;if(g<0)return;for(var i=c.length;--i>g;){var h=c[i];a.ELEMENTS[h]&a.eflags.OPTIONAL_ENDTAG||e.push("</",h,">")}c.length=g,e.push("</",b,">")}}},pcdata:function(a,b){d||b.push(a)},rcdata:function(a,b){d||b.push(a)},cdata:function(a,b){d||b.push(a)},endDoc:function(a){for(var b=c.length;--b>=0;)a.push("</",c[b],">");c.length=0}})}function v(c){return function(d,e){d=String(d);var f=null,g=!1,h=[],j=void 0,l=void 0,m=void 0;c.startDoc&&c.startDoc(e);while(d){var n=d.match(g?t:u);d=d.substring(n[0].length);if(g){if(n[1]){var o=b(n[1]),p;if(n[2]){var q=n[3];switch(q.charCodeAt(0)){case 34:case 39:q=q.substring(1,q.length-1)}p=k(i(q))}else p=o;h.push(o,p)}else if(n[4]){l!==void 0&&(m?c.startTag&&c.startTag(j,h,e):c.endTag&&c.endTag(j,e));if(m&&l&(a.eflags.CDATA|a.eflags.RCDATA)){f===null?f=b(d):f=f.substring(f.length-d.length);var r=f.indexOf("</"+j);r<0&&(r=d.length),l&a.eflags.CDATA?c.cdata&&c.cdata(d.substring(0,r),e):c.rcdata&&c.rcdata(s(d.substring(0,r)),e),d=d.substring(r)}j=l=m=void 0,h.length=0,g=!1}}else if(n[1])c.pcdata&&c.pcdata(n[0],e);else if(n[3])m=!n[2],g=!0,j=b(n[3]),l=a.ELEMENTS.hasOwnProperty(j)?a.ELEMENTS[j]:void 0;else if(n[4])c.pcdata&&c.pcdata(n[4],e);else if(n[5]&&c.pcdata)switch(n[5]){case"<":c.pcdata("&lt;",e);break;case">":c.pcdata("&gt;",e);break;default:c.pcdata("&amp;",e)}}c.endDoc&&c.endDoc(e)}}function s(a){return a.replace(m,"&amp;$1").replace(n,"&lt;").replace(o,"&gt;")}function r(a){return a.replace(l,"&amp;").replace(n,"&lt;").replace(o,"&gt;").replace(p,"&#34;").replace(q,"&#61;")}function k(a){return a.replace(j,g)}function i(a){return a.replace(h,"")}function g(a,b){return f(b)}function f(a){a=b(a);if(c.hasOwnProperty(a))return c[a];var f=a.match(d);if(f)return String.fromCharCode(parseInt(f[1],10));if(!!(f=a.match(e)))return String.fromCharCode(parseInt(f[1],16));return""}var b;"script"==="SCRIPT".toLowerCase()?b=function(a){return a.toLowerCase()}:b=function(a){return a.replace(/[A-Z]/g,function(a){return String.fromCharCode(a.charCodeAt(0)|32)})};var c={lt:"<",gt:">",amp:"&",nbsp:"240",quot:'"',apos:"'"},d=/^#(\d+)$/,e=/^#x([0-9A-Fa-f]+)$/,h=/\0/g,j=/&(#\d+|#x[0-9A-Fa-f]+|\w+);/g,l=/&/g,m=/&([^a-z#]|#(?:[^0-9x]|x(?:[^0-9a-f]|$)|$)|$)/gi,n=/</g,o=/>/g,p=/\"/g,q=/\=/g,t=new RegExp("^\\s*(?:(?:([a-z][a-z-]*)(\\s*=\\s*(\"[^\"]*\"|'[^']*'|(?=[a-z][a-z-]*\\s*=)|[^>\"'\\s]*))?)|(/?>)|[\\s\\S][^a-z\\s>]*)","i"),u=new RegExp("^(?:&(\\#[0-9]+|\\#[x][0-9a-f]+|\\w+);|<!--[\\s\\S]*?-->|<!\\w[^>]*>|<\\?[^>*]*>|<(/)?([a-z][a-z0-9]*)|([^<&>]+)|([<&>]))","i");return{escapeAttrib:r,makeHtmlSanitizer:w,makeSaxParser:v,normalizeRCData:s,sanitize:x,unescapeEntities:k}}(html4),html_sanitize=html.sanitize

// stop here if we're not in TiddlyWiki
// XXX: is this the correct way of checking for TiddlyWiki?
if (!window.TiddlyWiki || !window.store || !store instanceof TiddlyWiki) {
	return;
}

var tiddlyspace = config.extensions.tiddlyspace;

var _subWikify = Wikifier.prototype.subWikify;

var cleanedTitle = 'This section has been cleaned of any potentially harmful code';

var replaceFunctions = {
	html: function(w) {
		var sanitizedHTML, spanEl;
		this.lookaheadRegExp.lastIndex = w.matchStart;
		var lookaheadMatch = this.lookaheadRegExp.exec(w.source);
		if(lookaheadMatch && lookaheadMatch.index == w.matchStart) {
			sanitizedHTML = $.sanitize(lookaheadMatch[1]);
			spanEl = createTiddlyElement(w.output, 'span', null, 'sanitized');
			spanEl.innerHTML = sanitizedHTML;
			spanEl.setAttribute('title', cleanedTitle);
			w.nextMatch = this.lookaheadRegExp.lastIndex;
		}
	},
	customFormat: function(w) {
		switch(w.matchText) {
			case '@@':
				var e = createTiddlyElement(w.output, 'span');
				var styles = config.formatterHelpers.inlineCssHelper(w);
				if (styles.length === 0) {
					e.className = 'marked';
				}
				w.subWikifyTerm(e, /(@@)/mg);
				break;
			case '{{':
				var lookaheadRegExp = /\{\{[\s]*([\w]+[\s\w]*)[\s]*\{(\n?)/mg;
				lookaheadRegExp.lastIndex = w.matchStart;
				var lookaheadMatch = lookaheadRegExp.exec(w.source);
				if(lookaheadMatch) {
					w.nextMatch = lookaheadRegExp.lastIndex;
					e = createTiddlyElement(w.output,lookaheadMatch[2] == "\n" ? "div" : "span",null,lookaheadMatch[1]);
					w.subWikifyTerm(e,/(\}\}\})/mg);
				}
				break;
		}
	}
};

Wikifier.prototype.subWikify = function(output, terminator) {
	var tid = this.tiddler,
		spaceName = tiddlyspace.currentSpace.name,
		tidSpace, recipeName, stripped;
	try {
		recipeName = tid.fields['server.recipe'] ||
			tid.fields['server.workspace'];
		tidSpace = tiddlyspace.resolveSpaceName(recipeName);
		if (tidSpace !== spaceName) {
			// external tiddler, so replace dangerous formatters
			stripped = stripHTML(tid, this.formatter);
		}
	} catch(e) {
		// do nothing. There's no tiddler, so assume it's safe (?!?!?)
	}

	_subWikify.apply(this, arguments);

	if (stripped) {
		// change back to the original function
		unstripHTML(stripped, this.formatter);
	}
};

// replace potentially unsafe formatters with versions that strip bad HTML/CSS
var stripHTML = function(tid, formatter) {
	var popped = {}, _handler;
	for (var i = 0; i < formatter.formatters.length; i++) {
		var f = formatter.formatters[i];
		if (replaceFunctions[f.name]) {
			_handler = f.handler;
			popped[f.name] = _handler;
			f.handler = replaceFunctions[f.name];
		}
	};

	return popped;
};

// put the original formatters back where they belong
var unstripHTML = function(stripped, formatter) {
	for (var i = 0; i < formatter.formatters.length; i++) {
		var f = formatter.formatters[i];
		if (stripped[f.name]) {
			f.handler = stripped[f.name];
		}
	};
};

})(jQuery);
//}}}
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
Application Programming Interface
The interface that an application, module or sub-system exposes to be used from its outside.
----
@@color:#c4d6ed; ^^
Description: Application Programming Interface
^^@@
<!--{{{-->
<link rel="shortcut icon" href="/recipes/acarvalho_public/tiddlers/favicon.ico" />
<link href="/bags/acarvalho_public/tiddlers.atom" rel="alternate"
	type="application/atom+xml" title="acarvalho's public feed" />
<link rel="canonical" href="http://acarvalho.tiddlyspace.com/" />
<!--}}}-->
Strong [[cohesion|Cohesion]] and loose [[coupling|Coupling]] are a good thing in software design. On defining a good structure for your namespaces you will also be preventing "spaghetti coupling" and, to some extent, weak cohesion.

Coupling is not easy to [[refactor|Refactor]] as it involves moving code (and files) around. This usually messes up [[CVS]] and has large impact specially on reused code. This shall encourage you to clearly think ahead and establish your namespace coupling rules.

<<Image "FR" "250" "Coupling-root-level.png" "https://dl.dropbox.com/" "s/vfki4dkx343k4ut/" "?dl=1" "Root level allowed dependencies.">>

Your [[Meta-architecture]] shall address the Coupling control strategy by establishing clear rules about allowed dependencies between your namespaces.

Start at ''root level'' and define the allowed dependencies. Remember that you want your project's code to depend from your reusable code and both of them to depend from third-parties. Of course the inverse is not allowed as you want to keep reusable elements decoupled from specializations.



<<Image "FR" "250" "Coupling-reusable-code.png" "https://dl.dropbox.com/" "s/ayuutnc6sl4bha3/" "?dl=1" "Reusable code allowed dependencies.">>
Inside ''reusable code'' you shall promote a dependency hierarchy where the more specialized can depend from the more generic. Remember that your goal is to reduce reuse obstacles to the minimum possible.
See [[Namespace and Filesystem Guidelines]] for a rationale of the FRW, CMP and SYS division and [[Namespace Code Placement Guidelines]]. Of course you may use other if that makes more sense in your scenario.
Notice also that the same conceptual module (for instance ~ErrorHandling) may, and probably shall, have instances at different generalization layers (one generic instance in CMP to deal with basic catching and display and one more specialized instance at FRW that introduces context analysis for instance).





<<Image "FR" "250" "Coupling-tier-level.png" "https://dl.dropbox.com/" "s/hu07f3mq7229uce/" "?dl=1" "Tier level allowed dependencies.">>
Finally you shall consider to keep a strict ''tier level'' separation. Remember that tier level exists everywhere except on ~ThirdParties (and even here we could consider to implement it as second level). Again it is essential to promote a [[modularization|Modularization]] that favours reuse.
A conceptual module (for instance ~ErrorHandling at the component CMP layer) may have physical modules at ''Common'', ''Server'' and ''Client'' tiers (the catching code at Common and the dialogue for user display at Client and eventual server-only code at Server ).


----
See also : [[Namespace and Filesystem Guidelines]], [[Namespace Code Placement Guidelines]] and [[Promoting Reuse by Reference]]
----
@@color:#c4d6ed; ^^
Description: Guidelines for namespace coupling control.
^^@@
<!DOCTYPE html>
<html>
<head>
    <title>@tivity</title>
    <link rel="stylesheet" type="text/css"
    href="/bags/common/tiddlers/reset.css">
    <link rel="stylesheet" type="text/css"
    href="http://tiddlyspace.com/bags/tivity-extra_public/tiddlers/activity.css">
</head>
<body>
    <div id="message"></div>
    <div class="box">
        <h1 title="from spaces you follow">&#9634;</h1>
        <ul id="bbox" class="tiddlers"></ul>
    </div>
    <div class="box">
        <h1 title="tagged for you">@</h1>
        <ul id="atbox" class="tiddlers"></ul>
    </div>
    <div class="box">
        <h1 title="from your friends">&#x263A;</h1>
        <ul id="fbox" class="tiddlers"></ul>
    </div>
    <div class="box">
        <h1 title="from everybody">&#x221E;</h1>
        <ul id="upbox" class="tiddlers"></ul>
    </div>
    <div id="sizer">M</div>
    <div id="more">
        <input type="text" id="newsub" value="#tag, +modifier or @space">
        <button id="addsub">+</button>
    </div>
</body>
<script src="/bags/common/tiddlers/jquery.js"></script>
<script src="http://tiddlyspace.com/bags/tivity-extra_public/tiddlers/jquery.timeago.js"></script>
<script src="/status.js"></script>
<script src="http://tiddlyspace.com/bags/tivity-extra_public/tiddlers/tiddlersocket.js"></script>
<script src="http://tiddlyspace.com/bags/tivity-extra_public/tiddlers/activity.js"></script>
</html>

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
! Display and Navigation Options

//Display and navigation options for this space//

<<option chkEnableTabsBar>> Tabbed navigation
<<option chkShowBreadcrumbs>> Show Breadcrumbs
<<option chkSinglePageMode>> Display one tiddler at a time
><<option chkSinglePagePermalink>> Automatically permalink current tiddler
><<option chkSinglePageKeepFoldedTiddlers>> Don't close tiddlers that are folded
><<option chkSinglePageKeepEditedTiddlers>> Don't close tiddlers that are being edited
<<option chkTopOfPageMode>> Open tiddlers at the top of the page
<<option chkBottomOfPageMode>> Open tiddlers at the bottom of the page
<<option chkSinglePageAutoScroll>> Automatically scroll tiddler into view (if needed)

----
@@color:#c4d6ed; ^^
Description: Display and navigation options for this space
^^@@
/***
|''Name''|BinaryTiddlersPlugin|
|''Description''|renders base64-encoded binary tiddlers as images or links|
|''Author''|FND|
|''Version''|0.3.2|
|''Status''|@@beta@@|
|''Source''|http://svn.tiddlywiki.org/Trunk/association/plugins/BinaryTiddlersPlugin.js|
|''License''|[[BSD|http://www.opensource.org/licenses/bsd-license.php]]|
|''CoreVersion''|2.5|
!Code
***/
//{{{
(function($) {

"use strict";

var ctfield = "server.content-type";

var plugin = config.extensions.BinaryTiddlersPlugin = {
	isWikiText: function(tiddler) {
		var ctype = tiddler.fields[ctfield];
		if(ctype) {
			if (ctype === 'text/x-tiddlywiki') {
				return true;
			}
			return !this.isBinary(tiddler) && !this.isTextual(ctype);
		} else {
			return true;
		}
	},
	// NB: pseudo-binaries are considered non-binary here
	isBinary: function(tiddler) {
		var ctype = tiddler.fields[ctfield];
		return ctype ? !this.isTextual(ctype) : false;
	},
	isTextual: function(ctype) {
		return ctype.indexOf("text/") === 0
			|| this.endsWith(ctype, "+xml")
			|| ctype === 'application/json'
			|| ctype === 'application/javascript';
	},
	endsWith: function(str, suffix) {
		return str.length >= suffix.length &&
			str.substr(str.length - suffix.length) === suffix;
	},
	isLink: function(tiddler) {
		return this.isBinary(tiddler) && tiddler.text.indexOf("<html>") !== -1;
	}
};

// Disable edit for linked tiddlers (for now)
// This will be changed to a GET then PUT
config.commands.editTiddler.isEnabled = function(tiddler) {
    var existingTest = config.commands.editTiddler.isEnabled;
    if (existingTest) {
        return existingTest && !plugin.isLink(tiddler);
    } else {
        return !plugin.isLink(tiddler);
    }
};

// hijack text viewer to add special handling for binary tiddlers
var _view = config.macros.view.views.wikified;
config.macros.view.views.wikified = function(value, place, params, wikifier,
		paramString, tiddler) {
	var ctype = tiddler.fields["server.content-type"];
	if(params[0] === "text" && ctype && ctype !== 'text/x-tiddlywiki' &&
			!tiddler.tags.contains("systemConfig") && !plugin.isLink(tiddler)) {
		var el;
		if(plugin.isBinary(tiddler)) {
			var uri = "data:%0;base64,%1".format([ctype, tiddler.text]); // TODO: fallback for legacy browsers
			if(ctype.indexOf("image/") === 0) {
				el = $("<img />").attr("alt", tiddler.title).attr("src", uri);
			} else {
				el = $("<a />").attr("href", uri).text(tiddler.title);
			}
		} else {
			el = $("<pre />").text(tiddler.text);
		}
		el.appendTo(place);
	} else {
		_view.apply(this, arguments);
	}
};

// hijack edit macro to disable editing of binary tiddlers' body
var _editHandler = config.macros.edit.handler;
config.macros.edit.handler = function(place, macroName, params, wikifier,
		paramString, tiddler) {
	if(params[0] === "text" && plugin.isBinary(tiddler)) {
		return false;
	} else {
		_editHandler.apply(this, arguments);
	}
};

// hijack autoLinkWikiWords to ignore binary tiddlers
var _autoLink = Tiddler.prototype.autoLinkWikiWords;
Tiddler.prototype.autoLinkWikiWords = function() {
	return plugin.isWikiText(this) ? _autoLink.apply(this, arguments) : false;
};

}(jQuery));
//}}}
/***
|''Name''|ImageMacroPlugin|
|''Version''|0.9.4|
|''Description''|Allows the rendering of svg images in a TiddlyWiki|
|''Author''|Osmosoft|
|''License''|[[BSD|http://www.opensource.org/licenses/bsd-license.php]]|
|''Notes''|Currently only works in modern browsers (not IE)|
|''Requires''|BinaryTiddlersPlugin|
!Usage
{{{<<image SVG>>}}} will render the text of the tiddler with title SVG as an SVG image (but not in ie where it will fail silently)
!!Parameters
width/height: specify width/height parameters
link: make the image link to a given location
tiddlyLink: link to a tiddler

!Notes
Binary tiddlers in TiddlyWeb when passed through the wikifier will be shown as images.
eg. {{{<<view text wikified>>}}} on a binary tiddler will show the image.
{{{<<view fieldname image>>}}}
will render the value of the tiddler field 'fieldname' as an image. This field can contain a tid
{{{<<image SiteIcon>>}}}
will create an image tag where the tiddler has content type beginning image and not ending +xml
will attempt to create svg object in other scenarios
{{{<<image /photos/x.jpg>>}}}
will create an image tag with src /photos/x.jpg as long as there is not a tiddler called /photos/x.jpg in 
which case it will render that tiddler as an image. Note for the case of svg files it will attempt to render as an svg if possible via the image
tag. It doesn't embed the svg in the dom for security reasons as svg code can contain javascript.
!Code
***/
//{{{
(function($) {

var macro = config.macros.image = {
	shim: "/bags/common/tiddlers/shim",
	ieVersion: config.browser.isIE ? parseInt(config.browser.ieVersion[1], 10) : false,
	svgns: "http://www.w3.org/2000/svg",
	xlinkns: "http://www.w3.org/1999/xlink", 
	svgAvailable: document.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#BasicStructure", "1.1"),
	_fixPrefix: 1,
	_external_cache: {},
	_image_tag_cache: {},
	_image_dimensions: {},
	locale: {
		badImage: "This image cannot be displayed."
	},
	handler: function(place, macroName, params, wikifier, paramString, tiddler){
		var imageSource = params[0];
		// collect named arguments
		var args = macro.getArguments(paramString, params);
		this.renderImage(place, imageSource, args);
	},
	init: function() {
		var startupImages = store.getTaggedTiddlers("systemImage");
		var place = $("<div />").attr("id", "systemImageArea").appendTo("body").hide()[0];
		for(var i = 0; i < startupImages.length; i++) {
			var image = startupImages[i];
			macro.renderImage(place, image.title, { idPrefix: "" });
		}
		var data = new Image();
		data.onload = function() {
			// note ie 8 only supports data uris up to 32k so cannot be relied on
			macro.supportsDataUris = this.width != 1 || this.height != 1 ? false : true;
			macro.supportsDataUris = macro.ieVersion && macro.ieVersion < 9 ? false : macro.supportsDataUris;
		};
		data.onerror = data.onload;
		data.src = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==";
	},
	refreshImage: function(src) {
		var elements = macro._image_tag_cache[src] ? macro._image_tag_cache[src] : [];
		if(macro._image_dimensions[src]) {
			macro._image_dimensions[src] = false;
		}
		for(var i = 0; i < elements.length; i++) {
			var el = $(elements[i]);
			var newSrc = "%0?nocache=%1".format(src, Math.random());
			el.attr("src", newSrc); // force reload
		}
	},
	isBinaryImageType: function(contentType) {
		return (contentType && contentType.indexOf("image") === 0 &&
			contentType.indexOf("+xml") != contentType.length - 4) ? true : false;
	},
	isImageTiddler: function(tiddler) {
		return macro.isSVGTiddler(tiddler) || macro.isBinaryImageTiddler(tiddler);
	},
	isSVGTiddler: function(tiddler) {
		var type = tiddler ? tiddler.fields['server.content-type'] : false;
		return type == "image/svg+xml";
	},
	isBinaryImageTiddler: function(tiddler) {
		return macro.isBinaryImageType(tiddler.fields['server.content-type']);
	},
	renderImage: function(place, imageSource, options) {
		var imageTiddler = store.getTiddler(imageSource);
		var container;
		var classes = ["image"];
		if(options.link) {
			classes = classes.concat(["imageLink", "externalLink"]);
			container = $("<a />").attr("href", options.link).appendTo(place)[0];
		} else if(options.tiddlyLink) {
			classes.push("imageLink");
			container = createTiddlyLink(place, options.tiddlyLink, false);
		} else {
			container = $("<span />").appendTo(place)[0];
		}
		$(container).addClass(classes.join(" "));

		options = options ? options : {};
		if(imageTiddler && macro.isBinaryImageTiddler(imageTiddler)) { // handle the case where we have an image url
			return macro._renderBinaryImageTiddler(container, imageTiddler, options);
		} else if(imageTiddler){ // handle the case where we have a tiddler
			return macro._renderSVGTiddler(container, imageTiddler, options);
		} else { // we have a string representing a url
			return macro._renderBinaryImageUrl(container, imageSource, options);
		}
	},
	_renderAlternateText: function(container, options) {
		var img;
		var src = options.src || "";
		if(options.width && options.height) {
			img = $("<img />").attr("src", src).addClass("svgImageText").attr("width", options.width).
				attr("height", options.height).appendTo(container);
		}
		var alt = options.alt;
		if(img && alt) {
			img.attr("alt", alt).attr("title", alt);
		} else if(alt) {
			$(container).addClass("svgImageText").text(alt);
		}
		macro._image_tag_cache[src] = img;
	},
	_renderSVGTiddler: function(place, tiddler, options) {
		if(!options) {
			options = {};
		}
		merge(options, { tiddler: tiddler, fix: true});

		if(macro.svgAvailable) {
			this._importSVG(place, options); // display the svg
		} else if(options.altImage) {
			var image = options.altImage;
			delete options.altImage;
			this._renderBinaryImageUrl(place, image, options);
		} else {
			this._renderAlternateText(place, options); // instead of showing the image show the alternate text.
		}
	},
	_renderBinaryImageTiddler: function(place, tiddler, options) {
		var resourceURI;
		var fields = tiddler.fields;
		if(fields["server.type"] == "tiddlyweb") { // construct an accurate url for the resource
			resourceURI = "%0/%1/tiddlers/%2".format(config.defaultCustomFields["server.host"],
				fields["server.workspace"], encodeURI(fields["server.title"]));
		} else { // guess the url for the resource
			resourceURI = tiddler.title;
		}
		var ctype = fields["server.content-type"] || tiddler.type;
		var text = tiddler.text;
		if(macro.supportsDataUris && ctype && text.indexOf("<html") == -1) {
			var uri = "data:%0;base64,%1".format(ctype, text);
			options.src = resourceURI;
			return macro._renderBinaryImageUrl(place, uri, options);
		} else if(options.src) {
			return macro._renderBinaryImageUrl(place, options.src, options);
		} else {
			return macro._renderBinaryImageUrl(place, resourceURI, options);
		}
	},
	_renderImageTag: function(container, src, width, height, options) {
		var img;
		img = $("<img />").appendTo(container);
		if(height) {
			img.attr("height", height);
		}
		if(width) {
			img.attr("width", width);
		}
		if(macro.ieVersion && macro.ieVersion < 7 && macro.shim && options.ie6png) {
			$(img).css({width: userW, height: userH,
					filter: "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='%0', sizingMethod='scale')".format(src)
				}).attr("src", macro.shim);
		} else {
			img.attr("src", src);
		}
		if(!macro._image_tag_cache[options.srcUrl]) {
			macro._image_tag_cache[options.srcUrl] = [];
		}
		img = $(img).addClass(options.imageClass)[0];
		macro._image_tag_cache[options.srcUrl].push(img);
		return img;
	},
	_getDimensions: function(realDimensions, reqDimensions, preserve) {
		var w = realDimensions.width;
		var h = realDimensions.height;
		var reqh = reqDimensions.height;
		var reqw = reqDimensions.width;
		var finalw = w, finalh = h;
		var ratiow = reqw / w, ratioh = reqh / h;
		var scaledw = ratioh * w;
		var scaledh = ratiow * h;
		if(!reqw && reqh) {
			finalw = scaledw;
			finalh = reqh;
		} else if(reqw && !reqh) {
			finalw = reqw;
			finalh = scaledh;
		} else if(reqh && reqw) {
			var preserveWidth = w > h ? true : false;
			if(preserve) {
				if(preserveWidth && scaledh < reqh) {
					finalh = scaledh;
					finalw = reqw;
				} else {
					finalh = reqh;
					finalw = scaledw;
				}
			} else {
				finalw = reqw;
				finalh = reqh;
			}
		}
		return { width: parseInt(finalw, 10), height: parseInt(finalh, 10) };
	},
	_renderBinaryImageUrl: function(container, src, options) {
		var srcUrl = options.src ? options.src : src;
		srcUrl = srcUrl.indexOf("/") === -1 ? "/%0".format(srcUrl) : srcUrl; // for IE. 
		var image_dimensions = macro._image_dimensions[srcUrl];
		var image = new Image(); // due to weird scaling issues where you use just a width or just a height
		var createImageTag = function(dimensions, error) {
			if(error) {
				var altImage = options.altImage;
				if(altImage) {
					delete options.altImage;
					macro._renderBinaryImageUrl(container, altImage, options);
				} else {
					options.src = src;
					macro._renderAlternateText(container, options);
				}
			} else {
				var dim = macro._getDimensions(dimensions, { 
					width: options.width, height: options.height }, options.preserveAspectRatio);
				options.srcUrl = srcUrl;
				macro._renderImageTag(container, src, dim.width, dim.height, options);
			}
		};

		if(!image_dimensions) {
			image.onload = function() {
				var dimensions = { width: image.width, height: image.height};
				macro._image_dimensions[srcUrl] = dimensions;
				createImageTag(dimensions);
			};
			image.onerror = function() {
				createImageTag(null, true);
			};
			image.src = src;
		} else {
			createImageTag(image_dimensions);
		}
	},
	_generateIdPrefix: function(){
		return "twsvgfix_" + (this._fixPrefix++).toString() + "_";
	},
	_fixSVG: function(childNodes, idPrefix) {
		var urlPattern = /url\(\#([^\)]*)\)*/ig;
		var fixes = [
		{ attr: "id", pattern: /^(.*)$/ig },
		{ attr: "href", namespace: macro.xlinkns, pattern: /^#(.*)$/ig }
		];
		var url_fixes = ["filter", "fill", "mask", "stroke", "style"];
		for(var i = 0; i < url_fixes.length; i++) {
			fixes.push({ attr: url_fixes[i], pattern: urlPattern });
		}
		for(var t = 0; t < childNodes.length; t++) {
			var node = childNodes[t];
			for(var a = 0; a < fixes.length; a++) {
				var fix = fixes[a];
				var attr = fix.attr;
				var ns = fix.namespace || "";
				if(node.hasAttributeNS && node.hasAttributeNS(ns, attr)) {
					var v = node.getAttributeNS(ns, attr);
					fix.pattern.lastIndex = 0;
					var match = fix.pattern.exec(v);
					if(match) {
						// Make sure replacement string doesn't contain any single dollar signs
						var toReplace = match[1];
						if(toReplace.indexOf(idPrefix) !== 0 && toReplace.indexOf("twglobal_") !== 0) {
							var replacement = (idPrefix + toReplace).replace("$", "$$$$"); 
							v = v.replace(match[1], replacement);
						}
						node.setAttributeNS(ns, attr,v);
					}
				}
			}
			var children = node.childNodes;
			if(children.length > 0) {
				this._fixSVG(children, idPrefix);
			}
		}
	},
	_importSVG: function(place, options){
		options = options ? options : {};
		var svgDoc, tiddlerText = options.tiddler.text;
		if (window.DOMParser) {
			svgDoc = new DOMParser().parseFromString(tiddlerText, "application/xml").documentElement;
			var idPrefix = options.idPrefix || this._generateIdPrefix();
			this._fixSVG([svgDoc], idPrefix);
			var el = document.importNode(svgDoc, true);
			var svgHolder = document.createElementNS(macro.svgns,"svg");
			var width = options.width;
			var height = options.height;
			if(width || height) {
				if(width && height) { // set view box of containing svg element based on the svg viewbox and width and height.
					var viewBox = el.getAttribute("viewBox");
					var topLeft = "0 0";
					if(viewBox) {
						topLeft = viewBox.replace(/([0-9]*) +([0-9]*) +([0-9]*) +([0-9]*) */gi,"$1 $2");
					}
					svgHolder.setAttributeNS(macro.svgns, "viewBox", "0 0 %0 %1".format(width, height));
				} else {
					if(!width) {
						width = el.getAttribute("width");
					}
					if(!height) {
						height = el.getAttribute("height");
					}
				}
				svgHolder.setAttribute("width", width);
				svgHolder.setAttribute("height", height);

				el.setAttribute("width", "100%");
				el.setAttribute("height", "100%");
				svgHolder.setAttribute("class", "svgImage svgIcon %0".format(options.imageClass || ""));
				svgHolder.appendChild(el);
				place.appendChild(svgHolder);
			}
			else {
				var existing = el.className ? el.className.baseVal : "";
				el.setAttribute("class","svgImage %0".format(existing));
				place.appendChild(el);
			}
			// if a tiddler attribute is set this is read as a link
			$("[tiddler], [tiddlyLink]", place).attr("refresh", "link").click(function(ev) {
				var tiddler = $(ev.target).attr("tiddlyLink");
				if(tiddler) {
					story.displayTiddler(ev.target, tiddler);
				}
			});
		}
	},
	getArguments: function(paramString, params) {
		var args = paramString.parseParams("name", null, true, false, true)[0];
		var options = {};
		for(var id in args) {
			if(true) {
				var p = args[id];
				if(id == "def") {
					options[id] = p;
				} else {
					options[id] = p[0];
				}
			}
		}
		var width = isNaN(params[1]) ? false : parseInt(params[1], 10);
		var height = isNaN(params[2]) ? false : parseInt(params[2], 10);

		options.width = macro.lookupArgument(options, "width", width);
		options.height = macro.lookupArgument(options, "height", height);
		options.preserveAspectRatio = args.preserveAspectRatio && 
			args.preserveAspectRatio[0] == "yes" ? true : false;
		options.tiddlyLink = macro.lookupArgument(options, "tiddlyLink", false);
		options.link = macro.lookupArgument(options, "link", false);
		return options;
	},
	lookupArgument: function(args, id, ifEmpty) {
		return args[id] ? args[id] : ifEmpty;
	}
};

// update views
var _oldwikifiedview = config.macros.view.views.wikified;
// update wikifier to check tiddler type before rendering
merge(config.macros.view.views, {
	wikified: function(value, place, params, wikifier, paramString, tiddler) {
		if(macro.isImageTiddler(tiddler) && params[0] == "text") {
			var newplace = $("<div />").addClass("wikifiedImage").appendTo(place)[0];
			macro.renderImage(newplace, tiddler.title, { alt: macro.locale.badImage });
		} else {
			_oldwikifiedview.apply(this, arguments);
		}
	},
	image: function(value, place, params, wikifier, paramString, tiddler) {
		// a field can point to another tiddler whereas text is the current tiddler.
		var title = params[0] == "text" ? tiddler.title : value;
		var args = macro.getArguments(paramString, params);
		macro.renderImage(place, title, args);
	}
});
config.shadowTiddlers.StyleSheetImageMacro = [".wikifiedImage svg, .wikifiedImage .image { width: 80%; }",
	".svgImageText { background-color:[[ColorPalette::Error]]; color:#ddd; display: inline-block; }",
	"span.svgImageText { display: inline-block; overflow: hidden; }"
].join("");
store.addNotification("StyleSheetImageMacro", refreshStyles);

})(jQuery);
//}}}
http://acarvalho.tiddlyspace.com
Concurrent Versioning System methods and tools play a fundamental role in [[Configuration Management]] and may be decisive in your efforts to achieve [[Systematic Reuse]]. In fact, choosing the wrong method may be one of the major [[Reuse Obstacles]].

No professional software development may be carried on without a Concurrent Versioning System (CVS) and CVS is a major part of Configuration Management.

A CVS is a centralized repository (software and hardware) that holds the digital artefacts  used and produced during development (source code, documents, designs, etc.). In this perspective it may be seen as a filesystem. 
The ''Versioning'' part, however, introduces a new requirement that most filesystems do not provide : version management, that is, the preservation and identification of the several versions that changes to an artefact produce along its lifecycle and also the versioning of a sub-system or the system as a whole in order to present a coherent set of its artefacts in a given moment. This introduces us to __tag__ and __revision__ concepts.
The ''Concurrent'' part introduces the needs of team development in concurrent access to the artefacts and points us to __reserved editing or lock__, __branch__, __compare__ and __merge__ functionalities.

It must be said that there are several methodological approaches to use such a system. They are determined, mainly, by the exploration environment intended. An open source, widely participated and with loose governance project shall not be dealt with in the same manner as a professional team development project, also, a professional project, in a [[Systematic Reuse]] environment, presents challenges and needs that are not the same as the ones of a pure "project oriented" project.

Many people will say that you can do everything you need with any modern [[CVS]] system. Maybe that's true, but some systems are more suitable for some scenarios and, here (at professional team development), suitability means efficiency, time and money. Choosing the right methodological approach for concurrent versioning for your scenario means that you will save a lot in unnecessary effort, avoid shortcuts, hacks or "//solutions//" that impair your Company's strategic goals, like [[Systematic Reuse]], and also prevent frustration in your team. Version management shall not add effort to your projects, it shall reduce it. See also [[Reuse oriented CVS]].

In my opinion, nowadays, many people is choosing the wrong approaches and tools for [[CVS]] just because the more recent major products in the area emerged from wide open-source environments and, naturally, target those environments primarily, although they "//can also be used//" in professional, team based, environments. The older ones, team and project oriented, are so old (CVS launched in 1990, CVSNT in 1998) that they might even not have bugs any more… but also they are not so glamorous any more...

The first thing to take into account is that, in professional development, not all versioned artefacts are code, some projects may even not have code artefacts at all. This puts aside all methodologies based on the assumed mergeability of versioned artefacts. Modern project's artefacts are code, generated code, [[CASE]] tool's files, documents, binaries, images and anything else you can think of.

A professional team [[CVS]] shall :
# Allow ''reserved edit'' working mode. Not so much to forbid concurrent editing, but to notify us that someone else is editing the artefact __before__ we do change it. Merges are, many times, impossible and, most of the times, difficult.
# Allow ''checkout read-only'' files to prevent environments, like MS Visual Studio, from inadvertently change files without the user knowledge. This produces merge nightmares.
# Use a ''sequential, predictable, revision identifier per file''. This is very important if you want, for instance, that your documents refer their [[CVS]] revision on their content (and yes, this is quite useful, and mandatory on most mature [[Configuration Management]] processes).
# Have a ''tag system'' that can work in a single branch or across branches. This is essential to promote [[Systematic Reuse]] with real code sharing and collaborative improvement. Tags must be overwrite able in order to allow to update a tag in a single file to another revision of that file. This is very important for the process agility in controlled environments. Imagine a test release with a simple, self-contained show stopper bug, do you want to repeat the entire release process? Imagine a self-contained correction or improvement ([[Refactoring|Refactor]]) in a reused module, do you want to make all dependent projects to perform merges or revalidation of your entire reuse framework?
# Have ''branching capability'' and also the ability to transform a tag into a branch. This is important for reuse in order to allow projects to start by reusing "as-is" and then, when needed and if needed, to adapt to the project's needs.
# ''Artefact renaming and moving'' is also an important feature. [[Refactoring|Refactor]], [[Continuous Improvement]] and [[Emergent Reuse]] are enough to ask for it.
# Availability of a ''stand-alone client'' is essential, as said, you are not working with code only, nor the project's context is the [[IDE]] context only.

----
Back to [[High Maturity Practices]]
----
/%
@@color:#c4d6ed; ^^
Description: Concurrent Versioning Systems discussion
^^@@
%/
/*{{{*/
Background: #dce8f8
Foreground: #061222
PrimaryPale: #fafcfe
PrimaryLight: #c4d6ed
PrimaryMid: #4878b6
PrimaryDark: #4a4e53
SecondaryPale: #fefdfa
SecondaryLight: #ede3c4
SecondaryMid: #b69c48
SecondaryDark: #53514a
TertiaryPale: #fefbfa
TertiaryLight: #edd3c4
TertiaryMid: #b67048
TertiaryDark: #534d4a
Error: #f88
ColorPaletteParameters: HSL([214|12], [0.67|0.53|0.43|0.06],[0.31|0.5|0.85|0.99])
/*}}}*/
Unless you're delighted with the default theme you can make some quick changes by generating a new random color palette, hit this button to cycle through some alternatives.

<<RandomColorPaletteButton saturation_pale:0.67 saturation_light:0.53
saturation_mid:0.43 saturation_dark:0.06 pale:0.99 light:0.85 mid:0.5 dark:0.31>>

You can also change the look and feel completely by installing a new theme. To do this, find one you like in the @themes space, note down the name, and include it in this space by going to the space menu. You can reach the space menu by clicking on the blue and pink circle at the top-right of the page and chooshing "THIS SPACE". Here are a few to check out:
* @pip
* @caspian-ii
* @basalt
* @simplicity
* @cheesecake
* @jelly-doughnut

(//Note that if you are using a custom TiddlySpace install, these themes may not be present.//)
----
@@color:#c4d6ed; ^^
Description: following http://docs.tiddlyspace.com
^^@@
<<Image "FR" "125" "250px-Mozambique_(orthographic_projection).svg.png" "http://upload.wikimedia.org/" "wikipedia/commons/thumb/8/84/Mozambique_(orthographic_projection).svg/" "" "Mozambique">>
[[Mozambique|http://en.wikipedia.org/wiki/Mozambique]] is a beautiful country with very nice people and great food. 

<<Image "FL" "300" "Dao.jpg" "https://dl.dropbox.com/" "s/5ohjd1mw0c2kpa0/" "?dl=1" "Dao - Maputo">>
<<Image "FL" "300" "Fishing.jpg" "https://dl.dropbox.com/" "s/pniyd8l8emo1cm1/" "?dl=1" "Fishing - Maputo">>













[[South Africa|http://en.wikipedia.org/wiki/South_Africa]] Seems also nice but I've only had the chance to know a little of the fabulous [[Kruger Park|http://www.krugerpark.co.za/]]. 
<<Image "FR" "125" "250px-South_Africa_%28orthographic_projection%29.svg.png" "http://upload.wikimedia.org/" "wikipedia/commons/thumb/6/6e/South_Africa_%28orthographic_projection%29.svg/" "" "South Africa">>
This is wild life as it is meant to be. Free, happy and alive animals in all their glory.
<<Image "FL" "300" "Gazele.jpg" "https://dl.dropbox.com/" "s/8b5ntg4y5f8b3ga/" "?dl=1" "Gazele - Kruger Park">> <<Image "FR" "125" "kruger-nav-map_r10_c1_s1.gif" "http://www.krugerpark.co.za/" "images/" "" "Kruger Park">>












----
@@color:#c4d6ed; ^^
Description: Two great weeks in Mozambique and South Africa
^^@@
Software Development Process tailoring "//is an activity that adjusts an abstract set of processes and activities to the needs of a concrete project by selecting processes and activities and/or reducing (or enlarging) their complexity, frequency, etc.//"
[[Software Development Plan Tailoring : A Goal Oriented Strategy Proposal|https://dl.dropbox.com/s/p308qz0iwtnhvy8/Software%20Development%20Plan%20Tailoring.pdf?dl=1]] by André de Carvalho, 2002 (draft 1)

“//Tailoring is a key element in the organization’s ability to develop reasonable and efficient software development plans for use in managing and controlling projects within the organization.//”
Process Tailoring and the Software Capability Maturity Model – CMU/~SEI-94-TR-024 – Mark P. Ginsberg, Lauren H. Quinn – 1995

----
@@color:#c4d6ed; ^^
Description: Software Development Process tailoring concept and references
^^@@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->

<svg
   xmlns:dc="http://purl.org/dc/elements/1.1/"
   xmlns:cc="http://creativecommons.org/ns#"
   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
   xmlns:svg="http://www.w3.org/2000/svg"
   xmlns="http://www.w3.org/2000/svg"
   xmlns:xlink="http://www.w3.org/1999/xlink"
   version="1.1"
   width="14pt"
   height="14pt"
   viewBox="918 510 14 14"
   id="svg3070">
  <metadata
     id="metadata3089">
    <rdf:RDF>
      <cc:Work
         rdf:about="">
        <dc:format>image/svg+xml</dc:format>
        <dc:type
           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
        <dc:title></dc:title>
      </cc:Work>
    </rdf:RDF>
  </metadata>
  <defs
     id="defs3072">
    <radialGradient
       cx="0"
       cy="0"
       r="1"
       id="Gradient"
       gradientUnits="userSpaceOnUse">
      <stop
         id="stop3075"
         style="stop-color:#ffffff;stop-opacity:1"
         offset="0" />
      <stop
         id="stop3077"
         style="stop-color:#2b2b2b;stop-opacity:1"
         offset="1" />
    </radialGradient>
    <radialGradient
       id="Obj_Gradient"
       xlink:href="#Gradient"
       gradientTransform="matrix(11.473944,0,0,11.473944,922.3752,513.7837)" />
  </defs>
  <g
     id="g3080"
     style="fill:none;stroke:none">
    <g
       id="g3082">
      <path
         d="m 929.6952,512.9018 c -2.5384,-2.53843 -6.654,-2.53843 -9.1924,0 -2.5384,2.5384 -2.5384,6.654 0,9.19238 2.5384,2.53839 6.654,2.53839 9.1924,0 2.5384,-2.53838 2.5384,-6.65398 0,-9.19238 m -4.5962,2.8407 2.07733,-2.07734 1.75547,1.75549 -2.0773,2.07735 2.0773,2.07732 -1.75547,1.75548 -2.07733,-2.07732 -2.07733,2.07732 -1.75547,-1.75548 2.0773,-2.07732 -2.0773,-2.07735 1.75547,-1.75549 z"
         id="path3084"
         style="fill:url(#Obj_Gradient)" />
      <path
         d="m 927.61447,515.38354 a 4.51205,4.2590378 0 1 1 -9.0241,0 4.51205,4.2590378 0 1 1 9.0241,0 z"
         transform="matrix(1.0218069,0,0,1.0462046,-18.063694,-21.648443)"
         id="path2394"
         style="fill:#000000;fill-opacity:0;fill-rule:evenodd;stroke:none;stroke-width:5;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
    </g>
  </g>
</svg>
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
<svg xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" height="100%" width="100%" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" viewBox="0 0 40 40"><metadata><rdf:RDF><cc:Work rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/><dc:title/></cc:Work></rdf:RDF></metadata><defs><linearGradient id="lG3826" x1="7.0996" gradientUnits="userSpaceOnUse" y1="18.829" gradientTransform="matrix(1.5858347,0,0,1.8078238,1098.1851,351.13716)" x2="1.5461" y2="-0.95166"><stop stop-color="#000" offset="0"/><stop stop-color="#9c9b99" offset="1"/></linearGradient><linearGradient id="lG3828" y2="372.44" gradientUnits="userSpaceOnUse" y1="375.7" x2="1111.7" x1="1097.7"><stop style="stop-color:#ac9393;" offset="0"/><stop style="stop-color:#c8b7b7;" offset="1"/></linearGradient></defs><g transform="translate(-1080.9375,-357.3329)"><path style="stroke-width:0;stroke-miterlimit:4;fill:url(#lG3826);" d="m1080.9,357.32,39.996-0.0426-0.01,40.008c-15.507-25.519-15.36-25.95-39.988-39.965z"/><path style="stroke-dashoffset:0;stroke:#7aa3be;stroke-linecap:round;stroke-miterlimit:4;stroke-width:1.49999988;fill:#c1e6fd;" d="m1091.9,363.55c6.5716-6.4925,16.576-7.3925,23.147-0.90003,6.5717,6.4925,6.5717,17.019,0,23.511-4.4424-8.6113-12.288-15.713-23.147-22.611z"/><path style="stroke-dashoffset:0;stroke:#ce81b0;stroke-linecap:round;stroke-miterlimit:4;stroke-width:1.5;fill:#f4c4e2;" d="m1110.2,367.62c3.217,3.2168,3.217,8.4323,0,11.649-3.8194-4.2357-8.3307-8.1824-11.649-11.649,3.217-3.2168,8.4325-3.2168,11.649-0.00002z"/><path style="stroke-linejoin:bevel;stroke:#000000;stroke-linecap:round;stroke-dasharray:none;stroke-miterlimit:4;stroke-width:0.80000001;fill:url(#lG3828);" d="m1081,357.34c18.79,6.4752,32.53,16.56,39.894,39.892-11.19-17.028-14.878-19.19-27.352-14.96,6.2984-12.098,3.9371-13.19-12.542-24.932z"/></g></svg>
Scope : Requirements and Features
<<Image "FR" "350" "EA%20Element%20Properties%20-%20Status%20and%20Version.jpg" "https://dl.dropbox.com/" "s/tjoknyicii3ssm9/" "?dl=1" "EA element properties dialog.">>
The following topics establish the versioning schema for Requirements and Features (and their included additional diagrams).
Notice that Version is, in this scope, closely related to [[Status|EA Usage - Attribute Status]].

Versioning of the Requirements and Features is not intended to provide baseline identification, that's the generated documents job. These versions are working versions and their purpose is to mark changes in specification against Customer or stakeholder formal or informal interactions, that is, if you informally validate a set of requirements with one stakeholder and then you make changes to some of them you want to be able to quickly list them in the next interaction with that stakeholder. Also if you have a set of requirements formally approved and after you update them to reflect implementation findings you also want to be able to build a list of changed requirements. In this last case the baseline is established by the generated document that the Customer approves and that is placed under Change Management and Version Control not by each requirement's version but you surly understand the utility of being able to tell what changed after that, think about revision and validation effort.

We propose that a major and minor version scheme be used like 1.2. The major version shall be incremented when a change occurs after any formal interaction with the Customer, that is, over any baselined item. The minor version shall be incremented when a change happens after an informal stakeholder validation.

----
See also : [[Sparx Enterprise Architect]]
/%
@@color:#c4d6ed; ^^
Description: Enterprise Architect attribute usage guideline - Version
^^@@
%/

Developing professional software needs tools, [[CASE]] software tools, but beware, a tool is just as good as the usage you make of it. Software development challenges are not solved by tools but tools may be useful in implementing the solutions you define for those challenges. The bottom line here is that you must have a method and then choose tools to help implementing it not the opposite. 

!!Concurrent Version Management
* [[CVS]] - This is the first area any professional software development must address. CVS and WinCVS are still my choice.
!!Modelling
*[[Sparx Enterprise Architect]] - is my primary tool and I try to make it the //Single Version of the Truth// in my specifications.
!!Prototyping
* [[Pencil]] - is an excellent [[GUI]] prototyping tool.
!!Information gathering
* Microsoft OneNote - is a tool I'm learning to like. It is quite useful for note-taking in meetings and interviews. It is also nice to be able to share it through DropBox.
----
/%
@@color:#c4d6ed; ^^
Description: A list of essential CASE software tools.
^^@@
%/
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xl="http://www.w3.org/1999/xlink" version="1.1" viewBox="506 234 68 36" width="30" height="30"><metadata xmlns:dc="http://purl.org/dc/elements/1.1/"><dc:date>2010-09-16 14:51Z</dc:date><!-- Produced by OmniGraffle Professional 5.2.3 --></metadata><defs></defs><g stroke="none" stroke-opacity="1" stroke-dasharray="none" fill="none" fill-opacity="1"><rect width="1118" height="783"/><g><path d="M 538.68195 244.31807 C 540.43927 246.07547 540.43927 248.9247 538.68195 250.68204 C 536.92456 252.4394 534.07532 252.4394 532.318 250.68204 C 530.5606 248.9247 530.5606 246.07547 532.318 244.31807 C 534.07532 242.56075 536.92456 242.56075 538.68195 244.31807 M 511.12607 257.99356 C 511.26108 258.13019 511.39728 258.26608 511.53473 258.40121 C 527.2556 273.86606 552.74414 273.86606 568.46515 258.40121 C 568.60248 258.26617 568.73853 258.13037 568.87354 257.9938 C 568.8736 257.99374 568.8736 257.99371 568.8736 257.99362 C 568.87366 257.99371 568.87366 257.9938 568.87372 257.9939 C 570.72504 256.12051 572.35046 254.11153 573.74994 252 C 573.74994 251.99997 573.74994 251.99994 573.74994 251.99992 C 572.35046 249.8884 570.72504 247.87938 568.87372 246.00606 C 568.87366 246.00613 568.87366 246.00621 568.8736 246.00627 C 568.73865 245.86966 568.60254 245.73383 568.46515 245.5987 C 552.74414 230.13387 527.2556 230.13387 511.53473 245.5987 C 511.39728 245.73383 511.26108 245.86974 511.12613 246.00635 C 511.126 246.00624 511.126 246.00616 511.12595 246.00606 C 509.2748 247.87938 507.64954 249.88837 506.24994 251.9998 L 506.24994 251.99983 C 506.24994 251.9999 506.25 251.99992 506.25 251.99997 C 506.25 252 506.24994 252.00005 506.24994 252.00009 L 506.24994 252.00012 C 507.64954 254.11157 509.2748 256.12051 511.12595 257.9939 C 511.126 257.99377 511.126 257.99365 511.12607 257.99359 Z M 515.44916 252 C 515.8548 251.55469 516.27502 251.11778 516.71014 250.68985 C 522.16632 245.32257 529.06055 242.23206 536.17273 241.41824 C 534.6662 241.96199 533.2525 242.83762 532.04498 244.04512 C 527.65155 248.43852 527.65155 255.56163 532.04498 259.95502 C 533.2522 261.16226 534.6656 262.03778 536.17175 262.58154 C 529.05988 261.76761 522.16608 258.6771 516.71014 253.31009 C 516.2751 252.88219 515.85486 252.44528 515.44922 252 Z M 564.55054 251.99995 C 564.14502 252.44525 563.7248 252.88217 563.28973 253.31009 C 557.83368 258.67712 550.93988 261.76764 543.828 262.58157 C 545.33423 262.03781 546.74756 261.1623 547.9549 259.95502 C 552.34833 255.56163 552.34833 248.43852 547.9549 244.04512 C 546.74744 242.83765 545.33374 241.96202 543.82715 241.41824 C 550.9394 242.23206 557.83356 245.3226 563.28973 250.68985 C 563.7248 251.11775 564.14502 251.55467 564.55054 251.99995 Z M 568.8736 257.99362 C 570.7249 256.12033 572.35028 254.11139 573.74988 252.00002" fill="black" class="glyph"/></g></g></svg>
/***
|Name|ContentTimelineMacro|
|Created by|Andre' de Carvalho|
|Date|12/04/2013|
|Location|http://acarvalho.tiddlyspace.com/#ContentTimelineMacro|
|Version|1.0.1|
|Type|Macro|
|Description|A TiddlyWiki Macro to show timelines (modified, created) for tiddlers tagged 'Content'|

!!Code
***/
{{{
version.extensions.ContentTimeline= {major: 1, minor: 0 , revision: 1, date: new Date(2013,4,12)};
}}}
{{{
config.macros.ContentTimeline={};
config.macros.ContentTimeline.dateFormat=config.macros.timeline.dateFormat;
config.macros.ContentTimeline.handler = function(place,macroName,params)
{
var field = params[0] ? params[0] : "modified";
var tiddlers = store.reverseLookup("tags","excludeLists",false,field);
var lastDay = "";
//var last = params[1] ? tiddlers.length-Math.min(tiddlers.length,parseInt(params[1])) : 0;
var count = params[1];
for(var t=tiddlers.length-1; t>=0; t--)
{
 var tiddler = tiddlers[t];
 if (!tiddler.isTagged("Content")) continue;
 
 count=count-1;
 if (count < 0) 
  {
   break;
  }
 var theDay = tiddler[field].convertToLocalYYYYMMDDHHMM().substr(0,8);
 if(theDay != lastDay)
  {
   var theDateList = document.createElement("ul");
   place.appendChild(theDateList);
   createTiddlyElement(theDateList,"li",null,"listTitle",tiddler[field].formatString(this.dateFormat));
   lastDay = theDay;
  }
 var theDateListItem = createTiddlyElement(theDateList,"li",null,"listLink");
 theDateListItem.appendChild(createTiddlyLink(place,tiddler.title,true));
 }
};
}}}
<<Image "FR" "350" "RUP-Elaboration.png" "https://dl.dropbox.com/" "s/wswkdlgwx5gdqpm/" "?dl=1" "This is the RUP vision of the Development Process.">>
Software Specification occurs mainly in the ''Elaboration Phase'' and encompasses :
* Software Requirements Specification (SRS)
* Software Architecture Specification (SAS)

----
Back to : [[Software Development Pattern]]
See also : [[Development Links]]
----
<<Image "FL" "" "logo-shadow.png" "http://pencil.evolus.vn/" "styling/images/" "" "">> <<Image "FR" "" "home-ss.jpg" "http://pencil.evolus.vn/" "images/" "" "">>
[[Pencil Project|http://pencil.evolus.vn/]] - //An open-source [[GUI]] prototyping tool that's available for ALL platforms. Pencil is built for the purpose of providing a free and open-source GUI prototyping tool that people can easily install and use to create mockups in popular desktop platforms.//


* [[Google Code stencil download page for Pencil|http://code.google.com/p/evoluspencil/downloads/list?q=label:Stencil]]. 
* [[Google Code template download page for Pencil|http://code.google.com/p/evoluspencil/downloads/list?q=label:Template]].

Pencil is a very useful tool for sketching GUI elements. These are a very important way of validating intended and expected user interaction.
----
See also : [[EA Usage - Alternate Image]]
----
/%
@@color:#c4d6ed; ^^
Description: Pencil - GUI modelling free and open-source tool
^^@@
%/
Concurrent Versioning System

See : [[Concurrent Versioning System]]
----
@@color:#c4d6ed; ^^
Description: Concurrent Versioning System.
^^@@
There are a lot of interesting people using ~TiddlySpace that you might like to keep track of and interact with. There are a number of ways of doing this.

If you see a number in the speech bubble in one of your tiddlers, it means that someone is writing about the same thing as you. You can find out what they're saying by clicking on it. Likewise, if you see something interesting in someone else's space, you can respond to it and write up your own thoughts on the subject by clicking "Reply to this tiddler".

Additionally, if you find anyone interesting, or you find an interesting looking space and you'd like to know when it's changed, you can "follow" that space. To do this, simply create a tiddler with the title: {{{@space-name}}} and tag it {{{follow}}}. If you want, you can store some notes about that space in the body of the tiddler.

If you then want to know what happening, simply [[include|How do I include/exclude spaces?]]@docs the @tivity space and then visit your activity stream at [[/activity|/activity]], or just visit the @tapas space directly.

!Not sure who to follow?
Here's a few suggestions:
* @fnd
* @cdent
* @pmario
* @bengillies
* @dickon
/***
|''Name''|TiddlySpaceFollowingPlugin|
|''Version''|0.7.1|
|''Description''|Provides a following macro|
|''Author''|Jon Robson|
|''Requires''|TiddlySpaceConfig TiddlySpaceTiddlerIconsPlugin ErrorHandler|
|''License''|[[BSD|http://www.opensource.org/licenses/bsd-license.php]]|
!Usage
Tag a tiddler with "follow" to express a list of followers.
Using the {{{<<followTiddlers X>>}}}
will reveal the number of tiddlers with name X in the set of spaces the *current* user viewing your space follows.
{{{<<following jon>>}}} will list all the users following Jon.
{{{<<followers jon>>}}} will list all the followers of jon.
{{{<linkedTiddlers>>}}} will list all tiddlers across TiddlySpace linked to the current tiddler
{{{<linkedTiddlers follow:yes>>}}} will list all tiddlers across TiddlySpace that come from your list of followers
adds spaceLink view type {{{<<view server.bag spaceLink>>}}} creates a link to the space described in server.bag
{{{<<view server.bag spaceLink title>>}}} makes a link to the tiddler with title expressed in the field title in space server.bag
If no name is given eg. {{{<<following>>}}} or {{{<<follow>>}}} it will default the current user.
!StyleSheet
.followTiddlersList li {
	list-style:none;
}

.followButton {
	width: 2em;
}

.followTiddlersList li .siteIcon {
	height:48px;
	width: 48px;
}

#sidebarTabs .followers li a,
.followers .siteIcon,
.followers .siteIcon div {
	display: inline;
}

.followTiddlersList li .externalImage, .followTiddlersList li .image {
	display: inline;
}

.scanResults li {
	list-style: none;
}
!Code
***/
//{{{
(function($) {
var LIMIT_FOLLOWING = 100;

var tweb = config.extensions.tiddlyweb;
var tiddlyspace = config.extensions.tiddlyspace;
var currentSpace = tiddlyspace.currentSpace.name;

var shadows = config.shadowTiddlers;
config.annotations.ScanTemplate = "This tiddler is the default template used in the display of tiddlers founding using the tsScan macro. To access attributes use the view macro e.g. {{{<<view title text>>}}}";
shadows.ScanTemplate = "<<view modifier SiteIcon width:24 height:24 spaceLink:yes label:no>> <<view title link>>";
shadows.FollowersTemplate = "<<view server.bag SiteIcon width:24 height:24 spaceLink:yes label:no>> <<view server.bag spaceLink>>";
shadows.FollowingTemplate = "<<view title SiteIcon width:24 height:24 spaceLink:yes label:no>> <<view title spaceLink>>";
shadows.FollowTiddlersBlackList = "";
shadows.FollowTiddlersHeading = "There are tiddlers in spaces you follow using the follow tag which use the title <<view title text>>";
shadows.FollowTiddlersTemplate = ["* <<view server.space SiteIcon width:24 height:24 spaceLink:yes label:no>> ",
	"<<view server.space spaceLink title external:no>> modified by <<view modifier spaceLink>> ",
	"in the <<view server.space spaceLink>> space (<<view modified date>> @ <<view modified date 0hh:0mm>>).\n"].join("");

var name = "StyleSheetFollowing";
shadows[name] = "/*{{{*/\n%0\n/*}}}*/".
	format(store.getTiddlerText(tiddler.title + "##StyleSheet"));
store.addNotification(name, refreshStyles);

// provide support for sucking in tiddlers from the server
tiddlyspace.displayServerTiddler = function(src, title, workspace, callback) {
	var adaptor = store.getTiddlers()[0].getAdaptor();
	var localTitle = tiddlyspace.getLocalTitle(title, workspace);
	var tiddler = new Tiddler(localTitle);
	tiddler.text = "Please wait while this tiddler is retrieved...";
	tiddler.fields.doNotSave = "true";
	store.addTiddler(tiddler);
	src = story.displayTiddler(src || null, tiddler.title);
	tweb.getStatus(function(status) {
		var context = {
			host: tweb.host, // TODO: inherit from source tiddler?
			workspace: workspace,
			headers: { "X-ControlView": "false" }
		};
		var getCallback = function(context, userParams) {
			var tiddler = context.tiddler;
			tiddler.title = localTitle;
			store.addTiddler(tiddler);
			story.refreshTiddler(localTitle, null, true); // overriding existing allows updating
			if(callback) {
				callback(src, tiddler);
			}
		};
		adaptor.getTiddler(title, context, null, getCallback);
	});
};

tiddlyspace.scroller = {
	runHandler: function(title, top, bottom, height) {
		var i;
		var handlers = tiddlyspace.scroller.handlers;
		var tidEl = story.getTiddler(title);
		if(tidEl) {
			var topEl = $(tidEl).offset().top + 20;
			if(top === false || (topEl > top && topEl < bottom)) {
				var h = handlers[title];
				for(i = 0; i < h.length; i++) {
					h[i]();
				}
				tiddlyspace.scroller.clearHandlers(title);
			}
		} else {
			tiddlyspace.scroller.clearHandlers(title);
		}
	},
	clearHandlers: function(title) {
		tiddlyspace.scroller.handlers[title] = [];
	},
	registerIsVisibleEvent: function(title, handler) {
		tiddlyspace.scroller.handlers[title] = tiddlyspace.scroller.handlers[title] || [];
		tiddlyspace.scroller.handlers[title].push(handler);
	},
	init: function() {
		this.handlers = {};
		this.interval = window.setInterval(function() {
			var top = $(window).scrollTop();
			var height = $(window).height();
			var bottom = top + height;
			var title;
			for(title in tiddlyspace.scroller.handlers) {
				if(title) {
					tiddlyspace.scroller.runHandler(title, top, bottom, height);
				}
			}
		}, 2000); // every 2 seconds check scroll position
	}
};
tiddlyspace.scroller.init();

var followMacro = config.macros.followTiddlers = {
	locale: {
		followListHeader: "Here are tiddlers from spaces you follow using the follow tag which use this title.",
		noTiddlersFromFollowers: "None of the spaces you follow contain a tiddler with this name.",
		errorMessage: "There was a problem retrieving tiddlers from the server. Please try again later."
	},
	init: function() {
		followMacro.lookup = {};
	},
	followTag: "follow",
	getHosts: function(callback) {
		tweb.getStatus(function(status) {
			callback(tweb.host, tiddlyspace.getHost(status.server_host, "%0"));
		});
	},
	getBlacklist: function() {
		return store.getTiddlerText("FollowTiddlersBlackList").split("\n");
	},
	handler: function(place, macroName, params, wikifier, paramString, tiddler) {
		var args = paramString.parseParams("anon")[0];
		var containingTiddler = story.findContainingTiddler(place).getAttribute('tiddler');
		var title = (args.anon && args.anon[0]) || tiddler.fields["server.title"] || tiddler.title;
		var tid = store.getTiddler(title);
		var user = params[1] || false;
		if(tid) {
			followMacro.makeButton(place, {
				url: "/search?q=title:%22" + encodeURIComponent(title) + "%22",
				containingTiddler: containingTiddler,
				blacklisted: followMacro.getBlacklist(), title: title, user: user,
				consultFollowRelationship: (args.follow &&
					args.follow[0] === 'false') ? false : true });
		}
	},
	makeButton: function(place, options) { // this is essentially the same code in TiddlySpaceFollowingPlugin
		var title = options.title;
		var blacklisted = options.blacklisted;
		var tiddler = store.getTiddler(title);
		var btn = $('<div class="followButton" />').addClass("notLoaded").appendTo(place)[0];
		if(blacklisted.contains(title)) {
			$(btn).remove();
			return;
		} else {
			var user = options.user;
			window.setTimeout(function() { // prevent multiple calls due to refresh
				tiddlyspace.scroller.registerIsVisibleEvent(options.containingTiddler, function() {
					var mkButton = function(followers, ignore) {
						if(!followers && !ignore) {
							$(btn).remove();
						} else {
							$("<a />").appendTo(btn);
							var scanOptions = { url: options.url,
								spaceField: options.spaceField || "bag", template: null, sort: "-modified",
								callback: function(tiddlers) {
									$(btn).removeClass("notLoaded");
									followMacro.constructInterface(btn, tiddlers);
								}
							};
							if(!ignore) {
								scanOptions.showBags = followMacro._getFollowerBags(followers);
							}
							scanOptions.hideBags = [tiddler.fields["server.bag"]];
							scanMacro.scan(null, scanOptions, user);
						}
					};
					if(options.consultFollowRelationship) {
						followMacro.getFollowers(mkButton);
					} else {
						mkButton([], true);
					}
				});
			}, 1000);
		}
	},
	constructInterface: function(container, tiddlers) {
		var txt = tiddlers.length;
		var className = txt > 0 ? "hasReplies" : "noReplies";
		var el = $(story.findContainingTiddler(container));
		$(container).empty().addClass(className);
		var btn = $("<a />").addClass("followedTiddlers").text(txt).
			click(function(ev) {
				followMacro.followingOnClick(ev);
			}).appendTo('<div class="followedTiddlers" />').appendTo(container)[0];
		$.data(btn, "tiddlers", tiddlers);
	},
	followingOnClick: function(ev) {
		var target = ev.target;
		var locale = followMacro.locale;
		var el = $('<div class="followTiddlersList" />')[0];
		var popup = Popup.create(target,"div");
		$(popup).addClass("taggedTiddlerList followList").click(function(ev) { // make it so only clicking on the document outside the popup removes the popup
			if(ev.target.parentNode != document) {
				ev.stopPropagation();
			}
		}).append(el);
		var tiddlers = $.data(target, "tiddlers") || [];
		scanMacro.template(el, tiddlers.slice(0,1), "FollowTiddlersHeading");
		scanMacro.template(el, tiddlers, "FollowTiddlersTemplate");
		if(tiddlers.length === 0) {
			$("<li />").text(locale.noTiddlersFromFollowers).appendTo(el);
		}
		Popup.show();
		ev.stopPropagation();
		return popup;
	},
	_getFollowerBags: function(followers) { // XXX: private or not?
		return $.map(followers, function(name, i) {
			return name != currentSpace ? "%0_public".format(name) : null;
		});
	},
	getFollowers: function(callback, username) {
		// returns a list of spaces being followed by the existing space
		var followersCallback = function(user) {
			if(!user.anon) {
				scanMacro.scan(null, { 
					url: "/search?q=bag:%0_public tag:%1 _limit:%2".format(user.name, followMacro.followTag, LIMIT_FOLLOWING),
					spaceField: "title", template: null, cache: true,
					callback: function(tiddlers) {
						var followers = [];
						for(var i = 0; i < tiddlers.length; i++) {
							followers.push(tiddlyspace.resolveSpaceName(tiddlers[i].title));
						}
						callback(followers);
					}
				});
			} else {
				callback(false);
			}
		};
		return !username ? tweb.getUserInfo(followersCallback) : followersCallback({ name: username });
	}
};

var scanMacro = config.macros.tsScan = {
	init: function () {
		this.scanned = {};
	},
	_tiddlerfy: function(jsontiddlers, options) {
		var tiddlers = [];
		var spaceField = options.spaceField || "bag"; // TODO: phase out use view types instead
		$.each(jsontiddlers, function(i, t) {
			var use = false;
			if(!options.showBags || (options.showBags && options.showBags.contains(t.bag))) {
				use = true;
			}
			if(options.hideBags && options.hideBags.contains(t.bag)) {
				use = false;
			}
			if(use) {
				var spaceName = t[spaceField];
				var tiddler = config.adaptors.tiddlyweb.toTiddler(t, tweb.host);
				tiddler.fields["server.space"] = tiddlyspace.resolveSpaceName(spaceName);
				tiddlers.push(tiddler);
			}
		});
		return tiddlers;
	},
	_scanCallback: function(place, jsontiddlers, options) {
		var locale = followersMacro.locale;
		var tiddlers = scanMacro._tiddlerfy(jsontiddlers, options);
		
		if(options.sort) {
			tiddlers = store.sortTiddlers(tiddlers, options.sort);
		}
		if(options.filter) {
			var _store = new TiddlyWiki();
			config.lastStore = _store;
			for(var i = 0; i < tiddlers.length; i++) {
				var clone = tiddlers[i];
				clone.title = tiddlyspace.getLocalTitle(clone.title, clone.fields['server.workspace']);
				_store.addTiddler(clone);
			}
			tiddlers = _store.filterTiddlers(options.filter);
		}
		if(place) {
			$(place).empty();
			var list = $("<ul />").appendTo(place)[0];
			scanMacro.template(list, tiddlers, options.template);
			if(tiddlers.length === 0) {
				$("<li />").text(options.emptyMessage || locale.noone).appendTo(list);
				$(list).addClass("emptyList");
			}
		}
		if(options.callback) {
			options.callback(tiddlers);
		}
	},
	constructSearchUrl: function(host, options) {
		if(options.url) {
			return options.url;
		}
		var inputs = options.searchValues;
		var tag = options.tag;
		var searchField = options.searchField || "title";
		var searchQuery = [];
		for(var i = 0; i < inputs.length; i++) {
			searchQuery.push('%0:"%1"'.format(searchField, inputs[i]));
		}
		var query = searchQuery.join(" OR ");
		query = tag ? "(%0) AND tag:%1".format(query, tag) : query;
		query = options.query ? "%0;%1;".format(query, options.query) : query;
		query = options.fat ? "%0&fat=1".format(query) : query;
		return '%0/search?q=%1'.format(host, query);
	},
	scan: function(place, options) { // TODO: make use of list macro with url filter
		var locale = followersMacro.locale;
		options.template = options.template ? options.template : "ScanTemplate";
		followMacro.getHosts(function(host, tsHost) {
			$(place).text(followersMacro.locale.pleaseWait);
			options = options ? options: {};
			var url = scanMacro.constructSearchUrl(host, options);
			if(options.cache && scanMacro.scanned[url]) {
				var tiddlers = scanMacro.scanned[url].tiddlers;
				var run = function(tiddlers) {
					scanMacro._scanCallback(place, tiddlers, options);
				};
				if(tiddlers) {
					run(tiddlers);
				} else {
					scanMacro.scanned[url].callbacks.push(run);
				}
			} else {
				var callback = function(tiddlers) {
					scanMacro._scanCallback(place, tiddlers, options);
				};
				if(scanMacro.scanned[url] && scanMacro.scanned[url].callbacks) {
					scanMacro.scanned[url].callbacks.push(callback);
				} else {
					scanMacro.scanned[url] = {
						callbacks: [callback]
					};
				}
				ajaxReq({
					url: url,
					dataType: "json",
					success: function(tiddlers) {
						scanMacro.scanned[url].tiddlers = tiddlers;
						var callbacks = scanMacro.scanned[url].callbacks;
						while(callbacks.length > 0) {
							callbacks.pop()(tiddlers);
						}
					},
					error: function(xhr) {
						$(place).empty();
						$("<span />").addClass("annotation error").text(locale.error.format(xhr.status)).appendTo(place);
					}
				});
			}
		});
	},
	template: function(place, tiddlers, template) { // TODO: make use of list macro.
		for(var i = 0; i < tiddlers.length; i++) {
			var tiddler = tiddlers[i];
			var item = $('<li class="spaceName" />').appendTo(place)[0];
			var spaceName = tiddler.fields["server.space"] || "";
			var templateText = store.getTiddlerText(template).replace(/\$1/mg, spaceName);
			wikify(templateText, item, null, tiddler);
		}
	},
	getOptions: function(paramString, tiddler) {
		var args = paramString.parseParams("name", null, true, false, true)[0];
		var options = { query: false, sort: false, tag: false, template: false, showBags: args.show || false,
			hideBags: args.hide || false, filter: false, spaceField: "bag", searchField: "title", fat: false,
			emptyMessage: false };
		for(var name in args) {
			if(name != "name") {
				if(name == "fat") {
					options[name] = true;
				} else {
					options[name] = args[name][0];
				}
			}
		}
		// if user has set searchField to modifier, then use the modifiers value if available otherwise use searchValues.
		var searchField = options.searchField;
		var searchValues = args[searchField] ? args[searchField] : args.searchValues;
		// if neither of those were used use the first parameter
		var defaultValues = tiddler ? [ tiddler.title ] : [];
		options.searchValues = searchValues ? searchValues : ( args.name ? [args.name[0]] : defaultValues);
		return options;
	},
	handler: function(place, macroName, params, wikifier, paramString, tiddler) {
		var container = $("<div />").addClass("scanResults resultsArea").appendTo(place)[0];
		var options = scanMacro.getOptions(paramString, tiddler);
		scanMacro.scan(container, options);
	}
};

var followersMacro = config.macros.followers = {
	locale: {
		loggedOut: "Please login to see the list of followers",
		noSupport: "We were unable to retrieve followers as your browser does not support following.",
		pleaseWait: "Please wait while we look this up...",
		error: "Error %0 occurred whilst retrieving data from server",
		noone: "None."
	},
	handler: function(place, macroName, params, wikifier, paramString, tiddler) {
		var locale = followersMacro.locale;
		var args = paramString.parseParams("name", null, true, false, true)[0];
		var username = args.name ? args.name[0] : false;
		var container = $('<div class="followers" />').text(locale.pleaseWait).
			appendTo(place)[0];
		var followersCallback = function(user) {
			if(user.anon) {
				$("<span />").text(locale.loggedOut).appendTo(container);
			} else {
				var options = scanMacro.getOptions(paramString);
				$.extend(options, {
					url: "/search?q=title:@%0 OR title:%0 tag:%1 _limit:%2".
						format(user.name, followMacro.followTag, LIMIT_FOLLOWING),
					spaceField: "bag",
					template: options.template ? options.template : "FollowersTemplate"
				});
				scanMacro.scan(container, options);
			}
		};
		return !username ? followersCallback({ name: currentSpace }) : followersCallback({ name: username });
	}
};

var followingMacro = config.macros.following = {
	locale: {
		pleaseWait: followersMacro.locale.pleaseWait,
		loggedOut: "Please login to see who you are following",
		noSupport: followersMacro.locale.noSupport,
		error: followersMacro.locale.error,
		noone: followersMacro.locale.noone
	},
	handler: function(place, macroName, params, wikifier, paramString, tiddler) {
		var locale = followingMacro.locale;
		var args = paramString.parseParams("name", null, true, false, true)[0];
		var fat = args.fat ? true : false;
		var username = args.name ? args.name[0] : false;
		var container = $('<div class="following" />').text(locale.pleaseWait).
			appendTo(place)[0];
		var followingCallback = function(user) {
			if(user.anon) {
				$("<span />").text(locale.loggedOut).appendTo(container);
			} else {
				var options = scanMacro.getOptions(paramString);
				$.extend(options, {
					url: "/search?q=bag:%0_public tag:%1 _limit:%2".format(user.name, followMacro.followTag, LIMIT_FOLLOWING),
					spaceField: "title",
					template: options.template ? options.template : "FollowingTemplate"
				});
				scanMacro.scan(container, options);
			}
		};
		return !username ? followingCallback({ name: currentSpace }) : followingCallback({ name: username });
	}
};

var linkedMacro = config.macros.linkedTiddlers = {
	handler: function(place, macroName, params, wikifier, paramString, tiddler) {
		var args = paramString.parseParams("anon")[0];
		var title = params[0] || tiddler.fields["server.title"] || tiddler.title;
		var tid = store.getTiddler(title);
		var containingTiddler = story.findContainingTiddler(place).getAttribute('tiddler');
		if(tid) {
			followMacro.makeButton(place, {
				spaceField: "recipe",
				url: "/bags/%0/tiddlers/%1/backlinks".format(tid.fields['server.bag'],
					encodeURIComponent(tid.title)),
				blacklisted: followMacro.getBlacklist(),
				title: title,
				containingTiddler: containingTiddler,
				user: params[1] || false,
				consultFollowRelationship: args.follow ? true : false });
		}
	}
};

if(config.options.chkFollowTiddlersIsLinkedTiddlers) {
	merge(config.macros.followTiddlers, config.macros.linkedTiddlers);
	config.shadowTiddlers.FollowTiddlersHeading = "These are the other tiddlers that link to this tiddler.";
}

})(jQuery);
//}}}
test
<<Image "FL" "300" "Coupling-root-level.png" "https://dl.dropbox.com/" "s/vfki4dkx343k4ut/" "?dl=1" "Root level allowed dependencies.">>


----
/***
|Name|BibRefMacro|
|Created by|Andre' de Carvalho|
|Location|http://acarvalho.tiddlyspace.com/#BibRefMacro|
|Version|1.0.0|
|Type|Macro|
|Description|A TiddlyWiki Macro to create links to anchors in a bibliography tiddler.|

!!Example
{{{<<BibRef "Parnas 1972">>}}}
<<BibRef "Parnas 1972">>
or
{{{<<BibRef Berard>>}}}
<<BibRef Berard>>

!!Installation
Import (or copy/paste) this tiddler into your document and tag it with "systemConfig". Change the wikify path to suit your bibliography page and anchor style ( I use SectionLinksPlugin ).

!!Code
***/
//{{{
version.extensions.BibRef= {major: 1, minor: 0 , revision: 0, date: new Date(2012,6,17)};
//Created by André de Carvalho
//}}}
//{{{
config.macros.BibRef = {};
config.macros.BibRef.handler= function(place,macroName,params) {
   var bref=params[0];
   wikify("[[["+bref+"]|BibliographyPage##"+bref+"]]",place)
};
//}}}
 
chkPrivateMode: false
txt_GATracker_id: UA-32849239-1
txt_GATracker_track: 1%2C1%2C1%2C1%2C0%2C0%2C0
/***
|''Name''|jit-yc|
***/
//{{{
/*
  Copyright (c) 2010, Nicolas Garcia Belmonte
  All rights reserved

  > Redistribution and use in source and binary forms, with or without
  > modification, are permitted provided that the following conditions are met:
  >      * Redistributions of source code must retain the above copyright
  >        notice, this list of conditions and the following disclaimer.
  >      * Redistributions in binary form must reproduce the above copyright
  >        notice, this list of conditions and the following disclaimer in the
  >        documentation and/or other materials provided with the distribution.
  >      * Neither the name of the organization nor the
  >        names of its contributors may be used to endorse or promote products
  >        derived from this software without specific prior written permission.
  >
  >  THIS SOFTWARE IS PROVIDED BY NICOLAS GARCIA BELMONTE ``AS IS'' AND ANY
  >  EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  >  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  >  DISCLAIMED. IN NO EVENT SHALL NICOLAS GARCIA BELMONTE BE LIABLE FOR ANY
  >  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  >  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  >  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  >  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  >  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  >  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 (function(){window.$jit=function(x){x=x||window;for(var y in $jit){if($jit[y].$extend){x[y]=$jit[y]}}};$jit.version="2.0.0b";var c=function(w){return document.getElementById(w)};c.empty=function(){};c.extend=function(y,w){for(var x in (w||{})){y[x]=w[x]}return y};c.lambda=function(w){return(typeof w=="function")?w:function(){return w}};c.time=Date.now||function(){return +new Date};c.splat=function(x){var w=c.type(x);return w?((w!="array")?[x]:x):[]};c.type=function(x){var w=c.type.s.call(x).match(/^\[object\s(.*)\]$/)[1].toLowerCase();if(w!="object"){return w}if(x&&x.$$family){return x.$$family}return(x&&x.nodeName&&x.nodeType==1)?"element":w};c.type.s=Object.prototype.toString;c.each=function(B,A){var z=c.type(B);if(z=="object"){for(var y in B){A(B[y],y)}}else{for(var x=0,w=B.length;x<w;x++){A(B[x],x)}}};c.indexOf=function(z,y){if(Array.indexOf){return z.indexOf(y)}for(var x=0,w=z.length;x<w;x++){if(z[x]===y){return x}}return -1};c.map=function(y,x){var w=[];c.each(y,function(A,z){w.push(x(A,z))});return w};c.reduce=function(A,y,x){var w=A.length;if(w==0){return x}var z=arguments.length==3?x:A[--w];while(w--){z=y(z,A[w])}return z};c.merge=function(){var A={};for(var z=0,w=arguments.length;z<w;z++){var x=arguments[z];if(c.type(x)!="object"){continue}for(var y in x){var C=x[y],B=A[y];A[y]=(B&&c.type(C)=="object"&&c.type(B)=="object")?c.merge(B,C):c.unlink(C)}}return A};c.unlink=function(y){var x;switch(c.type(y)){case"object":x={};for(var A in y){x[A]=c.unlink(y[A])}break;case"array":x=[];for(var z=0,w=y.length;z<w;z++){x[z]=c.unlink(y[z])}break;default:return y}return x};c.zip=function(){if(arguments.length===0){return[]}for(var y=0,x=[],w=arguments.length,B=arguments[0].length;y<B;y++){for(var z=0,A=[];z<w;z++){A.push(arguments[z][y])}x.push(A)}return x};c.rgbToHex=function(A,z){if(A.length<3){return null}if(A.length==4&&A[3]==0&&!z){return"transparent"}var x=[];for(var w=0;w<3;w++){var y=(A[w]-0).toString(16);x.push(y.length==1?"0"+y:y)}return z?x:"#"+x.join("")};c.hexToRgb=function(y){if(y.length!=7){y=y.match(/^#?(\w{1,2})(\w{1,2})(\w{1,2})$/);y.shift();if(y.length!=3){return null}var w=[];for(var x=0;x<3;x++){var z=y[x];if(z.length==1){z+=z}w.push(parseInt(z,16))}return w}else{y=parseInt(y.slice(1),16);return[y>>16,y>>8&255,y&255]}};c.destroy=function(w){c.clean(w);if(w.parentNode){w.parentNode.removeChild(w)}if(w.clearAttributes){w.clearAttributes()}};c.clean=function(z){for(var y=z.childNodes,x=0,w=y.length;x<w;x++){c.destroy(y[x])}};c.addEvent=function(y,x,w){if(y.addEventListener){y.addEventListener(x,w,false)}else{y.attachEvent("on"+x,w)}};c.addEvents=function(x,y){for(var w in y){c.addEvent(x,w,y[w])}};c.hasClass=function(x,w){return(" "+x.className+" ").indexOf(" "+w+" ")>-1};c.addClass=function(x,w){if(!c.hasClass(x,w)){x.className=(x.className+" "+w)}};c.removeClass=function(x,w){x.className=x.className.replace(new RegExp("(^|\\s)"+w+"(?:\\s|$)"),"$1")};c.getPos=function(y){var B=A(y);var w=z(y);return{x:B.x-w.x,y:B.y-w.y};function A(D){var C={x:0,y:0};while(D&&!x(D)){C.x+=D.offsetLeft;C.y+=D.offsetTop;D=D.offsetParent}return C}function z(D){var C={x:0,y:0};while(D&&!x(D)){C.x+=D.scrollLeft;C.y+=D.scrollTop;D=D.parentNode}return C}function x(C){return(/^(?:body|html)$/i).test(C.tagName)}};c.event={get:function(x,w){w=w||window;return x||w.event},getWheel:function(w){return w.wheelDelta?w.wheelDelta/120:-(w.detail||0)/3},isRightClick:function(w){return(w.which==3||w.button==2)},getPos:function(z,y){y=y||window;z=z||y.event;var x=y.document;x=x.documentElement||x.body;if(z.touches&&z.touches.length){z=z.touches[0]}var w={x:z.pageX||(z.clientX+x.scrollLeft),y:z.pageY||(z.clientY+x.scrollTop)};return w},stop:function(w){if(w.stopPropagation){w.stopPropagation()}w.cancelBubble=true;if(w.preventDefault){w.preventDefault()}else{w.returnValue=false}}};$jit.util=$jit.id=c;var q=function(x){x=x||{};var w=function(){for(var A in this){if(typeof this[A]!="function"){this[A]=c.unlink(this[A])}}this.constructor=w;if(q.prototyping){return this}var z=this.initialize?this.initialize.apply(this,arguments):this;this.$$family="class";return z};for(var y in q.Mutators){if(!x[y]){continue}x=q.Mutators[y](x,x[y]);delete x[y]}c.extend(w,this);w.constructor=q;w.prototype=x;return w};q.Mutators={Implements:function(w,x){c.each(c.splat(x),function(z){q.prototyping=z;var y=(typeof z=="function")?new z:z;for(var A in y){if(!(A in w)){w[A]=y[A]}}delete q.prototyping});return w}};c.extend(q,{inherit:function(w,z){for(var y in z){var x=z[y];var B=w[y];var A=c.type(x);if(B&&A=="function"){if(x!=B){q.override(w,y,x)}}else{if(A=="object"){w[y]=c.merge(B,x)}else{w[y]=x}}}return w},override:function(x,w,A){var z=q.prototyping;if(z&&x[w]!=z[w]){z=null}var y=function(){var B=this.parent;this.parent=z?z[w]:x[w];var C=A.apply(this,arguments);this.parent=B;return C};x[w]=y}});q.prototype.implement=function(){var w=this.prototype;c.each(Array.prototype.slice.call(arguments||[]),function(x){q.inherit(w,x)});return this};$jit.Class=q;$jit.json={prune:function(x,w){this.each(x,function(z,y){if(y==w&&z.children){delete z.children;z.children=[]}})},getParent:function(w,A){if(w.id==A){return false}var z=w.children;if(z&&z.length>0){for(var y=0;y<z.length;y++){if(z[y].id==A){return w}else{var x=this.getParent(z[y],A);if(x){return x}}}}return false},getSubtree:function(w,A){if(w.id==A){return w}for(var y=0,z=w.children;y<z.length;y++){var x=this.getSubtree(z[y],A);if(x!=null){return x}}return null},eachLevel:function(w,B,y,A){if(B<=y){A(w,B);if(!w.children){return}for(var x=0,z=w.children;x<z.length;x++){this.eachLevel(z[x],B+1,y,A)}}},each:function(w,x){this.eachLevel(w,0,Number.MAX_VALUE,x)}};$jit.Trans={$extend:true,linear:function(w){return w}};var i=$jit.Trans;(function(){var w=function(z,y){y=c.splat(y);return c.extend(z,{easeIn:function(A){return z(A,y)},easeOut:function(A){return 1-z(1-A,y)},easeInOut:function(A){return(A<=0.5)?z(2*A,y)/2:(2-z(2*(1-A),y))/2}})};var x={Pow:function(z,y){return Math.pow(z,y[0]||6)},Expo:function(y){return Math.pow(2,8*(y-1))},Circ:function(y){return 1-Math.sin(Math.acos(y))},Sine:function(y){return 1-Math.sin((1-y)*Math.PI/2)},Back:function(z,y){y=y[0]||1.618;return Math.pow(z,2)*((y+1)*z-y)},Bounce:function(B){var A;for(var z=0,y=1;1;z+=y,y/=2){if(B>=(7-4*z)/11){A=y*y-Math.pow((11-6*z-11*B)/4,2);break}}return A},Elastic:function(z,y){return Math.pow(2,10*--z)*Math.cos(20*z*Math.PI*(y[0]||1)/3)}};c.each(x,function(z,y){i[y]=w(z)});c.each(["Quad","Cubic","Quart","Quint"],function(z,y){i[z]=w(function(A){return Math.pow(A,[y+2])})})})();var u=new q({initialize:function(w){this.setOptions(w)},setOptions:function(w){var x={duration:2500,fps:40,transition:i.Quart.easeInOut,compute:c.empty,complete:c.empty,link:"ignore"};this.opt=c.merge(x,w||{});return this},step:function(){var x=c.time(),w=this.opt;if(x<this.time+w.duration){var y=w.transition((x-this.time)/w.duration);w.compute(y)}else{this.timer=clearInterval(this.timer);w.compute(1);w.complete()}},start:function(){if(!this.check()){return this}this.time=0;this.startTimer();return this},startTimer:function(){var w=this,x=this.opt.fps;if(this.timer){return false}this.time=c.time()-this.time;this.timer=setInterval((function(){w.step()}),Math.round(1000/x));return true},pause:function(){this.stopTimer();return this},resume:function(){this.startTimer();return this},stopTimer:function(){if(!this.timer){return false}this.time=c.time()-this.time;this.timer=clearInterval(this.timer);return true},check:function(){if(!this.timer){return true}if(this.opt.link=="cancel"){this.stopTimer();return true}return false}});var n=function(){var y=arguments;for(var A=0,w=y.length,x={};A<w;A++){var z=n[y[A]];if(z.$extend){c.extend(x,z)}else{x[y[A]]=z}}return x};n.AreaChart={$extend:true,animate:true,labelOffset:3,type:"stacked",Tips:{enable:false,onShow:c.empty,onHide:c.empty},Events:{enable:false,onClick:c.empty},selectOnHover:true,showAggregates:true,showLabels:true,filterOnClick:false,restoreOnRightClick:false};n.Margin={$extend:false,top:0,left:0,right:0,bottom:0};n.Canvas={$extend:true,injectInto:"id",width:false,height:false,useCanvas:false,withLabels:true,background:false};n.Tree={$extend:true,orientation:"left",subtreeOffset:8,siblingOffset:5,indent:10,multitree:false,align:"center"};n.Node={$extend:false,overridable:false,type:"circle",color:"#ccb",alpha:1,dim:3,height:20,width:90,autoHeight:false,autoWidth:false,lineWidth:1,transform:true,align:"center",angularWidth:1,span:1,CanvasStyles:{}};n.Edge={$extend:false,overridable:false,type:"line",color:"#ccb",lineWidth:1,dim:15,alpha:1,epsilon:7,CanvasStyles:{}};n.Fx={$extend:true,fps:40,duration:2500,transition:$jit.Trans.Quart.easeInOut,clearCanvas:true};n.Label={$extend:false,overridable:false,type:"HTML",style:" ",size:10,family:"sans-serif",textAlign:"center",textBaseline:"alphabetic",color:"#fff"};n.Tips={$extend:false,enable:false,type:"auto",offsetX:20,offsetY:20,force:false,onShow:c.empty,onHide:c.empty};n.NodeStyles={$extend:false,enable:false,type:"auto",stylesHover:false,stylesClick:false};n.Events={$extend:false,enable:false,enableForEdges:false,type:"auto",onClick:c.empty,onRightClick:c.empty,onMouseMove:c.empty,onMouseEnter:c.empty,onMouseLeave:c.empty,onDragStart:c.empty,onDragMove:c.empty,onDragCancel:c.empty,onDragEnd:c.empty,onTouchStart:c.empty,onTouchMove:c.empty,onTouchEnd:c.empty,onMouseWheel:c.empty};n.Navigation={$extend:false,enable:false,type:"auto",panning:false,zooming:false};n.Controller={$extend:true,onBeforeCompute:c.empty,onAfterCompute:c.empty,onCreateLabel:c.empty,onPlaceLabel:c.empty,onComplete:c.empty,onBeforePlotLine:c.empty,onAfterPlotLine:c.empty,onBeforePlotNode:c.empty,onAfterPlotNode:c.empty,request:false};var t={initialize:function(y,w){this.viz=w;this.canvas=w.canvas;this.config=w.config[y];this.nodeTypes=w.fx.nodeTypes;var x=this.config.type;this.dom=x=="auto"?(w.config.Label.type!="Native"):(x!="Native");this.labelContainer=this.dom&&w.labels.getLabelContainer();this.isEnabled()&&this.initializePost()},initializePost:c.empty,setAsProperty:c.lambda(false),isEnabled:function(){return this.config.enable},isLabel:function(z,y){z=c.event.get(z,y);var w=this.labelContainer,x=z.target||z.srcElement;if(x&&x.parentNode==w){return x}return false}};var h={onMouseUp:c.empty,onMouseDown:c.empty,onMouseMove:c.empty,onMouseOver:c.empty,onMouseOut:c.empty,onMouseWheel:c.empty,onTouchStart:c.empty,onTouchMove:c.empty,onTouchEnd:c.empty,onTouchCancel:c.empty};var s=new q({initialize:function(w){this.viz=w;this.canvas=w.canvas;this.node=false;this.edge=false;this.registeredObjects=[];this.attachEvents()},attachEvents:function(){var y=this.canvas.getElement(),x=this;y.oncontextmenu=c.lambda(false);c.addEvents(y,{mouseup:function(B,A){var z=c.event.get(B,A);x.handleEvent("MouseUp",B,A,x.makeEventObject(B,A),c.event.isRightClick(z))},mousedown:function(B,A){var z=c.event.get(B,A);x.handleEvent("MouseDown",B,A,x.makeEventObject(B,A),c.event.isRightClick(z))},mousemove:function(A,z){x.handleEvent("MouseMove",A,z,x.makeEventObject(A,z))},mouseover:function(A,z){x.handleEvent("MouseOver",A,z,x.makeEventObject(A,z))},mouseout:function(A,z){x.handleEvent("MouseOut",A,z,x.makeEventObject(A,z))},touchstart:function(A,z){x.handleEvent("TouchStart",A,z,x.makeEventObject(A,z))},touchmove:function(A,z){x.handleEvent("TouchMove",A,z,x.makeEventObject(A,z))},touchend:function(A,z){x.handleEvent("TouchEnd",A,z,x.makeEventObject(A,z))}});var w=function(C,B){var A=c.event.get(C,B);var z=c.event.getWheel(A);x.handleEvent("MouseWheel",C,B,z)};if(!document.getBoxObjectFor&&window.mozInnerScreenX==null){c.addEvent(y,"mousewheel",w)}else{y.addEventListener("DOMMouseScroll",w,false)}},register:function(w){this.registeredObjects.push(w)},handleEvent:function(){var x=Array.prototype.slice.call(arguments),A=x.shift();for(var z=0,y=this.registeredObjects,w=y.length;z<w;z++){y[z]["on"+A].apply(y[z],x)}},makeEventObject:function(C,B){var z=this,A=this.viz.graph,y=this.viz.fx,x=y.nodeTypes,w=y.edgeTypes;return{pos:false,node:false,edge:false,contains:false,getNodeCalled:false,getEdgeCalled:false,getPos:function(){var F=z.viz.canvas,G=F.getSize(),H=F.getPos(),E=F.translateOffsetX,D=F.translateOffsetY,K=F.scaleOffsetX,I=F.scaleOffsetY,J=c.event.getPos(C,B);this.pos={x:(J.x-H.x-G.width/2-E)*1/K,y:(J.y-H.y-G.height/2-D)*1/I};return this.pos},getNode:function(){if(this.getNodeCalled){return this.node}this.getNodeCalled=true;for(var G in A.nodes){var F=A.nodes[G],E=F&&x[F.getData("type")],D=E&&E.contains&&E.contains.call(y,F,this.getPos());if(D){this.contains=D;return z.node=this.node=F}}return z.node=this.node=false},getEdge:function(){if(this.getEdgeCalled){return this.edge}this.getEdgeCalled=true;var F={};for(var J in A.edges){var H=A.edges[J];F[J]=true;for(var I in H){if(I in F){continue}var G=H[I],E=G&&w[G.getData("type")],D=E&&E.contains&&E.contains.call(y,G,this.getPos());if(D){this.contains=D;return z.edge=this.edge=G}}}return z.edge=this.edge=false},getContains:function(){if(this.getNodeCalled){return this.contains}this.getNode();return this.contains}}}});var o={initializeExtras:function(){var x=new s(this),w=this;c.each(["NodeStyles","Tips","Navigation","Events"],function(y){var z=new o.Classes[y](y,w);if(z.isEnabled()){x.register(z)}if(z.setAsProperty()){w[y.toLowerCase()]=z}})}};o.Classes={};o.Classes.Events=new q({Implements:[t,h],initializePost:function(){this.fx=this.viz.fx;this.ntypes=this.viz.fx.nodeTypes;this.etypes=this.viz.fx.edgeTypes;this.hovered=false;this.pressed=false;this.touched=false;this.touchMoved=false;this.moved=false},setAsProperty:c.lambda(true),onMouseUp:function(A,z,x,y){var w=c.event.get(A,z);if(!this.moved){if(y){this.config.onRightClick(this.hovered,x,w)}else{this.config.onClick(this.pressed,x,w)}}if(this.pressed){if(this.moved){this.config.onDragEnd(this.pressed,x,w)}else{this.config.onDragCancel(this.pressed,x,w)}this.pressed=this.moved=false}},onMouseOut:function(B,A,z){var x=c.event.get(B,A),y;if(this.dom&&(y=this.isLabel(B,A))){this.config.onMouseLeave(this.viz.graph.getNode(y.id),z,x);this.hovered=false;return}var w=x.relatedTarget,C=this.canvas.getElement();while(w&&w.parentNode){if(C==w.parentNode){return}w=w.parentNode}if(this.hovered){this.config.onMouseLeave(this.hovered,z,x);this.hovered=false}},onMouseOver:function(A,z,y){var w=c.event.get(A,z),x;if(this.dom&&(x=this.isLabel(A,z))){this.hovered=this.viz.graph.getNode(x.id);this.config.onMouseEnter(this.hovered,y,w)}},onMouseMove:function(C,B,A){var x,w=c.event.get(C,B);if(this.pressed){this.moved=true;this.config.onDragMove(this.pressed,A,w);return}if(this.dom){this.config.onMouseMove(this.hovered,A,w)}else{if(this.hovered){var D=this.hovered;var z=D.nodeFrom?this.etypes[D.getData("type")]:this.ntypes[D.getData("type")];var y=z&&z.contains&&z.contains.call(this.fx,D,A.getPos());if(y){this.config.onMouseMove(D,A,w);return}else{this.config.onMouseLeave(D,A,w);this.hovered=false}}if(this.hovered=(A.getNode()||(this.config.enableForEdges&&A.getEdge()))){this.config.onMouseEnter(this.hovered,A,w)}else{this.config.onMouseMove(false,A,w)}}},onMouseWheel:function(x,w,y){this.config.onMouseWheel(y,c.event.get(x,w))},onMouseDown:function(z,y,x){var w=c.event.get(z,y);this.pressed=x.getNode()||(this.config.enableForEdges&&x.getEdge());this.config.onDragStart(this.pressed,x,w)},onTouchStart:function(z,y,x){var w=c.event.get(z,y);this.touched=x.getNode()||(this.config.enableForEdges&&x.getEdge());this.config.onTouchStart(this.touched,x,w)},onTouchMove:function(z,y,x){var w=c.event.get(z,y);if(this.touched){this.touchMoved=true;this.config.onTouchMove(this.touched,x,w)}},onTouchEnd:function(z,y,x){var w=c.event.get(z,y);if(this.touched){if(this.touchMoved){this.config.onTouchEnd(this.touched,x,w)}else{this.config.onTouchCancel(this.touched,x,w)}this.touched=this.touchMoved=false}}});o.Classes.Tips=new q({Implements:[t,h],initializePost:function(){if(document.body){var w=c("_tooltip")||document.createElement("div");w.id="_tooltip";w.className="tip";c.extend(w.style,{position:"absolute",display:"none",zIndex:13000});document.body.appendChild(w);this.tip=w;this.node=false}},setAsProperty:c.lambda(true),onMouseOut:function(y,x){if(this.dom&&this.isLabel(y,x)){this.hide(true);return}var w=y.relatedTarget,z=this.canvas.getElement();while(w&&w.parentNode){if(z==w.parentNode){return}w=w.parentNode}this.hide(false)},onMouseOver:function(y,x){var w;if(this.dom&&(w=this.isLabel(y,x))){this.node=this.viz.graph.getNode(w.id);this.config.onShow(this.tip,this.node,w)}},onMouseMove:function(z,y,w){if(this.dom&&this.isLabel(z,y)){this.setTooltipPosition(c.event.getPos(z,y))}if(!this.dom){var x=w.getNode();if(!x){this.hide(true);return}if(this.config.force||!this.node||this.node.id!=x.id){this.node=x;this.config.onShow(this.tip,x,w.getContains())}this.setTooltipPosition(c.event.getPos(z,y))}},setTooltipPosition:function(F){var B=this.tip,A=B.style,z=this.config;A.display="";var D={height:document.body.clientHeight,width:document.body.clientWidth};var C={width:B.offsetWidth,height:B.offsetHeight};var w=z.offsetX,E=z.offsetY;A.top=((F.y+E+C.height>D.height)?(F.y-C.height-E):F.y+E)+"px";A.left=((F.x+C.width+w>D.width)?(F.x-C.width-w):F.x+w)+"px"},hide:function(w){this.tip.style.display="none";w&&this.config.onHide()}});o.Classes.NodeStyles=new q({Implements:[t,h],initializePost:function(){this.fx=this.viz.fx;this.types=this.viz.fx.nodeTypes;this.nStyles=this.config;this.nodeStylesOnHover=this.nStyles.stylesHover;this.nodeStylesOnClick=this.nStyles.stylesClick;this.hoveredNode=false;this.fx.nodeFxAnimation=new u();this.down=false;this.move=false},onMouseOut:function(y,x){this.down=this.move=false;if(!this.hoveredNode){return}if(this.dom&&this.isLabel(y,x)){this.toggleStylesOnHover(this.hoveredNode,false)}var w=y.relatedTarget,z=this.canvas.getElement();while(w&&w.parentNode){if(z==w.parentNode){return}w=w.parentNode}this.toggleStylesOnHover(this.hoveredNode,false);this.hoveredNode=false},onMouseOver:function(z,y){var w;if(this.dom&&(w=this.isLabel(z,y))){var x=this.viz.graph.getNode(w.id);if(x.selected){return}this.hoveredNode=x;this.toggleStylesOnHover(this.hoveredNode,true)}},onMouseDown:function(A,z,x,y){if(y){return}var w;if(this.dom&&(w=this.isLabel(A,z))){this.down=this.viz.graph.getNode(w.id)}else{if(!this.dom){this.down=x.getNode()}}this.move=false},onMouseUp:function(z,y,w,x){if(x){return}if(!this.move){this.onClick(w.getNode())}this.down=this.move=false},getRestoredStyles:function(x,w){var z={},y=this["nodeStylesOn"+w];for(var A in y){z[A]=x.styles["$"+A]}return z},toggleStylesOnHover:function(w,x){if(this.nodeStylesOnHover){this.toggleStylesOn("Hover",w,x)}},toggleStylesOnClick:function(w,x){if(this.nodeStylesOnClick){this.toggleStylesOn("Click",w,x)}},toggleStylesOn:function(A,w,C){var D=this.viz;var B=this.nStyles;if(C){var z=this;if(!w.styles){w.styles=c.merge(w.data,{})}for(var E in this["nodeStylesOn"+A]){var x="$"+E;if(!(x in w.styles)){w.styles[x]=w.getData(E)}}D.fx.nodeFx(c.extend({elements:{id:w.id,properties:z["nodeStylesOn"+A]},transition:i.Quart.easeOut,duration:300,fps:40},this.config))}else{var y=this.getRestoredStyles(w,A);D.fx.nodeFx(c.extend({elements:{id:w.id,properties:y},transition:i.Quart.easeOut,duration:300,fps:40},this.config))}},onClick:function(w){if(!w){return}var x=this.nodeStylesOnClick;if(!x){return}if(w.selected){this.toggleStylesOnClick(w,false);delete w.selected}else{this.viz.graph.eachNode(function(z){if(z.selected){for(var y in x){z.setData(y,z.styles["$"+y],"end")}delete z.selected}});this.toggleStylesOnClick(w,true);w.selected=true;delete w.hovered;this.hoveredNode=false}},onMouseMove:function(C,B,z){if(this.down){this.move=true}if(this.dom&&this.isLabel(C,B)){return}var A=this.nodeStylesOnHover;if(!A){return}if(!this.dom){if(this.hoveredNode){var x=this.types[this.hoveredNode.getData("type")];var w=x&&x.contains&&x.contains.call(this.fx,this.hoveredNode,z.getPos());if(w){return}}var y=z.getNode();if(!this.hoveredNode&&!y){return}if(y.hovered){return}if(y&&!y.selected){this.fx.nodeFxAnimation.stopTimer();this.viz.graph.eachNode(function(E){if(E.hovered&&!E.selected){for(var D in A){E.setData(D,E.styles["$"+D],"end")}delete E.hovered}});y.hovered=true;this.hoveredNode=y;this.toggleStylesOnHover(y,true)}else{if(this.hoveredNode&&!this.hoveredNode.selected){this.fx.nodeFxAnimation.stopTimer();this.toggleStylesOnHover(this.hoveredNode,false);delete this.hoveredNode.hovered;this.hoveredNode=false}}}}});o.Classes.Navigation=new q({Implements:[t,h],initializePost:function(){this.pos=false;this.pressed=false},onMouseWheel:function(z,y,w){if(!this.config.zooming){return}c.event.stop(c.event.get(z,y));var A=this.config.zooming/1000,x=1+w*A;this.canvas.scale(x,x)},onMouseDown:function(B,A,z){if(!this.config.panning){return}if(this.config.panning=="avoid nodes"&&z.getNode()){return}this.pressed=true;this.pos=z.getPos();var y=this.canvas,x=y.translateOffsetX,w=y.translateOffsetY,D=y.scaleOffsetX,C=y.scaleOffsetY;this.pos.x*=D;this.pos.x+=x;this.pos.y*=C;this.pos.y+=w},onMouseMove:function(D,C,F){if(!this.config.panning){return}if(!this.pressed){return}if(this.config.panning=="avoid nodes"&&F.getNode()){return}var B=this.pos,E=F.getPos(),z=this.canvas,A=z.translateOffsetX,w=z.translateOffsetY,J=z.scaleOffsetX,H=z.scaleOffsetY;E.x*=J;E.y*=H;E.x+=A;E.y+=w;var I=E.x-B.x,G=E.y-B.y;this.pos=E;this.canvas.translate(I*1/J,G*1/H)},onMouseUp:function(z,y,x,w){if(!this.config.panning){return}this.pressed=false}});var l;(function(){var w=typeof HTMLCanvasElement,y=(w=="object"||w=="function");function x(z,A){var B=document.createElement(z);for(var C in A){if(typeof A[C]=="object"){c.extend(B[C],A[C])}else{B[C]=A[C]}}if(z=="canvas"&&!y&&G_vmlCanvasManager){B=G_vmlCanvasManager.initElement(document.body.appendChild(B))}return B}$jit.Canvas=l=new q({canvases:[],pos:false,element:false,labelContainer:false,translateOffsetX:0,translateOffsetY:0,scaleOffsetX:1,scaleOffsetY:1,initialize:function(K,E){this.viz=K;this.opt=E;var B=c.type(E.injectInto)=="string"?E.injectInto:E.injectInto.id,C=B+"-label",z=c(B),D=E.width||z.offsetWidth,L=E.height||z.offsetHeight;this.id=B;var F={injectInto:B,width:D,height:L};this.element=x("div",{id:B+"-canvaswidget",style:{position:"relative",width:D+"px",height:L+"px"}});this.labelContainer=this.createLabelContainer(E.Label.type,C,F);this.canvases.push(new l.Base({config:c.extend({idSuffix:"-canvas"},F),plot:function(M){K.fx.plot()},resize:function(){K.refresh()}}));var G=E.background;if(G){var J=new l.Background[G.type](K,c.extend(G,F));this.canvases.push(new l.Base(J))}var I=this.canvases.length;while(I--){this.element.appendChild(this.canvases[I].canvas);if(I>0){this.canvases[I].plot()}}this.element.appendChild(this.labelContainer);z.appendChild(this.element);var A=null,H=this;c.addEvent(window,"scroll",function(){clearTimeout(A);A=setTimeout(function(){H.getPos(true)},500)})},getCtx:function(z){return this.canvases[z||0].getCtx()},getConfig:function(){return this.opt},getElement:function(){return this.element},getSize:function(z){return this.canvases[z||0].getSize()},resize:function(D,z){this.getPos(true);this.translateOffsetX=this.translateOffsetY=0;this.scaleOffsetX=this.scaleOffsetY=1;for(var B=0,A=this.canvases.length;B<A;B++){this.canvases[B].resize(D,z)}var C=this.element.style;C.width=D+"px";C.height=z+"px";if(this.labelContainer){this.labelContainer.style.width=D+"px"}},translate:function(z,D,C){this.translateOffsetX+=z*this.scaleOffsetX;this.translateOffsetY+=D*this.scaleOffsetY;for(var B=0,A=this.canvases.length;B<A;B++){this.canvases[B].translate(z,D,C)}},scale:function(E,B,C){var F=this.scaleOffsetX*E,D=this.scaleOffsetY*B;var H=this.translateOffsetX*(E-1)/F,G=this.translateOffsetY*(B-1)/D;this.scaleOffsetX=F;this.scaleOffsetY=D;for(var A=0,z=this.canvases.length;A<z;A++){this.canvases[A].scale(E,B,true)}this.translate(H,G,false)},getPos:function(z){if(z||!this.pos){return this.pos=c.getPos(this.getElement())}return this.pos},clear:function(z){this.canvases[z||0].clear()},path:function(A,B){var z=this.canvases[0].getCtx();z.beginPath();B(z);z[A]();z.closePath()},createLabelContainer:function(B,F,E){var D="http://www.w3.org/2000/svg";if(B=="HTML"||B=="Native"){return x("div",{id:F,style:{overflow:"visible",position:"absolute",top:0,left:0,width:E.width+"px",height:0}})}else{if(B=="SVG"){var C=document.createElementNS(D,"svg:svg");C.setAttribute("width",E.width);C.setAttribute("height",E.height);var A=C.style;A.position="absolute";A.left=A.top="0px";var z=document.createElementNS(D,"svg:g");z.setAttribute("width",E.width);z.setAttribute("height",E.height);z.setAttribute("x",0);z.setAttribute("y",0);z.setAttribute("id",F);C.appendChild(z);return C}}}});l.Base=new q({translateOffsetX:0,translateOffsetY:0,scaleOffsetX:1,scaleOffsetY:1,initialize:function(z){this.viz=z;this.opt=z.config;this.size=false;this.createCanvas();this.translateToCenter()},createCanvas:function(){var A=this.opt,B=A.width,z=A.height;this.canvas=x("canvas",{id:A.injectInto+A.idSuffix,width:B,height:z,style:{position:"absolute",top:0,left:0,width:B+"px",height:z+"px"}})},getCtx:function(){if(!this.ctx){return this.ctx=this.canvas.getContext("2d")}return this.ctx},getSize:function(){if(this.size){return this.size}var z=this.canvas;return this.size={width:z.width,height:z.height}},translateToCenter:function(C){var A=this.getSize(),B=C?(A.width-C.width-this.translateOffsetX*2):A.width;height=C?(A.height-C.height-this.translateOffsetY*2):A.height;var z=this.getCtx();C&&z.scale(1/this.scaleOffsetX,1/this.scaleOffsetY);z.translate(B/2,height/2)},resize:function(C,z){var B=this.getSize(),A=this.canvas,D=A.style;this.size=false;A.width=C;A.height=z;D.width=C+"px";D.height=z+"px";if(!y){this.translateToCenter(B)}else{this.translateToCenter()}this.translateOffsetX=this.translateOffsetY=0;this.scaleOffsetX=this.scaleOffsetY=1;this.clear();this.viz.resize(C,z,this)},translate:function(z,D,A){var C=this.scaleOffsetX,B=this.scaleOffsetY;this.translateOffsetX+=z*C;this.translateOffsetY+=D*B;this.getCtx().translate(z,D);!A&&this.plot()},scale:function(z,B,A){this.scaleOffsetX*=z;this.scaleOffsetY*=B;this.getCtx().scale(z,B);!A&&this.plot()},clear:function(){var B=this.getSize(),A=this.translateOffsetX,z=this.translateOffsetY,D=this.scaleOffsetX,C=this.scaleOffsetY;this.getCtx().clearRect((-B.width/2-A)*1/D,(-B.height/2-z)*1/C,B.width*1/D,B.height*1/C)},plot:function(){this.clear();this.viz.plot(this)}});l.Background={};l.Background.Circles=new q({initialize:function(z,A){this.viz=z;this.config=c.merge({idSuffix:"-bkcanvas",levelDistance:100,numberOfCircles:6,CanvasStyles:{},offset:0},A)},resize:function(A,z,B){this.plot(B)},plot:function(z){var A=z.canvas,G=z.getCtx(),D=this.config,F=D.CanvasStyles;for(var H in F){G[H]=F[H]}var B=D.numberOfCircles,E=D.levelDistance;for(var C=1;C<=B;C++){G.beginPath();G.arc(0,0,E*C,0,2*Math.PI,false);G.stroke();G.closePath()}}})})();var b=function(x,w){this.theta=x;this.rho=w};$jit.Polar=b;b.prototype={getc:function(w){return this.toComplex(w)},getp:function(){return this},set:function(w){w=w.getp();this.theta=w.theta;this.rho=w.rho},setc:function(w,z){this.rho=Math.sqrt(w*w+z*z);this.theta=Math.atan2(z,w);if(this.theta<0){this.theta+=Math.PI*2}},setp:function(x,w){this.theta=x;this.rho=w},clone:function(){return new b(this.theta,this.rho)},toComplex:function(A){var w=Math.cos(this.theta)*this.rho;var z=Math.sin(this.theta)*this.rho;if(A){return{x:w,y:z}}return new p(w,z)},add:function(w){return new b(this.theta+w.theta,this.rho+w.rho)},scale:function(w){return new b(this.theta,this.rho*w)},equals:function(w){return this.theta==w.theta&&this.rho==w.rho},$add:function(w){this.theta=this.theta+w.theta;this.rho+=w.rho;return this},$madd:function(w){this.theta=(this.theta+w.theta)%(Math.PI*2);this.rho+=w.rho;return this},$scale:function(w){this.rho*=w;return this},interpolate:function(y,F){var z=Math.PI,C=z*2;var x=function(H){var G=(H<0)?(H%C)+C:H%C;return G};var B=this.theta,E=y.theta;var A,D=Math.abs(B-E);if(D==z){if(B>E){A=x((E+((B-C)-E)*F))}else{A=x((E-C+(B-(E))*F))}}else{if(D>=z){if(B>E){A=x((E+((B-C)-E)*F))}else{A=x((E-C+(B-(E-C))*F))}}else{A=x((E+(B-E)*F))}}var w=(this.rho-y.rho)*F+y.rho;return{theta:A,rho:w}}};var k=function(x,w){return new b(x,w)};b.KER=k(0,0);var p=function(w,z){this.x=w;this.y=z};$jit.Complex=p;p.prototype={getc:function(){return this},getp:function(w){return this.toPolar(w)},set:function(w){w=w.getc(true);this.x=w.x;this.y=w.y},setc:function(w,z){this.x=w;this.y=z},setp:function(x,w){this.x=Math.cos(x)*w;this.y=Math.sin(x)*w},clone:function(){return new p(this.x,this.y)},toPolar:function(y){var w=this.norm();var x=Math.atan2(this.y,this.x);if(x<0){x+=Math.PI*2}if(y){return{theta:x,rho:w}}return new b(x,w)},norm:function(){return Math.sqrt(this.squaredNorm())},squaredNorm:function(){return this.x*this.x+this.y*this.y},add:function(w){return new p(this.x+w.x,this.y+w.y)},prod:function(w){return new p(this.x*w.x-this.y*w.y,this.y*w.x+this.x*w.y)},conjugate:function(){return new p(this.x,-this.y)},scale:function(w){return new p(this.x*w,this.y*w)},equals:function(w){return this.x==w.x&&this.y==w.y},$add:function(w){this.x+=w.x;this.y+=w.y;return this},$prod:function(A){var w=this.x,z=this.y;this.x=w*A.x-z*A.y;this.y=z*A.x+w*A.y;return this},$conjugate:function(){this.y=-this.y;return this},$scale:function(w){this.x*=w;this.y*=w;return this},$div:function(B){var w=this.x,A=this.y;var z=B.squaredNorm();this.x=w*B.x+A*B.y;this.y=A*B.x-w*B.y;return this.$scale(1/z)}};var r=function(x,w){return new p(x,w)};p.KER=r(0,0);$jit.Graph=new q({initialize:function(y,x,w,C){var A={complex:false,Node:{}};this.Node=x;this.Edge=w;this.Label=C;this.opt=c.merge(A,y||{});this.nodes={};this.edges={};var z=this;this.nodeList={};for(var B in j){z.nodeList[B]=(function(D){return function(){var E=Array.prototype.slice.call(arguments);z.eachNode(function(F){F[D].apply(F,E)})}})(B)}},getNode:function(w){if(this.hasNode(w)){return this.nodes[w]}return false},getByName:function(w){for(var y in this.nodes){var x=this.nodes[y];if(x.name==w){return x}}return false},getAdjacence:function(x,w){if(x in this.edges){return this.edges[x][w]}return false},addNode:function(x){if(!this.nodes[x.id]){var w=this.edges[x.id]={};this.nodes[x.id]=new e.Node(c.extend({id:x.id,name:x.name,data:c.merge(x.data||{},{}),adjacencies:w},this.opt.Node),this.opt.complex,this.Node,this.Edge,this.Label)}return this.nodes[x.id]},addAdjacence:function(z,y,x){if(!this.hasNode(z.id)){this.addNode(z)}if(!this.hasNode(y.id)){this.addNode(y)}z=this.nodes[z.id];y=this.nodes[y.id];if(!z.adjacentTo(y)){var A=this.edges[z.id]=this.edges[z.id]||{};var w=this.edges[y.id]=this.edges[y.id]||{};A[y.id]=w[z.id]=new e.Adjacence(z,y,x,this.Edge,this.Label);return A[y.id]}return this.edges[z.id][y.id]},removeNode:function(y){if(this.hasNode(y)){delete this.nodes[y];var x=this.edges[y];for(var w in x){delete this.edges[w][y]}delete this.edges[y]}},removeAdjacence:function(x,w){delete this.edges[x][w];delete this.edges[w][x]},hasNode:function(w){return w in this.nodes},empty:function(){this.nodes={};this.edges={}}});var e=$jit.Graph;var j;(function(){var w=function(D,F,A,C,E){var B;A=A||"current";D="$"+(D?D+"-":"");if(A=="current"){B=this.data}else{if(A=="start"){B=this.startData}else{if(A=="end"){B=this.endData}}}var z=D+F;if(C){return B[z]}if(!this.Config.overridable){return E[F]||0}return(z in B)?B[z]:((z in this.data)?this.data[z]:(E[F]||0))};var y=function(C,D,B,z){z=z||"current";C="$"+(C?C+"-":"");var A;if(z=="current"){A=this.data}else{if(z=="start"){A=this.startData}else{if(z=="end"){A=this.endData}}}A[C+D]=B};var x=function(B,z){B="$"+(B?B+"-":"");var A=this;c.each(z,function(D){var C=B+D;delete A.data[C];delete A.endData[C];delete A.startData[C]})};j={getData:function(B,z,A){return w.call(this,"",B,z,A,this.Config)},setData:function(B,A,z){y.call(this,"",B,A,z)},setDataset:function(C,D){C=c.splat(C);for(var z in D){for(var B=0,E=c.splat(D[z]),A=C.length;B<A;B++){this.setData(z,E[B],C[B])}}},removeData:function(){x.call(this,"",Array.prototype.slice.call(arguments))},getCanvasStyle:function(B,z,A){return w.call(this,"canvas",B,z,A,this.Config.CanvasStyles)},setCanvasStyle:function(B,A,z){y.call(this,"canvas",B,A,z)},setCanvasStyles:function(C,D){C=c.splat(C);for(var z in D){for(var B=0,E=c.splat(D[z]),A=C.length;B<A;B++){this.setCanvasStyle(z,E[B],C[B])}}},removeCanvasStyle:function(){x.call(this,"canvas",Array.prototype.slice.call(arguments))},getLabelData:function(B,z,A){return w.call(this,"label",B,z,A,this.Label)},setLabelData:function(B,A,z){y.call(this,"label",B,A,z)},setLabelDataset:function(C,D){C=c.splat(C);for(var z in D){for(var B=0,E=c.splat(D[z]),A=C.length;B<A;B++){this.setLabelData(z,E[B],C[B])}}},removeLabelData:function(){x.call(this,"label",Array.prototype.slice.call(arguments))}}})();e.Node=new q({initialize:function(y,A,x,w,B){var z={id:"",name:"",data:{},startData:{},endData:{},adjacencies:{},selected:false,drawn:false,exist:false,angleSpan:{begin:0,end:0},pos:(A&&r(0,0))||k(0,0),startPos:(A&&r(0,0))||k(0,0),endPos:(A&&r(0,0))||k(0,0)};c.extend(this,c.extend(z,y));this.Config=this.Node=x;this.Edge=w;this.Label=B},adjacentTo:function(w){return w.id in this.adjacencies},getAdjacency:function(w){return this.adjacencies[w]},getPos:function(w){w=w||"current";if(w=="current"){return this.pos}else{if(w=="end"){return this.endPos}else{if(w=="start"){return this.startPos}}}},setPos:function(x,w){w=w||"current";var y;if(w=="current"){y=this.pos}else{if(w=="end"){y=this.endPos}else{if(w=="start"){y=this.startPos}}}y.set(x)}});e.Node.implement(j);e.Adjacence=new q({initialize:function(x,A,y,w,z){this.nodeFrom=x;this.nodeTo=A;this.data=y||{};this.startData={};this.endData={};this.Config=this.Edge=w;this.Label=z}});e.Adjacence.implement(j);e.Util={filter:function(x){if(!x||!(c.type(x)=="string")){return function(){return true}}var w=x.split(" ");return function(z){for(var y=0;y<w.length;y++){if(z[w[y]]){return false}}return true}},getNode:function(w,x){return w.nodes[x]},eachNode:function(A,z,w){var y=this.filter(w);for(var x in A.nodes){if(y(A.nodes[x])){z(A.nodes[x])}}},eachAdjacency:function(B,C,x){var y=B.adjacencies,A=this.filter(x);for(var D in y){var w=y[D];if(A(w)){if(w.nodeFrom!=B){var z=w.nodeFrom;w.nodeFrom=w.nodeTo;w.nodeTo=z}C(w,D)}}},computeLevels:function(C,D,z,y){z=z||0;var A=this.filter(y);this.eachNode(C,function(E){E._flag=false;E._depth=-1},y);var x=C.getNode(D);x._depth=z;var w=[x];while(w.length!=0){var B=w.pop();B._flag=true;this.eachAdjacency(B,function(E){var F=E.nodeTo;if(F._flag==false&&A(F)){if(F._depth<0){F._depth=B._depth+1+z}w.unshift(F)}},y)}},eachBFS:function(B,C,A,x){var y=this.filter(x);this.clean(B);var w=[B.getNode(C)];while(w.length!=0){var z=w.pop();z._flag=true;A(z,z._depth);this.eachAdjacency(z,function(D){var E=D.nodeTo;if(E._flag==false&&y(E)){E._flag=true;w.unshift(E)}},x)}},eachLevel:function(A,E,x,B,z){var D=A._depth,w=this.filter(z),C=this;x=x===false?Number.MAX_VALUE-D:x;(function y(H,F,G){var I=H._depth;if(I>=F&&I<=G&&w(H)){B(H,I)}if(I<G){C.eachAdjacency(H,function(J){var K=J.nodeTo;if(K._depth>I){y(K,F,G)}})}})(A,E+D,x+D)},eachSubgraph:function(x,y,w){this.eachLevel(x,0,false,y,w)},eachSubnode:function(x,y,w){this.eachLevel(x,1,1,y,w)},anySubnode:function(z,y,x){var w=false;y=y||c.lambda(true);var A=c.type(y)=="string"?function(B){return B[y]}:y;this.eachSubnode(z,function(B){if(A(B)){w=true}},x);return w},getSubnodes:function(B,C,w){var y=[],A=this;C=C||0;var z,x;if(c.type(C)=="array"){z=C[0];x=C[1]}else{z=C;x=Number.MAX_VALUE-B._depth}this.eachLevel(B,z,x,function(D){y.push(D)},w);return y},getParents:function(x){var w=[];this.eachAdjacency(x,function(y){var z=y.nodeTo;if(z._depth<x._depth){w.push(z)}});return w},isDescendantOf:function(z,A){if(z.id==A){return true}var y=this.getParents(z),w=false;for(var x=0;!w&&x<y.length;x++){w=w||this.isDescendantOf(y[x],A)}return w},clean:function(w){this.eachNode(w,function(x){x._flag=false})},getClosestNodeToOrigin:function(x,y,w){return this.getClosestNodeToPos(x,b.KER,y,w)},getClosestNodeToPos:function(y,B,A,w){var x=null;A=A||"current";B=B&&B.getc(true)||p.KER;var z=function(D,C){var F=D.x-C.x,E=D.y-C.y;return F*F+E*E};this.eachNode(y,function(C){x=(x==null||z(C.getPos(A).getc(true),B)<z(x.getPos(A).getc(true),B))?C:x},w);return x}};c.each(["getNode","eachNode","computeLevels","eachBFS","clean","getClosestNodeToPos","getClosestNodeToOrigin"],function(w){e.prototype[w]=function(){return e.Util[w].apply(e.Util,[this].concat(Array.prototype.slice.call(arguments)))}});c.each(["eachAdjacency","eachLevel","eachSubgraph","eachSubnode","anySubnode","getSubnodes","getParents","isDescendantOf"],function(w){e.Node.prototype[w]=function(){return e.Util[w].apply(e.Util,[this].concat(Array.prototype.slice.call(arguments)))}});e.Op={options:{type:"nothing",duration:2000,hideLabels:true,fps:30},initialize:function(w){this.viz=w},removeNode:function(B,z){var w=this.viz;var x=c.merge(this.options,w.controller,z);var D=c.splat(B);var y,A,C;switch(x.type){case"nothing":for(y=0;y<D.length;y++){w.graph.removeNode(D[y])}break;case"replot":this.removeNode(D,{type:"nothing"});w.labels.clearLabels();w.refresh(true);break;case"fade:seq":case"fade":A=this;for(y=0;y<D.length;y++){C=w.graph.getNode(D[y]);C.setData("alpha",0,"end")}w.fx.animate(c.merge(x,{modes:["node-property:alpha"],onComplete:function(){A.removeNode(D,{type:"nothing"});w.labels.clearLabels();w.reposition();w.fx.animate(c.merge(x,{modes:["linear"]}))}}));break;case"fade:con":A=this;for(y=0;y<D.length;y++){C=w.graph.getNode(D[y]);C.setData("alpha",0,"end");C.ignore=true}w.reposition();w.fx.animate(c.merge(x,{modes:["node-property:alpha","linear"],onComplete:function(){A.removeNode(D,{type:"nothing"})}}));break;case"iter":A=this;w.fx.sequence({condition:function(){return D.length!=0},step:function(){A.removeNode(D.shift(),{type:"nothing"});w.labels.clearLabels()},onComplete:function(){x.onComplete()},duration:Math.ceil(x.duration/D.length)});break;default:this.doError()}},removeEdge:function(D,B){var w=this.viz;var z=c.merge(this.options,w.controller,B);var y=(c.type(D[0])=="string")?[D]:D;var A,C,x;switch(z.type){case"nothing":for(A=0;A<y.length;A++){w.graph.removeAdjacence(y[A][0],y[A][1])}break;case"replot":this.removeEdge(y,{type:"nothing"});w.refresh(true);break;case"fade:seq":case"fade":C=this;for(A=0;A<y.length;A++){x=w.graph.getAdjacence(y[A][0],y[A][1]);if(x){x.setData("alpha",0,"end")}}w.fx.animate(c.merge(z,{modes:["edge-property:alpha"],onComplete:function(){C.removeEdge(y,{type:"nothing"});w.reposition();w.fx.animate(c.merge(z,{modes:["linear"]}))}}));break;case"fade:con":C=this;for(A=0;A<y.length;A++){x=w.graph.getAdjacence(y[A][0],y[A][1]);if(x){x.setData("alpha",0,"end");x.ignore=true}}w.reposition();w.fx.animate(c.merge(z,{modes:["edge-property:alpha","linear"],onComplete:function(){C.removeEdge(y,{type:"nothing"})}}));break;case"iter":C=this;w.fx.sequence({condition:function(){return y.length!=0},step:function(){C.removeEdge(y.shift(),{type:"nothing"});w.labels.clearLabels()},onComplete:function(){z.onComplete()},duration:Math.ceil(z.duration/y.length)});break;default:this.doError()}},sum:function(A,z){var w=this.viz;var y=c.merge(this.options,w.controller,z),x=w.root;var C;w.root=z.id||w.root;switch(y.type){case"nothing":C=w.construct(A);C.eachNode(function(E){E.eachAdjacency(function(F){w.graph.addAdjacence(F.nodeFrom,F.nodeTo,F.data)})});break;case"replot":w.refresh(true);this.sum(A,{type:"nothing"});w.refresh(true);break;case"fade:seq":case"fade":case"fade:con":that=this;C=w.construct(A);var D=this.preprocessSum(C);var B=!D?["node-property:alpha"]:["node-property:alpha","edge-property:alpha"];w.reposition();if(y.type!="fade:con"){w.fx.animate(c.merge(y,{modes:["linear"],onComplete:function(){w.fx.animate(c.merge(y,{modes:B,onComplete:function(){y.onComplete()}}))}}))}else{w.graph.eachNode(function(E){if(E.id!=x&&E.pos.getp().equals(b.KER)){E.pos.set(E.endPos);E.startPos.set(E.endPos)}});w.fx.animate(c.merge(y,{modes:["linear"].concat(B)}))}break;default:this.doError()}},morph:function(E,x,z){var B=this.viz;var F=c.merge(this.options,B.controller,x),A=B.root;var C;B.root=x.id||B.root;switch(F.type){case"nothing":C=B.construct(E);C.eachNode(function(I){var H=B.graph.hasNode(I.id);I.eachAdjacency(function(M){var L=!!B.graph.getAdjacence(M.nodeFrom.id,M.nodeTo.id);B.graph.addAdjacence(M.nodeFrom,M.nodeTo,M.data);if(L){var K=B.graph.getAdjacence(M.nodeFrom.id,M.nodeTo.id);for(var N in (M.data||{})){K.data[N]=M.data[N]}}});if(H){var G=B.graph.getNode(I.id);for(var J in (I.data||{})){G.data[J]=I.data[J]}}});B.graph.eachNode(function(G){G.eachAdjacency(function(H){if(!C.getAdjacence(H.nodeFrom.id,H.nodeTo.id)){B.graph.removeAdjacence(H.nodeFrom.id,H.nodeTo.id)}});if(!C.hasNode(G.id)){B.graph.removeNode(G.id)}});break;case"replot":B.labels.clearLabels(true);this.morph(E,{type:"nothing"});B.refresh(true);B.refresh(true);break;case"fade:seq":case"fade":case"fade:con":that=this;C=B.construct(E);var D=z&&("node-property" in z)&&c.map(c.splat(z["node-property"]),function(G){return"$"+G});B.graph.eachNode(function(H){var I=C.getNode(H.id);if(!I){H.setData("alpha",1);H.setData("alpha",1,"start");H.setData("alpha",0,"end");H.ignore=true}else{var G=I.data;for(var J in G){if(D&&(c.indexOf(D,J)>-1)){H.endData[J]=G[J]}else{H.data[J]=G[J]}}}});B.graph.eachNode(function(G){if(G.ignore){return}G.eachAdjacency(function(H){if(H.nodeFrom.ignore||H.nodeTo.ignore){return}var I=C.getNode(H.nodeFrom.id);var J=C.getNode(H.nodeTo.id);if(!I.adjacentTo(J)){var H=B.graph.getAdjacence(I.id,J.id);w=true;H.setData("alpha",1);H.setData("alpha",1,"start");H.setData("alpha",0,"end")}})});var w=this.preprocessSum(C);var y=!w?["node-property:alpha"]:["node-property:alpha","edge-property:alpha"];y[0]=y[0]+((z&&("node-property" in z))?(":"+c.splat(z["node-property"]).join(":")):"");y[1]=(y[1]||"edge-property:alpha")+((z&&("edge-property" in z))?(":"+c.splat(z["edge-property"]).join(":")):"");if(z&&("label-property" in z)){y.push("label-property:"+c.splat(z["label-property"]).join(":"))}B.reposition();B.graph.eachNode(function(G){if(G.id!=A&&G.pos.getp().equals(b.KER)){G.pos.set(G.endPos);G.startPos.set(G.endPos)}});B.fx.animate(c.merge(F,{modes:["polar"].concat(y),onComplete:function(){B.graph.eachNode(function(G){if(G.ignore){B.graph.removeNode(G.id)}});B.graph.eachNode(function(G){G.eachAdjacency(function(H){if(H.ignore){B.graph.removeAdjacence(H.nodeFrom.id,H.nodeTo.id)}})});F.onComplete()}}));break;default:}},contract:function(y,x){var w=this.viz;if(y.collapsed||!y.anySubnode(c.lambda(true))){return}x=c.merge(this.options,w.config,x||{},{modes:["node-property:alpha:span","linear"]});y.collapsed=true;(function z(A){A.eachSubnode(function(B){B.ignore=true;B.setData("alpha",0,x.type=="animate"?"end":"current");z(B)})})(y);if(x.type=="animate"){w.compute("end");if(w.rotated){w.rotate(w.rotated,"none",{property:"end"})}(function z(A){A.eachSubnode(function(B){B.setPos(y.getPos("end"),"end");z(B)})})(y);w.fx.animate(x)}else{if(x.type=="replot"){w.refresh()}}},expand:function(y,x){if(!("collapsed" in y)){return}var w=this.viz;x=c.merge(this.options,w.config,x||{},{modes:["node-property:alpha:span","linear"]});delete y.collapsed;(function z(A){A.eachSubnode(function(B){delete B.ignore;B.setData("alpha",1,x.type=="animate"?"end":"current");z(B)})})(y);if(x.type=="animate"){w.compute("end");if(w.rotated){w.rotate(w.rotated,"none",{property:"end"})}w.fx.animate(x)}else{if(x.type=="replot"){w.refresh()}}},preprocessSum:function(x){var w=this.viz;x.eachNode(function(z){if(!w.graph.hasNode(z.id)){w.graph.addNode(z);var A=w.graph.getNode(z.id);A.setData("alpha",0);A.setData("alpha",0,"start");A.setData("alpha",1,"end")}});var y=false;x.eachNode(function(z){z.eachAdjacency(function(A){var B=w.graph.getNode(A.nodeFrom.id);var C=w.graph.getNode(A.nodeTo.id);if(!B.adjacentTo(C)){var A=w.graph.addAdjacence(B,C,A.data);if(B.startAlpha==B.endAlpha&&C.startAlpha==C.endAlpha){y=true;A.setData("alpha",0);A.setData("alpha",0,"start");A.setData("alpha",1,"end")}}})});return y}};var a={none:{render:c.empty,contains:c.lambda(false)},circle:{render:function(z,A,w,y){var x=y.getCtx();x.beginPath();x.arc(A.x,A.y,w,0,Math.PI*2,true);x.closePath();x[z]()},contains:function(B,A,w){var y=B.x-A.x,x=B.y-A.y,z=y*y+x*x;return z<=w*w}},ellipse:{render:function(A,B,z,w,y){var x=y.getCtx();w/=2;z/=2;x.save();x.scale(z/w,w/z);x.beginPath();x.arc(B.x*(w/z),B.y*(z/w),w,0,Math.PI*2,true);x.closePath();x[A]();x.restore()},contains:function(D,C,z,w){z/=2;w/=2;var B=(z+w)/2,y=D.x-C.x,x=D.y-C.y,A=y*y+x*x;return A<=B*B}},square:{render:function(x,z,y,w){w.getCtx()[x+"Rect"](z.x-y,z.y-y,2*y,2*y)},contains:function(y,x,w){return Math.abs(x.x-y.x)<=w&&Math.abs(x.y-y.y)<=w}},rectangle:{render:function(z,A,y,w,x){x.getCtx()[z+"Rect"](A.x-y/2,A.y-w/2,y,w)},contains:function(z,y,x,w){return Math.abs(y.x-z.x)<=x/2&&Math.abs(y.y-z.y)<=w/2}},triangle:{render:function(C,D,z,w){var G=w.getCtx(),y=D.x,x=D.y-z,F=y-z,E=D.y+z,B=y+z,A=E;G.beginPath();G.moveTo(y,x);G.lineTo(F,E);G.lineTo(B,A);G.closePath();G[C]()},contains:function(y,x,w){return a.circle.contains(y,x,w)}},star:{render:function(A,C,B,x){var w=x.getCtx(),z=Math.PI/5;w.save();w.translate(C.x,C.y);w.beginPath();w.moveTo(B,0);for(var y=0;y<9;y++){w.rotate(z);if(y%2==0){w.lineTo((B/0.525731)*0.200811,0)}else{w.lineTo(B,0)}}w.closePath();w[A]();w.restore()},contains:function(y,x,w){return a.circle.contains(y,x,w)}}};var m={line:{render:function(z,y,x){var w=x.getCtx();w.beginPath();w.moveTo(z.x,z.y);w.lineTo(y.x,y.y);w.stroke()},contains:function(G,y,B,E){var z=Math.min,C=Math.max,x=z(G.x,y.x),F=C(G.x,y.x),w=z(G.y,y.y),D=C(G.y,y.y);if(B.x>=x&&B.x<=F&&B.y>=w&&B.y<=D){if(Math.abs(y.x-G.x)<=E){return true}var A=(y.y-G.y)/(y.x-G.x)*(B.x-G.x)+G.y;return Math.abs(A-B.y)<=E}return false}},arrow:{render:function(F,G,z,x,w){var H=w.getCtx();if(x){var y=F;F=G;G=y}var C=new p(G.x-F.x,G.y-F.y);C.$scale(z/C.norm());var A=new p(G.x-C.x,G.y-C.y),B=new p(-C.y/2,C.x/2),E=A.add(B),D=A.$add(B.$scale(-1));H.beginPath();H.moveTo(F.x,F.y);H.lineTo(G.x,G.y);H.stroke();H.beginPath();H.moveTo(E.x,E.y);H.lineTo(D.x,D.y);H.lineTo(G.x,G.y);H.closePath();H.fill()},contains:function(x,w,z,y){return m.line.contains(x,w,z,y)}},hyperline:{render:function(D,E,w,y){var F=y.getCtx();var z=A(D,E);if(z.a>1000||z.b>1000||z.ratio<0){F.beginPath();F.moveTo(D.x*w,D.y*w);F.lineTo(E.x*w,E.y*w);F.stroke()}else{var C=Math.atan2(E.y-z.y,E.x-z.x);var B=Math.atan2(D.y-z.y,D.x-z.x);var x=x(C,B);F.beginPath();F.arc(z.x*w,z.y*w,z.ratio*w,C,B,x);F.stroke()}function A(S,R){var K=(S.x*R.y-S.y*R.x),G=K;var J=S.squaredNorm(),I=R.squaredNorm();if(K==0){return{x:0,y:0,ratio:-1}}var Q=(S.y*I-R.y*J+S.y-R.y)/K;var O=(R.x*J-S.x*I+R.x-S.x)/G;var P=-Q/2;var N=-O/2;var M=(Q*Q+O*O)/4-1;if(M<0){return{x:0,y:0,ratio:-1}}var L=Math.sqrt(M);var H={x:P,y:N,ratio:L>1000?-1:L,a:Q,b:O};return H}function x(G,H){return(G<H)?((G+Math.PI>H)?false:true):((H+Math.PI>G)?true:false)}},contains:c.lambda(false)}};e.Plot={initialize:function(x,w){this.viz=x;this.config=x.config;this.node=x.config.Node;this.edge=x.config.Edge;this.animation=new u;this.nodeTypes=new w.Plot.NodeTypes;this.edgeTypes=new w.Plot.EdgeTypes;this.labels=x.labels},nodeHelper:a,edgeHelper:m,Interpolator:{map:{border:"color",color:"color",width:"number",height:"number",dim:"number",alpha:"number",lineWidth:"number",angularWidth:"number",span:"number",valueArray:"array-number",dimArray:"array-number"},canvas:{globalAlpha:"number",fillStyle:"color",strokeStyle:"color",lineWidth:"number",shadowBlur:"number",shadowColor:"color",shadowOffsetX:"number",shadowOffsetY:"number",miterLimit:"number"},label:{size:"number",color:"color"},compute:function(y,x,w){return y+(x-y)*w},moebius:function(D,C,F,z){var B=z.scale(-F);if(B.norm()<1){var w=B.x,E=B.y;var A=D.startPos.getc().moebiusTransformation(B);D.pos.setc(A.x,A.y);B.x=w;B.y=E}},linear:function(x,w,A){var z=x.startPos.getc(true);var y=x.endPos.getc(true);x.pos.setc(this.compute(z.x,y.x,A),this.compute(z.y,y.y,A))},polar:function(y,x,B){var A=y.startPos.getp(true);var z=y.endPos.getp();var w=z.interpolate(A,B);y.pos.setp(w.theta,w.rho)},number:function(x,C,B,w,A){var z=x[w](C,"start");var y=x[w](C,"end");x[A](C,this.compute(z,y,B))},color:function(y,w,E,B,z){var C=c.hexToRgb(y[B](w,"start"));var D=c.hexToRgb(y[B](w,"end"));var A=this.compute;var x=c.rgbToHex([parseInt(A(C[0],D[0],E)),parseInt(A(C[1],D[1],E)),parseInt(A(C[2],D[2],E))]);y[z](w,x)},"array-number":function(z,y,J,G,B){var H=z[G](y,"start"),I=z[G](y,"end"),K=[];for(var E=0,A=H.length;E<A;E++){var x=H[E],w=I[E];if(x.length){for(var D=0,F=x.length,C=[];D<F;D++){C.push(this.compute(x[D],w[D],J))}K.push(C)}else{K.push(this.compute(x,w,J))}}z[B](y,K)},node:function(x,C,E,w,D,y){w=this[w];if(C){var B=C.length;for(var z=0;z<B;z++){var A=C[z];this[w[A]](x,A,E,D,y)}}else{for(var A in w){this[w[A]](x,A,E,D,y)}}},edge:function(y,x,D,z,w,C){var B=y.adjacencies;for(var A in B){this["node"](B[A],x,D,z,w,C)}},"node-property":function(x,w,y){this["node"](x,w,y,"map","getData","setData")},"edge-property":function(x,w,y){this["edge"](x,w,y,"map","getData","setData")},"label-property":function(x,w,y){this["node"](x,w,y,"label","getLabelData","setLabelData")},"node-style":function(x,w,y){this["node"](x,w,y,"canvas","getCanvasStyle","setCanvasStyle")},"edge-style":function(x,w,y){this["edge"](x,w,y,"canvas","getCanvasStyle","setCanvasStyle")}},sequence:function(x){var y=this;x=c.merge({condition:c.lambda(false),step:c.empty,onComplete:c.empty,duration:200},x||{});var w=setInterval(function(){if(x.condition()){x.step()}else{clearInterval(w);x.onComplete()}y.viz.refresh(true)},x.duration)},prepare:function(C){var B=this.viz.graph,z={"node-property":{getter:"getData",setter:"setData"},"edge-property":{getter:"getData",setter:"setData"},"node-style":{getter:"getCanvasStyle",setter:"setCanvasStyle"},"edge-style":{getter:"getCanvasStyle",setter:"setCanvasStyle"}};var x={};if(c.type(C)=="array"){for(var A=0,w=C.length;A<w;A++){var y=C[A].split(":");x[y.shift()]=y}}else{for(var D in C){if(D=="position"){x[C.position]=[]}else{x[D]=c.splat(C[D])}}}B.eachNode(function(E){E.startPos.set(E.pos);c.each(["node-property","node-style"],function(H){if(H in x){var I=x[H];for(var G=0,F=I.length;G<F;G++){E[z[H].setter](I[G],E[z[H].getter](I[G]),"start")}}});c.each(["edge-property","edge-style"],function(F){if(F in x){var G=x[F];E.eachAdjacency(function(I){for(var J=0,H=G.length;J<H;J++){I[z[F].setter](G[J],I[z[F].getter](G[J]),"start")}})}})});return x},animate:function(z,y){z=c.merge(this.viz.config,z||{});var A=this,x=this.viz,C=x.graph,D=this.Interpolator,B=z.type==="nodefx"?this.nodeFxAnimation:this.animation;var w=this.prepare(z.modes);if(z.hideLabels){this.labels.hideLabels(true)}B.setOptions(c.merge(z,{$animating:false,compute:function(E){C.eachNode(function(F){for(var G in w){D[G](F,w[G],E,y)}});A.plot(z,this.$animating,E);this.$animating=true},complete:function(){if(z.hideLabels){A.labels.hideLabels(false)}A.plot(z);z.onComplete();z.onAfterCompute()}})).start()},nodeFx:function(y){var D=this.viz,E=D.graph,B=this.nodeFxAnimation,F=c.merge(this.viz.config,{elements:{id:false,properties:{}},reposition:false});y=c.merge(F,y||{},{onBeforeCompute:c.empty,onAfterCompute:c.empty});B.stopTimer();var C=y.elements.properties;if(!y.elements.id){E.eachNode(function(H){for(var G in C){H.setData(G,C[G],"end")}})}else{var w=c.splat(y.elements.id);c.each(w,function(I){var H=E.getNode(I);if(H){for(var G in C){H.setData(G,C[G],"end")}}})}var A=[];for(var x in C){A.push(x)}var z=["node-property:"+A.join(":")];if(y.reposition){z.push("linear");D.compute("end")}this.animate(c.merge(y,{modes:z,type:"nodefx"}))},plot:function(x,G){var E=this.viz,B=E.graph,y=E.canvas,w=E.root,C=this,F=y.getCtx(),A=Math.min,x=x||this.viz.controller;x.clearCanvas&&y.clear();var D=B.getNode(w);if(!D){return}var z=!!D.visited;B.eachNode(function(I){var H=I.getData("alpha");I.eachAdjacency(function(J){var K=J.nodeTo;if(!!K.visited===z&&I.drawn&&K.drawn){!G&&x.onBeforePlotLine(J);F.save();F.globalAlpha=A(H,K.getData("alpha"),J.getData("alpha"));C.plotLine(J,y,G);F.restore();!G&&x.onAfterPlotLine(J)}});F.save();if(I.drawn){!G&&x.onBeforePlotNode(I);C.plotNode(I,y,G);!G&&x.onAfterPlotNode(I)}if(!C.labelsHidden&&x.withLabels){if(I.drawn&&H>=0.95){C.labels.plotLabel(y,I,x)}else{C.labels.hideLabel(I,false)}}F.restore();I.visited=!z})},plotTree:function(A,x,E){var B=this,C=this.viz,y=C.canvas,z=this.config,D=y.getCtx();var w=A.getData("alpha");A.eachSubnode(function(G){if(x.plotSubtree(A,G)&&G.exist&&G.drawn){var F=A.getAdjacency(G.id);!E&&x.onBeforePlotLine(F);D.globalAlpha=Math.min(w,G.getData("alpha"));B.plotLine(F,y,E);!E&&x.onAfterPlotLine(F);B.plotTree(G,x,E)}});if(A.drawn){!E&&x.onBeforePlotNode(A);this.plotNode(A,y,E);!E&&x.onAfterPlotNode(A);if(!x.hideLabels&&x.withLabels&&w>=0.95){this.labels.plotLabel(y,A,x)}else{this.labels.hideLabel(A,false)}}else{this.labels.hideLabel(A,true)}},plotNode:function(y,x,F){var C=y.getData("type"),B=this.node.CanvasStyles;if(C!="none"){var w=y.getData("lineWidth"),A=y.getData("color"),z=y.getData("alpha"),D=x.getCtx();D.lineWidth=w;D.fillStyle=D.strokeStyle=A;D.globalAlpha=z;for(var E in B){D[E]=y.getCanvasStyle(E)}this.nodeTypes[C].render.call(this,y,x,F)}},plotLine:function(B,x,E){var A=B.getData("type"),z=this.edge.CanvasStyles;if(A!="none"){var w=B.getData("lineWidth"),y=B.getData("color"),C=x.getCtx();C.lineWidth=w;C.fillStyle=C.strokeStyle=y;for(var D in z){C[D]=B.getCanvasStyle(D)}this.edgeTypes[A].render.call(this,B,x,E)}}};e.Label={};e.Label.Native=new q({plotLabel:function(y,z,x){var w=y.getCtx();var A=z.pos.getc(true);w.font=z.getLabelData("style")+" "+z.getLabelData("size")+"px "+z.getLabelData("family");w.textAlign=z.getLabelData("textAlign");w.fillStyle=w.strokeStyle=z.getLabelData("color");w.textBaseline=z.getLabelData("textBaseline");this.renderLabel(y,z,x)},renderLabel:function(y,z,x){var w=y.getCtx();var A=z.pos.getc(true);w.fillText(z.name,A.x,A.y+z.getData("height")/2)},hideLabel:c.empty,hideLabels:c.empty});e.Label.DOM=new q({labelsHidden:false,labelContainer:false,labels:{},getLabelContainer:function(){return this.labelContainer?this.labelContainer:this.labelContainer=document.getElementById(this.viz.config.labelContainer)},getLabel:function(w){return(w in this.labels&&this.labels[w]!=null)?this.labels[w]:this.labels[w]=document.getElementById(w)},hideLabels:function(x){var w=this.getLabelContainer();if(x){w.style.display="none"}else{w.style.display=""}this.labelsHidden=x},clearLabels:function(w){for(var x in this.labels){if(w||!this.viz.graph.hasNode(x)){this.disposeLabel(x);delete this.labels[x]}}},disposeLabel:function(x){var w=this.getLabel(x);if(w&&w.parentNode){w.parentNode.removeChild(w)}},hideLabel:function(A,w){A=c.splat(A);var x=w?"":"none",y,z=this;c.each(A,function(C){var B=z.getLabel(C.id);if(B){B.style.display=x}})},fitsInCanvas:function(y,w){var x=w.getSize();if(y.x>=x.width||y.x<0||y.y>=x.height||y.y<0){return false}return true}});e.Label.HTML=new q({Implements:e.Label.DOM,plotLabel:function(z,A,y){var B=A.id,w=this.getLabel(B);if(!w&&!(w=document.getElementById(B))){w=document.createElement("div");var x=this.getLabelContainer();w.id=B;w.className="node";w.style.position="absolute";y.onCreateLabel(w,A);x.appendChild(w);this.labels[A.id]=w}this.placeLabel(w,A,y)}});e.Label.SVG=new q({Implements:e.Label.DOM,plotLabel:function(z,B,y){var D=B.id,w=this.getLabel(D);if(!w&&!(w=document.getElementById(D))){var A="http://www.w3.org/2000/svg";w=document.createElementNS(A,"svg:text");var C=document.createElementNS(A,"svg:tspan");w.appendChild(C);var x=this.getLabelContainer();w.setAttribute("id",D);w.setAttribute("class","node");x.appendChild(w);y.onCreateLabel(w,B);this.labels[B.id]=w}this.placeLabel(w,B,y)}});e.Geom=new q({initialize:function(w){this.viz=w;this.config=w.config;this.node=w.config.Node;this.edge=w.config.Edge},translate:function(x,w){w=c.splat(w);this.viz.graph.eachNode(function(y){c.each(w,function(z){y.getPos(z).$add(x)})})},setRightLevelToShow:function(z,w,B){var A=this.getRightLevelToShow(z,w),y=this.viz.labels,x=c.merge({execShow:true,execHide:true,onHide:c.empty,onShow:c.empty},B||{});z.eachLevel(0,this.config.levelsToShow,function(D){var C=D._depth-z._depth;if(C>A){x.onHide(D);if(x.execHide){D.drawn=false;D.exist=false;y.hideLabel(D,false)}}else{x.onShow(D);if(x.execShow){D.exist=true}}});z.drawn=true},getRightLevelToShow:function(z,x){var w=this.config;var A=w.levelsToShow;var y=w.constrained;if(!y){return A}while(!this.treeFitsInCanvas(z,x,A)&&A>1){A--}return A}});var d={construct:function(x){var y=(c.type(x)=="array");var w=new e(this.graphOptions,this.config.Node,this.config.Edge,this.config.Label);if(!y){(function(z,B){z.addNode(B);if(B.children){for(var A=0,C=B.children;A<C.length;A++){z.addAdjacence(B,C[A]);arguments.callee(z,C[A])}}})(w,x)}else{(function(H,I){var A=function(M){for(var L=0,J=I.length;L<J;L++){if(I[L].id==M){return I[L]}}var K={id:M,name:M};return H.addNode(K)};for(var E=0,B=I.length;E<B;E++){H.addNode(I[E]);var F=I[E].adjacencies;if(F){for(var C=0,G=F.length;C<G;C++){var z=F[C],D={};if(typeof F[C]!="string"){D=c.merge(z.data,{});z=z.nodeTo}H.addAdjacence(I[E],A(z),D)}}}})(w,x)}return w},loadJSON:function(x,w){this.json=x;if(this.labels&&this.labels.clearLabels){this.labels.clearLabels(true)}this.graph=this.construct(x);if(c.type(x)!="array"){this.root=x.id}else{this.root=x[w?w:0].id}},toJSON:function(A){A=A||"tree";if(A=="tree"){var y={};var x=this.graph.getNode(this.root);var y=(function w(D){var B={};B.id=D.id;B.name=D.name;B.data=D.data;var C=[];D.eachSubnode(function(E){C.push(w(E))});B.children=C;return B})(x);return y}else{var y=[];var z=!!this.graph.getNode(this.root).visited;this.graph.eachNode(function(C){var B={};B.id=C.id;B.name=C.name;B.data=C.data;var D=[];C.eachAdjacency(function(E){var G=E.nodeTo;if(!!G.visited===z){var F={};F.nodeTo=G.id;F.data=E.data;D.push(F)}});B.adjacencies=D;y.push(B);C.visited=!z});return y}}};var g=$jit.Layouts={};var f={label:null,compute:function(z,A,x){this.initializeLabel(x);var w=this.label,y=w.style;z.eachNode(function(D){var H=D.getData("autoWidth"),I=D.getData("autoHeight");if(H||I){delete D.data.$width;delete D.data.$height;delete D.data.$dim;var B=D.getData("width"),J=D.getData("height");y.width=H?"auto":B+"px";y.height=I?"auto":J+"px";w.innerHTML=D.name;var F=w.offsetWidth,C=w.offsetHeight;var G=D.getData("type");if(c.indexOf(["circle","square","triangle","star"],G)===-1){D.setData("width",F);D.setData("height",C)}else{var E=F>C?F:C;D.setData("width",E);D.setData("height",E);D.setData("dim",E)}}})},initializeLabel:function(w){if(!this.label){this.label=document.createElement("div");document.body.appendChild(this.label)}this.setLabelStyles(w)},setLabelStyles:function(w){c.extend(this.label.style,{visibility:"hidden",position:"absolute",width:"auto",height:"auto"});this.label.className="jit-autoadjust-label"}};g.Tree=(function(){var F=Array.prototype.slice;function D(P,K,H,N,I){var M=K.Node;var J=K.multitree;if(M.overridable){var O=-1,L=-1;P.eachNode(function(S){if(S._depth==H&&(!J||("$orn" in S.data)&&S.data.$orn==N)){var Q=S.getData("width",I);var R=S.getData("height",I);O=(O<Q)?Q:O;L=(L<R)?R:L}});return{width:O<0?M.width:O,height:L<0?M.height:L}}else{return M}}function G(I,L,K,H){var J=(H=="left"||H=="right")?"y":"x";I.getPos(L)[J]+=K}function B(I,J){var H=[];c.each(I,function(K){K=F.call(K);K[0]+=J;K[1]+=J;H.push(K)});return H}function E(K,H){if(K.length==0){return H}if(H.length==0){return K}var J=K.shift(),I=H.shift();return[[J[0],I[1]]].concat(E(K,H))}function z(H,I){I=I||[];if(H.length==0){return I}var J=H.pop();return z(H,E(J,I))}function C(K,I,L,H,J){if(K.length<=J||I.length<=J){return 0}var N=K[J][1],M=I[J][0];return Math.max(C(K,I,L,H,++J)+L,N-M+H)}function A(K,I,H){function J(N,P,M){if(P.length<=M){return[]}var O=P[M],L=C(N,O,I,H,0);return[L].concat(J(E(N,B(O,L)),P,++M))}return J([],K,0)}function x(L,K,J){function H(O,Q,N){if(Q.length<=N){return[]}var P=Q[N],M=-C(P,O,K,J,0);return[M].concat(H(E(B(P,M),O),Q,++N))}L=F.call(L);var I=H([],L.reverse(),0);return I.reverse()}function w(N,L,I,O){var J=A(N,L,I),M=x(N,L,I);if(O=="left"){M=J}else{if(O=="right"){J=M}}for(var K=0,H=[];K<J.length;K++){H[K]=(J[K]+M[K])/2}return H}function y(H,R,I,Y,W){var K=Y.multitree;var Q=["x","y"],N=["width","height"];var J=+(W=="left"||W=="right");var O=Q[J],X=Q[1-J];var T=Y.Node;var M=N[J],V=N[1-J];var L=Y.siblingOffset;var U=Y.subtreeOffset;var S=Y.align;function P(ab,af,aj){var aa=ab.getData(M,I);var ai=af||(ab.getData(V,I));var am=[],ak=[],ag=false;var Z=ai+Y.levelDistance;ab.eachSubnode(function(ao){if(ao.exist&&(!K||("$orn" in ao.data)&&ao.data.$orn==W)){if(!ag){ag=D(H,Y,ao._depth,W,I)}var an=P(ao,ag[V],aj+Z);am.push(an.tree);ak.push(an.extent)}});var ae=w(ak,U,L,S);for(var ad=0,ac=[],ah=[];ad<am.length;ad++){G(am[ad],I,ae[ad],W);ah.push(B(ak[ad],ae[ad]))}var al=[[-aa/2,aa/2]].concat(z(ah));ab.getPos(I)[O]=0;if(W=="top"||W=="left"){ab.getPos(I)[X]=aj}else{ab.getPos(I)[X]=-aj}return{tree:ab,extent:al}}P(R,false,0)}return new q({compute:function(J,I){var K=J||"start";var H=this.graph.getNode(this.root);c.extend(H,{drawn:true,exist:true,selected:true});f.compute(this.graph,K,this.config);if(!!I||!("_depth" in H)){this.graph.computeLevels(this.root,0,"ignore")}this.computePositions(H,K)},computePositions:function(L,H){var J=this.config;var I=J.multitree;var O=J.align;var K=O!=="center"&&J.indent;var P=J.orientation;var N=I?["top","right","bottom","left"]:[P];var M=this;c.each(N,function(Q){y(M.graph,L,H,M.config,Q,H);var R=["x","y"][+(Q=="left"||Q=="right")];(function S(T){T.eachSubnode(function(U){if(U.exist&&(!I||("$orn" in U.data)&&U.data.$orn==Q)){U.getPos(H)[R]+=T.getPos(H)[R];if(K){U.getPos(H)[R]+=O=="left"?K:-K}S(U)}})})(L)})}})})();$jit.ST=(function(){var x=[];function y(D){D=D||this.clickedNode;if(!this.config.constrained){return[]}var A=this.geom;var H=this.graph;var B=this.canvas;var z=D._depth,E=[];H.eachNode(function(I){if(I.exist&&!I.selected){if(I.isDescendantOf(D.id)){if(I._depth<=z){E.push(I)}}else{E.push(I)}}});var F=A.getRightLevelToShow(D,B);D.eachLevel(F,F,function(I){if(I.exist&&!I.selected){E.push(I)}});for(var G=0;G<x.length;G++){var C=this.graph.getNode(x[G]);if(!C.isDescendantOf(D.id)){E.push(C)}}return E}function w(B){var A=[],z=this.config;B=B||this.clickedNode;this.clickedNode.eachLevel(0,z.levelsToShow,function(C){if(z.multitree&&!("$orn" in C.data)&&C.anySubnode(function(D){return D.exist&&!D.drawn})){A.push(C)}else{if(C.drawn&&!C.anySubnode("drawn")){A.push(C)}}});return A}return new q({Implements:[d,o,g.Tree],initialize:function(z){var B=$jit.ST;var A={levelsToShow:2,levelDistance:30,constrained:true,Node:{type:"rectangle"},duration:700,offsetX:0,offsetY:0};this.controller=this.config=c.merge(n("Canvas","Fx","Tree","Node","Edge","Controller","Tips","NodeStyles","Events","Navigation","Label"),A,z);var C=this.config;if(C.useCanvas){this.canvas=C.useCanvas;this.config.labelContainer=this.canvas.id+"-label"}else{if(C.background){C.background=c.merge({type:"Circles"},C.background)}this.canvas=new l(this,C);this.config.labelContainer=(typeof C.injectInto=="string"?C.injectInto:C.injectInto.id)+"-label"}this.graphOptions={complex:true};this.graph=new e(this.graphOptions,this.config.Node,this.config.Edge);this.labels=new B.Label[C.Label.type](this);this.fx=new B.Plot(this,B);this.op=new B.Op(this);this.group=new B.Group(this);this.geom=new B.Geom(this);this.clickedNode=null;this.initializeExtras()},plot:function(){this.fx.plot(this.controller)},switchPosition:function(E,D,C){var z=this.geom,A=this.fx,B=this;if(!A.busy){A.busy=true;this.contract({onComplete:function(){z.switchOrientation(E);B.compute("end",false);A.busy=false;if(D=="animate"){B.onClick(B.clickedNode.id,C)}else{if(D=="replot"){B.select(B.clickedNode.id,C)}}}},E)}},switchAlignment:function(B,A,z){this.config.align=B;if(A=="animate"){this.select(this.clickedNode.id,z)}else{if(A=="replot"){this.onClick(this.clickedNode.id,z)}}},addNodeInPath:function(z){x.push(z);this.select((this.clickedNode&&this.clickedNode.id)||this.root)},clearNodesInPath:function(z){x.length=0;this.select((this.clickedNode&&this.clickedNode.id)||this.root)},refresh:function(){this.reposition();this.select((this.clickedNode&&this.clickedNode.id)||this.root)},reposition:function(){this.graph.computeLevels(this.root,0,"ignore");this.geom.setRightLevelToShow(this.clickedNode,this.canvas);this.graph.eachNode(function(z){if(z.exist){z.drawn=true}});this.compute("end")},requestNodes:function(B,C){var A=c.merge(this.controller,C),z=this.config.levelsToShow;if(A.request){var E=[],D=B._depth;B.eachLevel(0,z,function(F){if(F.drawn&&!F.anySubnode()){E.push(F);F._level=z-(F._depth-D)}});this.group.requestNodes(E,A)}else{A.onComplete()}},contract:function(D,E){var C=this.config.orientation;var z=this.geom,B=this.group;if(E){z.switchOrientation(E)}var A=y.call(this);if(E){z.switchOrientation(C)}B.contract(A,c.merge(this.controller,D))},move:function(A,B){this.compute("end",false);var z=B.Move,C={x:z.offsetX,y:z.offsetY};if(z.enable){this.geom.translate(A.endPos.add(C).$scale(-1),"end")}this.fx.animate(c.merge(this.controller,{modes:["linear"]},B))},expand:function(A,B){var z=w.call(this,A);this.group.expand(z,c.merge(this.controller,B))},selectPath:function(C){var B=this;this.graph.eachNode(function(E){E.selected=false});function D(F){if(F==null||F.selected){return}F.selected=true;c.each(B.group.getSiblings([F])[F.id],function(G){G.exist=true;G.drawn=true});var E=F.getParents();E=(E.length>0)?E[0]:null;D(E)}for(var z=0,A=[C.id].concat(x);z<A.length;z++){D(this.graph.getNode(A[z]))}},setRoot:function(G,F,E){if(this.busy){return}this.busy=true;var D=this,B=this.canvas;var z=this.graph.getNode(this.root);var A=this.graph.getNode(G);function C(){if(this.config.multitree&&A.data.$orn){var I=A.data.$orn;var J={left:"right",right:"left",top:"bottom",bottom:"top"}[I];z.data.$orn=J;(function H(K){K.eachSubnode(function(L){if(L.id!=G){L.data.$orn=J;H(L)}})})(z);delete A.data.$orn}this.root=G;this.clickedNode=A;this.graph.computeLevels(this.root,0,"ignore");this.geom.setRightLevelToShow(A,B,{execHide:false,onShow:function(K){if(!K.drawn){K.drawn=true;K.setData("alpha",1,"end");K.setData("alpha",0);K.pos.setc(A.pos.x,A.pos.y)}}});this.compute("end");this.busy=true;this.fx.animate({modes:["linear","node-property:alpha"],onComplete:function(){D.busy=false;D.onClick(G,{onComplete:function(){E&&E.onComplete()}})}})}delete z.data.$orns;if(F=="animate"){C.call(this);D.selectPath(A)}else{if(F=="replot"){C.call(this);this.select(this.root)}}},addSubtree:function(z,B,A){if(B=="replot"){this.op.sum(z,c.extend({type:"replot"},A||{}))}else{if(B=="animate"){this.op.sum(z,c.extend({type:"fade:seq"},A||{}))}}},removeSubtree:function(E,A,D,C){var B=this.graph.getNode(E),z=[];B.eachLevel(+!A,false,function(F){z.push(F.id)});if(D=="replot"){this.op.removeNode(z,c.extend({type:"replot"},C||{}))}else{if(D=="animate"){this.op.removeNode(z,c.extend({type:"fade:seq"},C||{}))}}},select:function(z,C){var H=this.group,F=this.geom;var D=this.graph.getNode(z),B=this.canvas;var G=this.graph.getNode(this.root);var A=c.merge(this.controller,C);var E=this;A.onBeforeCompute(D);this.selectPath(D);this.clickedNode=D;this.requestNodes(D,{onComplete:function(){H.hide(H.prepare(y.call(E)),A);F.setRightLevelToShow(D,B);E.compute("current");E.graph.eachNode(function(K){var J=K.pos.getc(true);K.startPos.setc(J.x,J.y);K.endPos.setc(J.x,J.y);K.visited=false});var I={x:A.offsetX,y:A.offsetY};E.geom.translate(D.endPos.add(I).$scale(-1),["start","current","end"]);H.show(w.call(E));E.plot();A.onAfterCompute(E.clickedNode);A.onComplete()}})},onClick:function(A,H){var C=this.canvas,G=this,z=this.geom,D=this.config;var F={Move:{enable:true,offsetX:D.offsetX||0,offsetY:D.offsetY||0},setRightLevelToShowConfig:false,onBeforeRequest:c.empty,onBeforeContract:c.empty,onBeforeMove:c.empty,onBeforeExpand:c.empty};var B=c.merge(this.controller,F,H);if(!this.busy){this.busy=true;var E=this.graph.getNode(A);this.selectPath(E,this.clickedNode);this.clickedNode=E;B.onBeforeCompute(E);B.onBeforeRequest(E);this.requestNodes(E,{onComplete:function(){B.onBeforeContract(E);G.contract({onComplete:function(){z.setRightLevelToShow(E,C,B.setRightLevelToShowConfig);B.onBeforeMove(E);G.move(E,{Move:B.Move,onComplete:function(){B.onBeforeExpand(E);G.expand(E,{onComplete:function(){G.busy=false;B.onAfterCompute(A);B.onComplete()}})}})}})}})}}})})();$jit.ST.$extend=true;$jit.ST.Op=new q({Implements:e.Op});$jit.ST.Group=new q({initialize:function(w){this.viz=w;this.canvas=w.canvas;this.config=w.config;this.animation=new u;this.nodes=null},requestNodes:function(B,A){var z=0,x=B.length,D={};var y=function(){A.onComplete()};var w=this.viz;if(x==0){y()}for(var C=0;C<x;C++){D[B[C].id]=B[C];A.request(B[C].id,B[C]._level,{onComplete:function(F,E){if(E&&E.children){E.id=F;w.op.sum(E,{type:"nothing"})}if(++z==x){w.graph.computeLevels(w.root,0);y()}}})}},contract:function(y,x){var w=this.viz;var z=this;y=this.prepare(y);this.animation.setOptions(c.merge(x,{$animating:false,compute:function(A){if(A==1){A=0.99}z.plotStep(1-A,x,this.$animating);this.$animating="contract"},complete:function(){z.hide(y,x)}})).start()},hide:function(y,x){var w=this.viz;for(var z=0;z<y.length;z++){if(true||!x||!x.request){y[z].eachLevel(1,false,function(B){if(B.exist){c.extend(B,{drawn:false,exist:false})}})}else{var A=[];y[z].eachLevel(1,false,function(B){A.push(B.id)});w.op.removeNode(A,{type:"nothing"});w.labels.clearLabels()}}x.onComplete()},expand:function(x,w){var y=this;this.show(x);this.animation.setOptions(c.merge(w,{$animating:false,compute:function(z){y.plotStep(z,w,this.$animating);this.$animating="expand"},complete:function(){y.plotStep(undefined,w,false);w.onComplete()}})).start()},show:function(w){var x=this.config;this.prepare(w);c.each(w,function(z){if(x.multitree&&!("$orn" in z.data)){delete z.data.$orns;var y=" ";z.eachSubnode(function(A){if(("$orn" in A.data)&&y.indexOf(A.data.$orn)<0&&A.exist&&!A.drawn){y+=A.data.$orn+" "}});z.data.$orns=y}z.eachLevel(0,x.levelsToShow,function(A){if(A.exist){A.drawn=true}})})},prepare:function(w){this.nodes=this.getNodesWithChildren(w);return this.nodes},getNodesWithChildren:function(y){var x=[],A=this.config,w=this.viz.root;y.sort(function(E,D){return(E._depth<=D._depth)-(E._depth>=D._depth)});for(var B=0;B<y.length;B++){if(y[B].anySubnode("exist")){for(var z=B+1,C=false;!C&&z<y.length;z++){if(!A.multitree||"$orn" in y[z].data){C=C||y[B].isDescendantOf(y[z].id)}}if(!C){x.push(y[B])}}}return x},plotStep:function(G,C,I){var F=this.viz,z=this.config,y=F.canvas,H=y.getCtx(),w=this.nodes;var B,A;var x={};for(B=0;B<w.length;B++){A=w[B];x[A.id]=[];var E=z.multitree&&!("$orn" in A.data);var D=E&&A.data.$orns;A.eachSubgraph(function(J){if(E&&D&&D.indexOf(J.data.$orn)>0&&J.drawn){J.drawn=false;x[A.id].push(J)}else{if((!E||!D)&&J.drawn){J.drawn=false;x[A.id].push(J)}}});A.drawn=true}if(w.length>0){F.fx.plot()}for(B in x){c.each(x[B],function(J){J.drawn=true})}for(B=0;B<w.length;B++){A=w[B];H.save();F.fx.plotSubtree(A,C,G,I);H.restore()}},getSiblings:function(w){var x={};c.each(w,function(A){var z=A.getParents();if(z.length==0){x[A.id]=[A]}else{var y=[];z[0].eachSubnode(function(B){y.push(B)});x[A.id]=y}});return x}});$jit.ST.Geom=new q({Implements:e.Geom,switchOrientation:function(w){this.config.orientation=w},dispatch:function(){var x=Array.prototype.slice.call(arguments);var y=x.shift(),w=x.length;var z=function(A){return typeof A=="function"?A():A};if(w==2){return(y=="top"||y=="bottom")?z(x[0]):z(x[1])}else{if(w==4){switch(y){case"top":return z(x[0]);case"right":return z(x[1]);case"bottom":return z(x[2]);case"left":return z(x[3])}}}return undefined},getSize:function(E,D){var C=E.data,z=this.config;var y=z.siblingOffset;var B=(z.multitree&&("$orn" in C)&&C.$orn)||z.orientation;var x=E.getData("width")+y;var A=E.getData("height")+y;if(!D){return this.dispatch(B,A,x)}else{return this.dispatch(B,x,A)}},getTreeBaseSize:function(A,B,x){var y=this.getSize(A,true),w=0,z=this;if(x(B,A)){return y}if(B===0){return 0}A.eachSubnode(function(C){w+=z.getTreeBaseSize(C,B-1,x)});return(y>w?y:w)+this.config.subtreeOffset},getEdge:function(C,B,A){var y=function(E,w){return function(){return C.pos.add(new p(E,w))}};var D=this.node;var x=C.getData("width");var z=C.getData("height");if(B=="begin"){if(D.align=="center"){return this.dispatch(A,y(0,z/2),y(-x/2,0),y(0,-z/2),y(x/2,0))}else{if(D.align=="left"){return this.dispatch(A,y(0,z),y(0,0),y(0,0),y(x,0))}else{if(D.align=="right"){return this.dispatch(A,y(0,0),y(-x,0),y(0,-z),y(0,0))}else{throw"align: not implemented"}}}}else{if(B=="end"){if(D.align=="center"){return this.dispatch(A,y(0,-z/2),y(x/2,0),y(0,z/2),y(-x/2,0))}else{if(D.align=="left"){return this.dispatch(A,y(0,0),y(x,0),y(0,z),y(0,0))}else{if(D.align=="right"){return this.dispatch(A,y(0,-z),y(0,0),y(0,0),y(-x,0))}else{throw"align: not implemented"}}}}}},getScaledTreePosition:function(B,D){var C=this.node;var x=B.getData("width");var A=B.getData("height");var z=(this.config.multitree&&("$orn" in B.data)&&B.data.$orn)||this.config.orientation;var y=function(E,w){return function(){return B.pos.add(new p(E,w)).$scale(1-D)}};if(C.align=="left"){return this.dispatch(z,y(0,A),y(0,0),y(0,0),y(x,0))}else{if(C.align=="center"){return this.dispatch(z,y(0,A/2),y(-x/2,0),y(0,-A/2),y(x/2,0))}else{if(C.align=="right"){return this.dispatch(z,y(0,0),y(-x,0),y(0,-A),y(0,0))}else{throw"align: not implemented"}}}},treeFitsInCanvas:function(B,w,C){var y=w.getSize();var z=(this.config.multitree&&("$orn" in B.data)&&B.data.$orn)||this.config.orientation;var x=this.dispatch(z,y.width,y.height);var A=this.getTreeBaseSize(B,C,function(E,D){return E===0||!D.anySubnode()});return(A<x)}});$jit.ST.Plot=new q({Implements:e.Plot,plotSubtree:function(z,w,A,E){var C=this.viz,x=C.canvas,y=C.config;A=Math.min(Math.max(0.001,A),1);if(A>=0){z.drawn=false;var D=x.getCtx();var B=C.geom.getScaledTreePosition(z,A);D.translate(B.x,B.y);D.scale(A,A)}this.plotTree(z,c.merge(w,{withLabels:true,hideLabels:!!A,plotSubtree:function(I,G){var F=y.multitree&&!("$orn" in z.data);var H=F&&z.getData("orns");return !F||H.indexOf(elem.getData("orn"))>-1}}),E);if(A>=0){z.drawn=true}},getAlignedPos:function(B,z,w){var y=this.node;var A,x;if(y.align=="center"){A={x:B.x-z/2,y:B.y-w/2}}else{if(y.align=="left"){x=this.config.orientation;if(x=="bottom"||x=="top"){A={x:B.x-z/2,y:B.y}}else{A={x:B.x,y:B.y-w/2}}}else{if(y.align=="right"){x=this.config.orientation;if(x=="bottom"||x=="top"){A={x:B.x-z/2,y:B.y-w}}else{A={x:B.x-z,y:B.y-w/2}}}else{throw"align: not implemented"}}}return A},getOrientation:function(w){var y=this.config;var x=y.orientation;if(y.multitree){var z=w.nodeFrom;var A=w.nodeTo;x=(("$orn" in z.data)&&z.data.$orn)||(("$orn" in A.data)&&A.data.$orn)}return x}});$jit.ST.Label={};$jit.ST.Label.Native=new q({Implements:e.Label.Native,renderLabel:function(y,z,x){var w=y.getCtx();var A=z.pos.getc(true);w.fillText(z.name,A.x,A.y)}});$jit.ST.Label.DOM=new q({Implements:e.Label.DOM,placeLabel:function(P,J,F){var B=J.pos.getc(true),O=this.viz.config,K=O.Node,x=this.viz.canvas,C=J.getData("width"),M=J.getData("height"),y=x.getSize(),G,N;var A=x.translateOffsetX,z=x.translateOffsetY,E=x.scaleOffsetX,D=x.scaleOffsetY,I=B.x*E+A,H=B.y*D+z;if(K.align=="center"){G={x:Math.round(I-C/2+y.width/2),y:Math.round(H-M/2+y.height/2)}}else{if(K.align=="left"){N=O.orientation;if(N=="bottom"||N=="top"){G={x:Math.round(I-C/2+y.width/2),y:Math.round(H+y.height/2)}}else{G={x:Math.round(I+y.width/2),y:Math.round(H-M/2+y.height/2)}}}else{if(K.align=="right"){N=O.orientation;if(N=="bottom"||N=="top"){G={x:Math.round(I-C/2+y.width/2),y:Math.round(H-M+y.height/2)}}else{G={x:Math.round(I-C+y.width/2),y:Math.round(H-M/2+y.height/2)}}}else{throw"align: not implemented"}}}var L=P.style;L.left=G.x+"px";L.top=G.y+"px";L.display=this.fitsInCanvas(G,x)?"":"none";F.onPlaceLabel(P,J)}});$jit.ST.Label.SVG=new q({Implements:[$jit.ST.Label.DOM,e.Label.SVG],initialize:function(w){this.viz=w}});$jit.ST.Label.HTML=new q({Implements:[$jit.ST.Label.DOM,e.Label.HTML],initialize:function(w){this.viz=w}});$jit.ST.Plot.NodeTypes=new q({none:{render:c.empty,contains:c.lambda(false)},circle:{render:function(x,w){var z=x.getData("dim"),A=this.getAlignedPos(x.pos.getc(true),z,z),y=z/2;this.nodeHelper.circle.render("fill",{x:A.x+y,y:A.y+y},y,w)},contains:function(w,A){var y=w.getData("dim"),z=this.getAlignedPos(w.pos.getc(true),y,y),x=y/2;this.nodeHelper.circle.contains({x:z.x+x,y:z.y+x},x)}},square:{render:function(x,w){var z=x.getData("dim"),y=z/2,A=this.getAlignedPos(x.pos.getc(true),z,z);this.nodeHelper.square.render("fill",{x:A.x+y,y:A.y+y},y,w)},contains:function(w,A){var y=w.getData("dim"),z=this.getAlignedPos(w.pos.getc(true),y,y),x=y/2;this.nodeHelper.square.contains({x:z.x+x,y:z.y+x},x)}},ellipse:{render:function(z,x){var y=z.getData("width"),w=z.getData("height"),A=this.getAlignedPos(z.pos.getc(true),y,w);this.nodeHelper.ellipse.render("fill",{x:A.x+y/2,y:A.y+w/2},y,w,x)},contains:function(y,A){var x=y.getData("width"),w=y.getData("height"),z=this.getAlignedPos(y.pos.getc(true),x,w);this.nodeHelper.ellipse.contains({x:z.x+x/2,y:z.y+w/2},x,w,canvas)}},rectangle:{render:function(z,x){var y=z.getData("width"),w=z.getData("height"),A=this.getAlignedPos(z.pos.getc(true),y,w);this.nodeHelper.rectangle.render("fill",{x:A.x+y/2,y:A.y+w/2},y,w,x)},contains:function(y,A){var x=y.getData("width"),w=y.getData("height"),z=this.getAlignedPos(y.pos.getc(true),x,w);this.nodeHelper.rectangle.contains({x:z.x+x/2,y:z.y+w/2},x,w,canvas)}}});$jit.ST.Plot.EdgeTypes=new q({none:c.empty,line:{render:function(x,z){var y=this.getOrientation(x),A=x.nodeFrom,B=x.nodeTo,w=A._depth<B._depth,D=this.viz.geom.getEdge(w?A:B,"begin",y),C=this.viz.geom.getEdge(w?B:A,"end",y);this.edgeHelper.line.render(D,C,z)},contains:function(x,D){var y=this.getOrientation(x),z=x.nodeFrom,A=x.nodeTo,w=z._depth<A._depth,C=this.viz.geom.getEdge(w?z:A,"begin",y),B=this.viz.geom.getEdge(w?A:z,"end",y);return this.edgeHelper.line.contains(C,B,D,this.edge.epsilon)}},arrow:{render:function(C,x){var B=this.getOrientation(C),y=C.nodeFrom,w=C.nodeTo,A=C.getData("dim"),E=this.viz.geom.getEdge(y,"begin",B),F=this.viz.geom.getEdge(w,"end",B),D=C.data.$direction,z=(D&&D.length>1&&D[0]!=y.id);this.edgeHelper.arrow.render(E,F,A,z,x)},contains:function(x,D){var y=this.getOrientation(x),z=x.nodeFrom,A=x.nodeTo,w=z._depth<A._depth,C=this.viz.geom.getEdge(w?z:A,"begin",y),B=this.viz.geom.getEdge(w?A:z,"end",y);return this.edgeHelper.arrow.contains(C,B,D,this.edge.epsilon)}},"quadratic:begin":{render:function(C,w){var B=this.getOrientation(C);var A=C.nodeFrom,D=C.nodeTo,F=A._depth<D._depth,x=this.viz.geom.getEdge(F?A:D,"begin",B),y=this.viz.geom.getEdge(F?D:A,"end",B),z=C.getData("dim"),E=w.getCtx();E.beginPath();E.moveTo(x.x,x.y);switch(B){case"left":E.quadraticCurveTo(x.x+z,x.y,y.x,y.y);break;case"right":E.quadraticCurveTo(x.x-z,x.y,y.x,y.y);break;case"top":E.quadraticCurveTo(x.x,x.y+z,y.x,y.y);break;case"bottom":E.quadraticCurveTo(x.x,x.y-z,y.x,y.y);break}E.stroke()}},"quadratic:end":{render:function(C,w){var B=this.getOrientation(C);var A=C.nodeFrom,D=C.nodeTo,F=A._depth<D._depth,x=this.viz.geom.getEdge(F?A:D,"begin",B),y=this.viz.geom.getEdge(F?D:A,"end",B),z=C.getData("dim"),E=w.getCtx();E.beginPath();E.moveTo(x.x,x.y);switch(B){case"left":E.quadraticCurveTo(y.x-z,y.y,y.x,y.y);break;case"right":E.quadraticCurveTo(y.x+z,y.y,y.x,y.y);break;case"top":E.quadraticCurveTo(y.x,y.y-z,y.x,y.y);break;case"bottom":E.quadraticCurveTo(y.x,y.y+z,y.x,y.y);break}E.stroke()}},bezier:{render:function(C,w){var B=this.getOrientation(C),A=C.nodeFrom,D=C.nodeTo,F=A._depth<D._depth,x=this.viz.geom.getEdge(F?A:D,"begin",B),y=this.viz.geom.getEdge(F?D:A,"end",B),z=C.getData("dim"),E=w.getCtx();E.beginPath();E.moveTo(x.x,x.y);switch(B){case"left":E.bezierCurveTo(x.x+z,x.y,y.x-z,y.y,y.x,y.y);break;case"right":E.bezierCurveTo(x.x-z,x.y,y.x+z,y.y,y.x,y.y);break;case"top":E.bezierCurveTo(x.x,x.y+z,y.x,y.y-z,y.x,y.y);break;case"bottom":E.bezierCurveTo(x.x,x.y-z,y.x,y.y+z,y.x,y.y);break}E.stroke()}}});$jit.ST.Plot.NodeTypes.implement({"areachart-stacked":{render:function(V,D){var T=V.pos.getc(true),w=V.getData("width"),A=V.getData("height"),G=this.getAlignedPos(T,w,A),aa=G.x,Z=G.y,L=V.getData("stringArray"),F=V.getData("dimArray"),B=V.getData("valueArray"),ac=c.reduce(B,function(ai,aj){return ai+aj[0]},0),ab=c.reduce(B,function(ai,aj){return ai+aj[1]},0),I=V.getData("colorArray"),C=I.length,X=V.getData("config"),J=V.getData("gradient"),ah=X.showLabels,N=X.showAggregates,ad=X.Label,S=V.getData("prev");var M=D.getCtx(),H=V.getData("border");if(I&&F&&L){for(var ag=0,ae=F.length,K=0,E=0,W=0;ag<ae;ag++){M.fillStyle=M.strokeStyle=I[ag%C];M.save();if(J&&(F[ag][0]>0||F[ag][1]>0)){var Q=K+F[ag][0],O=E+F[ag][1],af=Math.atan((O-Q)/w),Y=55;var U=M.createLinearGradient(aa+w/2,Z-(Q+O)/2,aa+w/2+Y*Math.sin(af),Z-(Q+O)/2+Y*Math.cos(af));var P=c.rgbToHex(c.map(c.hexToRgb(I[ag%C].slice(1)),function(x){return(x*0.85)>>0}));U.addColorStop(0,I[ag%C]);U.addColorStop(1,P);M.fillStyle=U}M.beginPath();M.moveTo(aa,Z-K);M.lineTo(aa+w,Z-E);M.lineTo(aa+w,Z-E-F[ag][1]);M.lineTo(aa,Z-K-F[ag][0]);M.lineTo(aa,Z-K);M.fill();M.restore();if(H){var R=H.name==L[ag];var z=R?0.7:0.8;var P=c.rgbToHex(c.map(c.hexToRgb(I[ag%C].slice(1)),function(x){return(x*z)>>0}));M.strokeStyle=P;M.lineWidth=R?4:1;M.save();M.beginPath();if(H.index===0){M.moveTo(aa,Z-K);M.lineTo(aa,Z-K-F[ag][0])}else{M.moveTo(aa+w,Z-E);M.lineTo(aa+w,Z-E-F[ag][1])}M.stroke();M.restore()}K+=(F[ag][0]||0);E+=(F[ag][1]||0);if(F[ag][0]>0){W+=(B[ag][0]||0)}}if(S&&ad.type=="Native"){M.save();M.beginPath();M.fillStyle=M.strokeStyle=ad.color;M.font=ad.style+" "+ad.size+"px "+ad.family;M.textAlign="center";M.textBaseline="middle";if(N(V.name,ac,ab,V)){M.fillText(W,aa,Z-K-X.labelOffset-ad.size/2,w)}if(ah(V.name,ac,ab,V)){M.fillText(V.name,aa,Z+ad.size/2+X.labelOffset)}M.restore()}}},contains:function(C,E){var J=C.pos.getc(true),z=C.getData("width"),N=C.getData("height"),M=this.getAlignedPos(J,z,N),L=M.x,K=M.y,O=C.getData("dimArray"),w=E.x-L;if(E.x<L||E.x>L+z||E.y>K||E.y<K-N){return false}for(var F=0,D=O.length,I=K,A=K;F<D;F++){var B=O[F];I-=B[0];A-=B[1];var G=I+(A-I)*w/z;if(E.y>=G){var H=+(w>z/2);return{name:C.getData("stringArray")[F],color:C.getData("colorArray")[F],value:C.getData("valueArray")[F][H],index:H}}}return false}}});$jit.AreaChart=new q({st:null,colors:["#416D9C","#70A35E","#EBB056","#C74243","#83548B","#909291","#557EAA"],selected:{},busy:false,initialize:function(y){this.controller=this.config=c.merge(n("Canvas","Margin","Label","AreaChart"),{Label:{type:"Native"}},y);var z=this.config.showLabels,x=c.type(z),A=this.config.showAggregates,w=c.type(A);this.config.showLabels=x=="function"?z:c.lambda(z);this.config.showAggregates=w=="function"?A:c.lambda(A);this.initializeViz()},initializeViz:function(){var y=this.config,B=this,w=y.type.split(":")[0],A={};var x=new $jit.ST({injectInto:y.injectInto,orientation:"bottom",levelDistance:0,siblingOffset:0,subtreeOffset:0,withLabels:y.Label.type!="Native",useCanvas:y.useCanvas,Label:{type:y.Label.type},Node:{overridable:true,type:"areachart-"+w,align:"left",width:1,height:1},Edge:{type:"none"},Tips:{enable:y.Tips.enable,type:"Native",force:true,onShow:function(G,F,D){var E=D;y.Tips.onShow(G,E,F)}},Events:{enable:true,type:"Native",onClick:function(F,G,D){if(!y.filterOnClick&&!y.Events.enable){return}var E=G.getContains();if(E){y.filterOnClick&&B.filter(E.name)}y.Events.enable&&y.Events.onClick(E,G,D)},onRightClick:function(E,F,D){if(!y.restoreOnRightClick){return}B.restore()},onMouseMove:function(F,G,D){if(!y.selectOnHover){return}if(F){var E=G.getContains();B.select(F.id,E.name,E.index)}else{B.select(false,false,false)}}},onCreateLabel:function(J,G){var P=y.Label,O=G.getData("valueArray"),H=c.reduce(O,function(Q,R){return Q+R[0]},0),M=c.reduce(O,function(Q,R){return Q+R[1]},0);if(G.getData("prev")){var L={wrapper:document.createElement("div"),aggregate:document.createElement("div"),label:document.createElement("div")};var D=L.wrapper,N=L.label,E=L.aggregate,F=D.style,K=N.style,I=E.style;A[G.id]=L;D.appendChild(N);D.appendChild(E);if(!y.showLabels(G.name,H,M,G)){N.style.display="none"}if(!y.showAggregates(G.name,H,M,G)){E.style.display="none"}F.position="relative";F.overflow="visible";F.fontSize=P.size+"px";F.fontFamily=P.family;F.color=P.color;F.textAlign="center";I.position=K.position="absolute";J.style.width=G.getData("width")+"px";J.style.height=G.getData("height")+"px";N.innerHTML=G.name;J.appendChild(D)}},onPlaceLabel:function(U,O){if(!O.getData("prev")){return}var S=A[O.id],E=S.wrapper.style,D=S.label.style,N=S.aggregate.style,L=O.getData("width"),J=O.getData("height"),I=O.getData("dimArray"),F=O.getData("valueArray"),K=c.reduce(F,function(V,W){return V+W[0]},0),G=c.reduce(F,function(V,W){return V+W[1]},0),H=parseInt(E.fontSize,10),M=U.style;if(I&&F){if(y.showLabels(O.name,K,G,O)){D.display=""}else{D.display="none"}if(y.showAggregates(O.name,K,G,O)){N.display=""}else{N.display="none"}E.width=N.width=D.width=U.style.width=L+"px";N.left=D.left=-L/2+"px";for(var R=0,P=F.length,Q=0,T=0;R<P;R++){if(I[R][0]>0){Q+=F[R][0];T+=I[R][0]}}N.top=(-H-y.labelOffset)+"px";D.top=(y.labelOffset+T)+"px";U.style.top=parseInt(U.style.top,10)-T+"px";U.style.height=E.height=T+"px";S.aggregate.innerHTML=Q}}});var z=x.canvas.getSize(),C=y.Margin;x.config.offsetY=-z.height/2+C.bottom+(y.showLabels&&(y.labelOffset+y.Label.size));x.config.offsetX=(C.right-C.left)/2;this.st=x;this.canvas=this.st.canvas},loadJSON:function(N){var K=c.time(),B=[],G=this.st,Q=c.splat(N.label),J=c.splat(N.color||this.colors),O=this.config,x=!!O.type.split(":")[1],z=O.animate;for(var L=0,y=N.values,I=y.length;L<I-1;L++){var P=y[L],E=y[L-1],F=y[L+1];var M=c.splat(y[L].values),w=c.splat(y[L+1].values);var A=c.zip(M,w);var D=0,C=0;B.push({id:K+P.label,name:P.label,data:{value:A,"$valueArray":A,"$colorArray":J,"$stringArray":Q,"$next":F.label,"$prev":E?E.label:false,"$config":O,"$gradient":x},children:[]})}var H={id:K+"$root",name:"",data:{"$type":"none","$width":1,"$height":1},children:B};G.loadJSON(H);this.normalizeDims();G.compute();G.select(G.root);if(z){G.fx.animate({modes:["node-property:height:dimArray"],duration:1500})}},updateJSON:function(z,C){if(this.busy){return}this.busy=true;var y=this.st,B=y.graph,D=z.label&&c.splat(z.label),x=z.values,w=this.config.animate,A=this;c.each(x,function(F){var L=B.getByName(F.label);if(L){F.values=c.splat(F.values);var G=L.getData("stringArray"),K=L.getData("valueArray");c.each(K,function(M,N){M[0]=F.values[N];if(D){G[N]=D[N]}});L.setData("valueArray",K);var I=L.getData("prev"),H=L.getData("next"),E=B.getByName(H);if(I){var J=B.getByName(I);if(J){var K=J.getData("valueArray");c.each(K,function(M,N){M[1]=F.values[N]})}}if(!E){var K=L.getData("valueArray");c.each(K,function(M,N){M[1]=F.values[N]})}}});this.normalizeDims();y.compute();y.select(y.root);if(w){y.fx.animate({modes:["node-property:height:dimArray"],duration:1500,onComplete:function(){A.busy=false;C&&C.onComplete()}})}},filter:function(){if(this.busy){return}this.busy=true;if(this.config.Tips.enable){this.st.tips.hide()}this.select(false,false,false);var x=Array.prototype.slice.call(arguments);var w=this.st.graph.getNode(this.st.root);var y=this;w.eachAdjacency(function(z){var C=z.nodeTo,B=C.getData("dimArray"),A=C.getData("stringArray");C.setData("dimArray",c.map(B,function(E,D){return(c.indexOf(x,A[D])>-1)?E:[0,0]}),"end")});this.st.fx.animate({modes:["node-property:dimArray"],duration:1500,onComplete:function(){y.busy=false}})},restore:function(){if(this.busy){return}this.busy=true;if(this.config.Tips.enable){this.st.tips.hide()}this.select(false,false,false);this.normalizeDims();var w=this;this.st.fx.animate({modes:["node-property:height:dimArray"],duration:1500,onComplete:function(){w.busy=false}})},select:function(B,x,w){if(!this.config.selectOnHover){return}var y=this.selected;if(y.id!=B||y.name!=x||y.index!=w){y.id=B;y.name=x;y.index=w;this.st.graph.eachNode(function(C){C.setData("border",false)});if(B){var A=this.st.graph.getNode(B);A.setData("border",y);var z=w===0?"prev":"next";z=A.getData(z);if(z){A=this.st.graph.getByName(z);if(A){A.setData("border",{name:x,index:1-w})}}}this.st.plot()}},getLegend:function(){var y={};var z;this.st.graph.getNode(this.st.root).eachAdjacency(function(A){z=A.nodeTo});var x=z.getData("colorArray"),w=x.length;c.each(z.getData("stringArray"),function(B,A){y[B]=x[A%w]});return y},getMaxValue:function(){var w=0;this.st.graph.eachNode(function(B){var y=B.getData("valueArray"),x=0,A=0;c.each(y,function(C){x+=+C[0];A+=+C[1]});var z=A>x?A:x;w=w>z?w:z});return w},normalizeDims:function(){var C=this.st.graph.getNode(this.st.root),z=0;C.eachAdjacency(function(){z++});var B=this.getMaxValue()||1,F=this.st.canvas.getSize(),y=this.config,A=y.Margin,D=y.labelOffset+y.Label.size,w=(F.width-(A.left+A.right))/z,x=y.animate,E=F.height-(A.top+A.bottom)-(y.showAggregates&&D)-(y.showLabels&&D);this.st.graph.eachNode(function(L){var I=0,K=0,G=[];c.each(L.getData("valueArray"),function(M){I+=+M[0];K+=+M[1];G.push([0,0])});var J=K>I?K:I;L.setData("width",w);if(x){L.setData("height",J*E/B,"end");L.setData("dimArray",c.map(L.getData("valueArray"),function(M){return[M[0]*E/B,M[1]*E/B]}),"end");var H=L.getData("dimArray");if(!H){L.setData("dimArray",G)}}else{L.setData("height",J*E/B);L.setData("dimArray",c.map(L.getData("valueArray"),function(M){return[M[0]*E/B,M[1]*E/B]}))}})}});n.BarChart={$extend:true,animate:true,type:"stacked",labelOffset:3,barsOffset:0,hoveredColor:"#9fd4ff",orientation:"horizontal",showAggregates:true,showLabels:true,Tips:{enable:false,onShow:c.empty,onHide:c.empty},Events:{enable:false,onClick:c.empty}};$jit.ST.Plot.NodeTypes.implement({"barchart-stacked":{render:function(Q,C){var H=Q.pos.getc(true),P=Q.getData("width"),N=Q.getData("height"),L=this.getAlignedPos(H,P,N),K=L.x,J=L.y,M=Q.getData("dimArray"),F=Q.getData("valueArray"),E=Q.getData("colorArray"),B=E.length,X=Q.getData("stringArray");var S=C.getCtx(),w={},T=Q.getData("border"),z=Q.getData("gradient"),Z=Q.getData("config"),A=Z.orientation=="horizontal",D=Z.showAggregates,O=Z.showLabels,I=Z.Label;if(E&&M&&X){for(var W=0,R=M.length,V=0,G=0;W<R;W++){S.fillStyle=S.strokeStyle=E[W%B];if(z){var Y;if(A){Y=S.createLinearGradient(K+V+M[W]/2,J,K+V+M[W]/2,J+N)}else{Y=S.createLinearGradient(K,J-V-M[W]/2,K+P,J-V-M[W]/2)}var U=c.rgbToHex(c.map(c.hexToRgb(E[W%B].slice(1)),function(x){return(x*0.5)>>0}));Y.addColorStop(0,U);Y.addColorStop(0.5,E[W%B]);Y.addColorStop(1,U);S.fillStyle=Y}if(A){S.fillRect(K+V,J,M[W],N)}else{S.fillRect(K,J-V-M[W],P,M[W])}if(T&&T.name==X[W]){w.acum=V;w.dimValue=M[W]}V+=(M[W]||0);G+=(F[W]||0)}if(T){S.save();S.lineWidth=2;S.strokeStyle=T.color;if(A){S.strokeRect(K+w.acum+1,J+1,w.dimValue-2,N-2)}else{S.strokeRect(K+1,J-w.acum-w.dimValue+1,P-2,w.dimValue-2)}S.restore()}if(I.type=="Native"){S.save();S.fillStyle=S.strokeStyle=I.color;S.font=I.style+" "+I.size+"px "+I.family;S.textBaseline="middle";if(D(Q.name,G)){if(A){S.textAlign="right";S.fillText(G,K+V-Z.labelOffset,J+N/2)}else{S.textAlign="center";S.fillText(G,K+P/2,J-N-I.size/2-Z.labelOffset)}}if(O(Q.name,G,Q)){if(A){S.textAlign="center";S.translate(K-Z.labelOffset-I.size/2,J+N/2);S.rotate(Math.PI/2);S.fillText(Q.name,0,0)}else{S.textAlign="center";S.fillText(Q.name,K+P/2,J+I.size/2+Z.labelOffset)}}S.restore()}}},contains:function(D,F){var I=D.pos.getc(true),A=D.getData("width"),N=D.getData("height"),M=this.getAlignedPos(I,A,N),L=M.x,J=M.y,O=D.getData("dimArray"),B=D.getData("config"),z=F.x-L,w=B.orientation=="horizontal";if(w){if(F.x<L||F.x>L+A||F.y>J+N||F.y<J){return false}}else{if(F.x<L||F.x>L+A||F.y>J||F.y<J-N){return false}}for(var G=0,E=O.length,K=(w?L:J);G<E;G++){var C=O[G];if(w){K+=C;var H=K;if(F.x<=H){return{name:D.getData("stringArray")[G],color:D.getData("colorArray")[G],value:D.getData("valueArray")[G],label:D.name}}}else{K-=C;var H=K;if(F.y>=H){return{name:D.getData("stringArray")[G],color:D.getData("colorArray")[G],value:D.getData("valueArray")[G],label:D.name}}}}return false}},"barchart-grouped":{render:function(R,C){var I=R.pos.getc(true),Q=R.getData("width"),O=R.getData("height"),M=this.getAlignedPos(I,Q,O),L=M.x,K=M.y,N=R.getData("dimArray"),G=R.getData("valueArray"),X=G.length,F=R.getData("colorArray"),B=F.length,Z=R.getData("stringArray");var T=C.getCtx(),w={},U=R.getData("border"),z=R.getData("gradient"),ab=R.getData("config"),A=ab.orientation=="horizontal",E=ab.showAggregates,P=ab.showLabels,J=ab.Label,D=(A?O:Q)/X;if(F&&N&&Z){for(var Y=0,S=X,W=0,H=0;Y<S;Y++){T.fillStyle=T.strokeStyle=F[Y%B];if(z){var aa;if(A){aa=T.createLinearGradient(L+N[Y]/2,K+D*Y,L+N[Y]/2,K+D*(Y+1))}else{aa=T.createLinearGradient(L+D*Y,K-N[Y]/2,L+D*(Y+1),K-N[Y]/2)}var V=c.rgbToHex(c.map(c.hexToRgb(F[Y%B].slice(1)),function(x){return(x*0.5)>>0}));aa.addColorStop(0,V);aa.addColorStop(0.5,F[Y%B]);aa.addColorStop(1,V);T.fillStyle=aa}if(A){T.fillRect(L,K+D*Y,N[Y],D)}else{T.fillRect(L+D*Y,K-N[Y],D,N[Y])}if(U&&U.name==Z[Y]){w.acum=D*Y;w.dimValue=N[Y]}W+=(N[Y]||0);H+=(G[Y]||0)}if(U){T.save();T.lineWidth=2;T.strokeStyle=U.color;if(A){T.strokeRect(L+1,K+w.acum+1,w.dimValue-2,D-2)}else{T.strokeRect(L+w.acum+1,K-w.dimValue+1,D-2,w.dimValue-2)}T.restore()}if(J.type=="Native"){T.save();T.fillStyle=T.strokeStyle=J.color;T.font=J.style+" "+J.size+"px "+J.family;T.textBaseline="middle";if(E(R.name,H)){if(A){T.textAlign="right";T.fillText(H,L+Math.max.apply(null,N)-ab.labelOffset,K+O/2)}else{T.textAlign="center";T.fillText(H,L+Q/2,K-Math.max.apply(null,N)-J.size/2-ab.labelOffset)}}if(P(R.name,H,R)){if(A){T.textAlign="center";T.translate(L-ab.labelOffset-J.size/2,K+O/2);T.rotate(Math.PI/2);T.fillText(R.name,0,0)}else{T.textAlign="center";T.fillText(R.name,L+Q/2,K+J.size/2+ab.labelOffset)}}T.restore()}}},contains:function(J,F){var B=J.pos.getc(true),I=J.getData("width"),H=J.getData("height"),E=this.getAlignedPos(B,I,H),D=E.x,C=E.y,G=J.getData("dimArray"),M=G.length,P=J.getData("config"),A=F.x-D,w=P.orientation=="horizontal",z=(w?H:I)/M;if(w){if(F.x<D||F.x>D+I||F.y>C+H||F.y<C){return false}}else{if(F.x<D||F.x>D+I||F.y>C||F.y<C-H){return false}}for(var L=0,K=G.length;L<K;L++){var O=G[L];if(w){var N=C+z*L;if(F.x<=D+O&&F.y>=N&&F.y<=N+z){return{name:J.getData("stringArray")[L],color:J.getData("colorArray")[L],value:J.getData("valueArray")[L],label:J.name}}}else{var N=D+z*L;if(F.x>=N&&F.x<=N+z&&F.y>=C-O){return{name:J.getData("stringArray")[L],color:J.getData("colorArray")[L],value:J.getData("valueArray")[L],label:J.name}}}}return false}}});$jit.BarChart=new q({st:null,colors:["#416D9C","#70A35E","#EBB056","#C74243","#83548B","#909291","#557EAA"],selected:{},busy:false,initialize:function(y){this.controller=this.config=c.merge(n("Canvas","Margin","Label","BarChart"),{Label:{type:"Native"}},y);var z=this.config.showLabels,x=c.type(z),A=this.config.showAggregates,w=c.type(A);this.config.showLabels=x=="function"?z:c.lambda(z);this.config.showAggregates=w=="function"?A:c.lambda(A);this.initializeViz()},initializeViz:function(){var y=this.config,B=this;var w=y.type.split(":")[0],D=y.orientation=="horizontal",A={};var x=new $jit.ST({injectInto:y.injectInto,orientation:D?"left":"bottom",levelDistance:0,siblingOffset:y.barsOffset,subtreeOffset:0,withLabels:y.Label.type!="Native",useCanvas:y.useCanvas,Label:{type:y.Label.type},Node:{overridable:true,type:"barchart-"+w,align:"left",width:1,height:1},Edge:{type:"none"},Tips:{enable:y.Tips.enable,type:"Native",force:true,onShow:function(H,G,E){var F=E;y.Tips.onShow(H,F,G)}},Events:{enable:true,type:"Native",onClick:function(G,H,E){if(!y.Events.enable){return}var F=H.getContains();y.Events.onClick(F,H,E)},onMouseMove:function(G,H,E){if(!y.hoveredColor){return}if(G){var F=H.getContains();B.select(G.id,F.name,F.index)}else{B.select(false,false,false)}}},onCreateLabel:function(J,H){var P=y.Label,N=H.getData("valueArray"),M=c.reduce(N,function(Q,R){return Q+R},0);var L={wrapper:document.createElement("div"),aggregate:document.createElement("div"),label:document.createElement("div")};var E=L.wrapper,O=L.label,F=L.aggregate,G=E.style,K=O.style,I=F.style;A[H.id]=L;E.appendChild(O);E.appendChild(F);if(!y.showLabels(H.name,M,H)){K.display="none"}if(!y.showAggregates(H.name,M,H)){I.display="none"}G.position="relative";G.overflow="visible";G.fontSize=P.size+"px";G.fontFamily=P.family;G.color=P.color;G.textAlign="center";I.position=K.position="absolute";J.style.width=H.getData("width")+"px";J.style.height=H.getData("height")+"px";I.left=K.left="0px";O.innerHTML=H.name;J.appendChild(E)},onPlaceLabel:function(L,H){if(!A[H.id]){return}var N=A[H.id],I=N.wrapper.style,P=N.label.style,M=N.aggregate.style,Q=y.type.split(":")[0]=="grouped",E=y.orientation=="horizontal",T=H.getData("dimArray"),U=H.getData("valueArray"),F=(Q&&E)?Math.max.apply(null,T):H.getData("width"),S=(Q&&!E)?Math.max.apply(null,T):H.getData("height"),G=parseInt(I.fontSize,10),O=L.style;if(T&&U){I.width=M.width=P.width=L.style.width=F+"px";for(var K=0,J=U.length,R=0;K<J;K++){if(T[K]>0){R+=U[K]}}if(y.showLabels(H.name,R,H)){P.display=""}else{P.display="none"}if(y.showAggregates(H.name,R,H)){M.display=""}else{M.display="none"}if(y.orientation=="horizontal"){M.textAlign="right";P.textAlign="left";P.textIndex=M.textIndent=y.labelOffset+"px";M.top=P.top=(S-G)/2+"px";L.style.height=I.height=S+"px"}else{M.top=(-G-y.labelOffset)+"px";P.top=(y.labelOffset+S)+"px";L.style.top=parseInt(L.style.top,10)-S+"px";L.style.height=I.height=S+"px"}N.aggregate.innerHTML=R}}});var z=x.canvas.getSize(),C=y.Margin;if(D){x.config.offsetX=z.width/2-C.left-(y.showLabels&&(y.labelOffset+y.Label.size));x.config.offsetY=(C.bottom-C.top)/2}else{x.config.offsetY=-z.height/2+C.bottom+(y.showLabels&&(y.labelOffset+y.Label.size));x.config.offsetX=(C.right-C.left)/2}this.st=x;this.canvas=this.st.canvas},loadJSON:function(K){if(this.busy){return}this.busy=true;var I=c.time(),C=[],D=this.st,N=c.splat(K.label),H=c.splat(K.color||this.colors),L=this.config,w=!!L.type.split(":")[1],z=L.animate,y=L.orientation=="horizontal",A=this;for(var J=0,x=K.values,F=x.length;J<F;J++){var M=x[J];var B=c.splat(x[J].values);var G=0;C.push({id:I+M.label,name:M.label,data:{value:B,"$valueArray":B,"$colorArray":H,"$stringArray":N,"$gradient":w,"$config":L},children:[]})}var E={id:I+"$root",name:"",data:{"$type":"none","$width":1,"$height":1},children:C};D.loadJSON(E);this.normalizeDims();D.compute();D.select(D.root);if(z){if(y){D.fx.animate({modes:["node-property:width:dimArray"],duration:1500,onComplete:function(){A.busy=false}})}else{D.fx.animate({modes:["node-property:height:dimArray"],duration:1500,onComplete:function(){A.busy=false}})}}else{this.busy=false}},updateJSON:function(z,C){if(this.busy){return}this.busy=true;var y=this.st;var B=y.graph;var x=z.values;var w=this.config.animate;var A=this;var D=this.config.orientation=="horizontal";c.each(x,function(E){var F=B.getByName(E.label);if(F){F.setData("valueArray",c.splat(E.values));if(z.label){F.setData("stringArray",c.splat(z.label))}}});this.normalizeDims();y.compute();y.select(y.root);if(w){if(D){y.fx.animate({modes:["node-property:width:dimArray"],duration:1500,onComplete:function(){A.busy=false;C&&C.onComplete()}})}else{y.fx.animate({modes:["node-property:height:dimArray"],duration:1500,onComplete:function(){A.busy=false;C&&C.onComplete()}})}}},select:function(y,w){if(!this.config.hoveredColor){return}var x=this.selected;if(x.id!=y||x.name!=w){x.id=y;x.name=w;x.color=this.config.hoveredColor;this.st.graph.eachNode(function(z){if(y==z.id){z.setData("border",x)}else{z.setData("border",false)}});this.st.plot()}},getLegend:function(){var y={};var z;this.st.graph.getNode(this.st.root).eachAdjacency(function(A){z=A.nodeTo});var x=z.getData("colorArray"),w=x.length;c.each(z.getData("stringArray"),function(B,A){y[B]=x[A%w]});return y},getMaxValue:function(){var x=0,w=this.config.type.split(":")[0]=="stacked";this.st.graph.eachNode(function(A){var y=A.getData("valueArray"),z=0;if(!y){return}if(w){c.each(y,function(B){z+=+B})}else{z=Math.max.apply(null,y)}x=x>z?x:z});return x},setBarType:function(w){this.config.type=w;this.st.config.Node.type="barchart-"+w.split(":")[0]},normalizeDims:function(){var G=this.st.graph.getNode(this.st.root),B=0;G.eachAdjacency(function(){B++});var D=this.getMaxValue()||1,J=this.st.canvas.getSize(),z=this.config,C=z.Margin,H=C.left+C.right,A=C.top+C.bottom,x=z.orientation=="horizontal",w=(J[x?"height":"width"]-(x?A:H)-(B-1)*z.barsOffset)/B,y=z.animate,I=J[x?"width":"height"]-(x?H:A)-(!x&&z.showAggregates&&(z.Label.size+z.labelOffset))-(z.showLabels&&(z.Label.size+z.labelOffset)),F=x?"height":"width",E=x?"width":"height";this.st.graph.eachNode(function(N){var M=0,K=[];c.each(N.getData("valueArray"),function(O){M+=+O;K.push(0)});N.setData(F,w);if(y){N.setData(E,M*I/D,"end");N.setData("dimArray",c.map(N.getData("valueArray"),function(O){return O*I/D}),"end");var L=N.getData("dimArray");if(!L){N.setData("dimArray",K)}}else{N.setData(E,M*I/D);N.setData("dimArray",c.map(N.getData("valueArray"),function(O){return O*I/D}))}})}});n.PieChart={$extend:true,animate:true,offset:25,sliceOffset:0,labelOffset:3,type:"stacked",hoveredColor:"#9fd4ff",Events:{enable:false,onClick:c.empty},Tips:{enable:false,onShow:c.empty,onHide:c.empty},showLabels:true,resizeLabels:false,updateHeights:false};g.Radial=new q({compute:function(x){var y=c.splat(x||["current","start","end"]);f.compute(this.graph,y,this.config);this.graph.computeLevels(this.root,0,"ignore");var w=this.createLevelDistanceFunc();this.computeAngularWidths(y);this.computePositions(y,w)},computePositions:function(D,A){var F=D;var E=this.graph;var B=E.getNode(this.root);var C=this.parent;var w=this.config;for(var y=0,x=F.length;y<x;y++){var z=F[y];B.setPos(k(0,0),z);B.setData("span",Math.PI*2,z)}B.angleSpan={begin:0,end:2*Math.PI};E.eachBFS(this.root,function(K){var Q=K.angleSpan.end-K.angleSpan.begin;var S=K.angleSpan.begin;var R=A(K);var T=0,G=[],J={};K.eachSubnode(function(W){T+=W._treeAngularWidth;for(var X=0,V=F.length;X<V;X++){var Z=F[X],Y=W.getData("dim",Z);J[Z]=(Z in J)?(Y>J[Z]?Y:J[Z]):Y}G.push(W)},"ignore");if(C&&C.id==K.id&&G.length>0&&G[0].dist){G.sort(function(W,V){return(W.dist>=V.dist)-(W.dist<=V.dist)})}for(var M=0,O=G.length;M<O;M++){var I=G[M];if(!I._flag){var U=I._treeAngularWidth/T*Q;var H=S+U/2;for(var N=0,L=F.length;N<L;N++){var P=F[N];I.setPos(k(H,R),P);I.setData("span",U,P);I.setData("dim-quotient",I.getData("dim",P)/J[P],P)}I.angleSpan={begin:S,end:S+U};S+=U}}},"ignore")},setAngularWidthForNodes:function(w){this.graph.eachBFS(this.root,function(z,x){var y=z.getData("angularWidth",w[0])||5;z._angularWidth=y/x},"ignore")},setSubtreesAngularWidth:function(){var w=this;this.graph.eachNode(function(x){w.setSubtreeAngularWidth(x)},"ignore")},setSubtreeAngularWidth:function(z){var y=this,x=z._angularWidth,w=0;z.eachSubnode(function(A){y.setSubtreeAngularWidth(A);w+=A._treeAngularWidth},"ignore");z._treeAngularWidth=Math.max(x,w)},computeAngularWidths:function(w){this.setAngularWidthForNodes(w);this.setSubtreesAngularWidth()}});$jit.Sunburst=new q({Implements:[d,o,g.Radial],initialize:function(w){var y=$jit.Sunburst;var x={interpolation:"linear",levelDistance:100,Node:{type:"multipie",height:0},Edge:{type:"none"},Label:{textAlign:"start",textBaseline:"middle"}};this.controller=this.config=c.merge(n("Canvas","Node","Edge","Fx","Tips","NodeStyles","Events","Navigation","Controller","Label"),x,w);var z=this.config;if(z.useCanvas){this.canvas=z.useCanvas;this.config.labelContainer=this.canvas.id+"-label"}else{if(z.background){z.background=c.merge({type:"Circles"},z.background)}this.canvas=new l(this,z);this.config.labelContainer=(typeof z.injectInto=="string"?z.injectInto:z.injectInto.id)+"-label"}this.graphOptions={complex:false,Node:{selected:false,exist:true,drawn:true}};this.graph=new e(this.graphOptions,this.config.Node,this.config.Edge);this.labels=new y.Label[z.Label.type](this);this.fx=new y.Plot(this,y);this.op=new y.Op(this);this.json=null;this.root=null;this.rotated=null;this.busy=false;this.initializeExtras()},createLevelDistanceFunc:function(){var w=this.config.levelDistance;return function(x){return(x._depth+1)*w}},refresh:function(){this.compute();this.plot()},reposition:function(){this.compute("end")},rotate:function(y,z,x){var w=y.getPos(x.property||"current").getp(true).theta;this.rotated=y;this.rotateAngle(-w,z,x)},rotateAngle:function(y,B,x){var z=this;var w=c.merge(this.config,x||{},{modes:["polar"]});var A=x.property||(B==="animate"?"end":"current");if(B==="animate"){this.fx.animation.pause()}this.graph.eachNode(function(D){var C=D.getPos(A);C.theta+=y;if(C.theta<0){C.theta+=Math.PI*2}});if(B=="animate"){this.fx.animate(w)}else{if(B=="replot"){this.fx.plot();this.busy=false}}},plot:function(){this.fx.plot()}});$jit.Sunburst.$extend=true;(function(w){w.Op=new q({Implements:e.Op});w.Plot=new q({Implements:e.Plot});w.Label={};w.Label.Native=new q({Implements:e.Label.Native,initialize:function(x){this.viz=x;this.label=x.config.Label;this.config=x.config},renderLabel:function(C,E,G){var N=E.getData("span");if(N<Math.PI/2&&Math.tan(N)*this.config.levelDistance*E._depth<10){return}var O=C.getCtx();var A=O.measureText(E.name);if(E.id==this.viz.root){var M=-A.width/2,K=0,L=0;var z=0}else{var D=5;var z=G.levelDistance-D;var J=E.pos.clone();J.rho+=D;var B=J.getp(true);var H=J.getc(true);var M=H.x,K=H.y;var F=Math.PI;var I=(B.theta>F/2&&B.theta<3*F/2);var L=I?B.theta+F:B.theta;if(I){M-=Math.abs(Math.cos(B.theta)*A.width);K+=Math.sin(B.theta)*A.width}else{if(E.id==this.viz.root){M-=A.width/2}}}O.save();O.translate(M,K);O.rotate(L);O.fillText(E.name,0,0);O.restore()}});w.Label.SVG=new q({Implements:e.Label.SVG,initialize:function(x){this.viz=x},placeLabel:function(N,C,E){var J=C.pos.getc(true),M=this.viz,A=this.viz.canvas;var F=A.getSize();var B={x:Math.round(J.x+F.width/2),y:Math.round(J.y+F.height/2)};N.setAttribute("x",B.x);N.setAttribute("y",B.y);var G=N.getBBox();if(G){var L=N.getAttribute("x");var I=N.getAttribute("y");var z=C.pos.getp(true);var D=Math.PI;var H=(z.theta>D/2&&z.theta<3*D/2);if(H){N.setAttribute("x",L-G.width);N.setAttribute("y",I-G.height)}else{if(C.id==M.root){N.setAttribute("x",L-G.width/2)}}var K=H?z.theta+D:z.theta;if(C._depth){N.setAttribute("transform","rotate("+K*360/(2*D)+" "+L+" "+I+")")}}E.onPlaceLabel(N,C)}});w.Label.HTML=new q({Implements:e.Label.HTML,initialize:function(x){this.viz=x},placeLabel:function(G,A,C){var E=A.pos.clone(),y=this.viz.canvas,F=A.getData("height"),B=((F||A._depth==0)?F:this.viz.config.levelDistance)/2,D=y.getSize();E.rho+=B;E=E.getc(true);var z={x:Math.round(E.x+D.width/2),y:Math.round(E.y+D.height/2)};var x=G.style;x.left=z.x+"px";x.top=z.y+"px";x.display=this.fitsInCanvas(z,y)?"":"none";C.onPlaceLabel(G,A)}});w.Plot.NodeTypes=new q({none:{render:c.empty,contains:c.lambda(false),anglecontains:function(B,D){var A=B.getData("span")/2,y=B.pos.theta;var z=y-A,x=y+A;if(z<0){z+=Math.PI*2}var C=Math.atan2(D.y,D.x);if(C<0){C+=Math.PI*2}if(z>x){return(C>z&&C<=Math.PI*2)||C<x}else{return C>z&&C<x}}},pie:{render:function(C,A){var G=C.getData("span")/2,z=C.pos.theta;var B=z-G,D=z+G;var F=C.pos.getp(true);var x=new b(F.rho,B);var y=x.getc(true);x.theta=D;var E=x.getc(true);var H=A.getCtx();H.beginPath();H.moveTo(0,0);H.lineTo(y.x,y.y);H.moveTo(0,0);H.lineTo(E.x,E.y);H.moveTo(0,0);H.arc(0,0,F.rho*C.getData("dim-quotient"),B,D,false);H.fill()},contains:function(z,B){if(this.nodeTypes.none.anglecontains.call(this,z,B)){var x=Math.sqrt(B.x*B.x+B.y*B.y);var y=this.config.levelDistance,A=z._depth;return(x<=y*A)}return false}},multipie:{render:function(D,B){var K=D.getData("height");var E=K?K:this.config.levelDistance;var J=D.getData("span")/2,A=D.pos.theta;var C=A-J,G=A+J;var I=D.pos.getp(true);var y=new b(I.rho,C);var z=y.getc(true);y.theta=G;var H=y.getc(true);y.rho+=E;var x=y.getc(true);y.theta=C;var F=y.getc(true);var L=B.getCtx();L.moveTo(0,0);L.beginPath();L.arc(0,0,I.rho,C,G,false);L.arc(0,0,I.rho+E,G,C,true);L.moveTo(z.x,z.y);L.lineTo(F.x,F.y);L.moveTo(H.x,H.y);L.lineTo(x.x,x.y);L.fill();if(D.collapsed){L.save();L.lineWidth=2;L.moveTo(0,0);L.beginPath();L.arc(0,0,I.rho+E+5,G-0.01,C+0.01,true);L.stroke();L.restore()}},contains:function(A,D){if(this.nodeTypes.none.anglecontains.call(this,A,D)){var y=Math.sqrt(D.x*D.x+D.y*D.y);var x=A.getData("height");var B=x?x:this.config.levelDistance;var z=this.config.levelDistance,C=A._depth;return(y>=z*C)&&(y<=(z*C+B))}return false}},"gradient-multipie":{render:function(A,x){var F=x.getCtx();var E=A.getData("height");var B=E?E:this.config.levelDistance;var y=F.createRadialGradient(0,0,A.getPos().rho,0,0,A.getPos().rho+B);var D=c.hexToRgb(A.getData("color")),C=[];c.each(D,function(G){C.push(parseInt(G*0.5,10))});var z=c.rgbToHex(C);y.addColorStop(0,z);y.addColorStop(1,A.getData("color"));F.fillStyle=y;this.nodeTypes.multipie.render.call(this,A,x)},contains:function(x,y){return this.nodeTypes.multipie.contains.call(this,x,y)}},"gradient-pie":{render:function(C,z){var x=z.getCtx();var D=x.createRadialGradient(0,0,0,0,0,C.getPos().rho);var B=c.hexToRgb(C.getData("color")),y=[];c.each(B,function(E){y.push(parseInt(E*0.5,10))});var A=c.rgbToHex(y);D.addColorStop(1,A);D.addColorStop(0,C.getData("color"));x.fillStyle=D;this.nodeTypes.pie.render.call(this,C,z)},contains:function(x,y){return this.nodeTypes.pie.contains.call(this,x,y)}}});w.Plot.EdgeTypes=new q({none:c.empty,line:{render:function(x,y){var A=x.nodeFrom.pos.getc(true),z=x.nodeTo.pos.getc(true);this.edgeHelper.line.render(A,z,y)},contains:function(x,A){var z=x.nodeFrom.pos.getc(true),y=x.nodeTo.pos.getc(true);return this.edgeHelper.line.contains(z,y,A,this.edge.epsilon)}},arrow:{render:function(y,z){var D=y.nodeFrom.pos.getc(true),C=y.nodeTo.pos.getc(true),B=y.getData("dim"),A=y.data.$direction,x=(A&&A.length>1&&A[0]!=y.nodeFrom.id);this.edgeHelper.arrow.render(D,C,B,x,z)},contains:function(x,A){var z=x.nodeFrom.pos.getc(true),y=x.nodeTo.pos.getc(true);return this.edgeHelper.arrow.contains(z,y,A,this.edge.epsilon)}},hyperline:{render:function(x,y){var B=x.nodeFrom.pos.getc(),A=x.nodeTo.pos.getc(),z=Math.max(B.norm(),A.norm());this.edgeHelper.hyperline.render(B.$scale(1/z),A.$scale(1/z),z,y)},contains:c.lambda(false)}})})($jit.Sunburst);$jit.Sunburst.Plot.NodeTypes.implement({"piechart-stacked":{render:function(U,A){var T=U.pos.getp(true),C=U.getData("dimArray"),S=U.getData("valueArray"),G=U.getData("colorArray"),z=G.length,M=U.getData("stringArray"),P=U.getData("span")/2,K=U.pos.theta,F=K-P,J=K+P,R=new b;var N=A.getCtx(),L={},I=U.getData("gradient"),D=U.getData("border"),Z=U.getData("config"),ai=Z.showLabels,Y=Z.resizeLabels,ab=Z.Label;var ae=Z.sliceOffset*Math.cos((F+J)/2);var E=Z.sliceOffset*Math.sin((F+J)/2);if(G&&C&&M){for(var af=0,ac=C.length,w=0,X=0;af<ac;af++){var B=C[af],ag=G[af%z];if(B<=0){continue}N.fillStyle=N.strokeStyle=ag;if(I&&B){var ad=N.createRadialGradient(ae,E,w+Z.sliceOffset,ae,E,w+B+Z.sliceOffset);var x=c.hexToRgb(ag),W=c.map(x,function(al){return(al*0.8)>>0}),y=c.rgbToHex(W);ad.addColorStop(0,ag);ad.addColorStop(0.5,ag);ad.addColorStop(1,y);N.fillStyle=ad}R.rho=w+Z.sliceOffset;R.theta=F;var ah=R.getc(true);R.theta=J;var O=R.getc(true);R.rho+=B;var aj=R.getc(true);R.theta=F;var Q=R.getc(true);N.beginPath();N.arc(ae,E,w+0.01,F,J,false);N.arc(ae,E,w+B+0.01,J,F,true);N.fill();if(D&&D.name==M[af]){L.acum=w;L.dimValue=C[af];L.begin=F;L.end=J}w+=(B||0);X+=(S[af]||0)}if(D){N.save();N.globalCompositeOperation="source-over";N.lineWidth=2;N.strokeStyle=D.color;var aa=F<J?1:-1;N.beginPath();N.arc(ae,E,L.acum+0.01+1,L.begin,L.end,false);N.arc(ae,E,L.acum+L.dimValue+0.01-1,L.end,L.begin,true);N.closePath();N.stroke();N.restore()}if(ai&&ab.type=="Native"){N.save();N.fillStyle=N.strokeStyle=ab.color;var V=Y?U.getData("normalizedDim"):1,H=(ab.size*V)>>0;H=H<+Y?+Y:H;N.font=ab.style+" "+H+"px "+ab.family;N.textBaseline="middle";N.textAlign="center";R.rho=w+Z.labelOffset+Z.sliceOffset;R.theta=U.pos.theta;var ak=R.getc(true);N.fillText(U.name,ak.x,ak.y);N.restore()}}},contains:function(z,D){if(this.nodeTypes.none.anglecontains.call(this,z,D)){var F=Math.sqrt(D.x*D.x+D.y*D.y);var w=this.config.levelDistance,C=z._depth;var x=z.getData("config");if(F<=w*C+x.sliceOffset){var G=z.getData("dimArray");for(var B=0,A=G.length,E=x.sliceOffset;B<A;B++){var y=G[B];if(F>=E&&F<=E+y){return{name:z.getData("stringArray")[B],color:z.getData("colorArray")[B],value:z.getData("valueArray")[B],label:z.name}}E+=y}}return false}return false}}});$jit.PieChart=new q({sb:null,colors:["#416D9C","#70A35E","#EBB056","#C74243","#83548B","#909291","#557EAA"],selected:{},busy:false,initialize:function(w){this.controller=this.config=c.merge(n("Canvas","PieChart","Label"),{Label:{type:"Native"}},w);this.initializeViz()},initializeViz:function(){var x=this.config,A=this;var w=x.type.split(":")[0];var B=new $jit.Sunburst({injectInto:x.injectInto,useCanvas:x.useCanvas,withLabels:x.Label.type!="Native",Label:{type:x.Label.type},Node:{overridable:true,type:"piechart-"+w,width:1,height:1},Edge:{type:"none"},Tips:{enable:x.Tips.enable,type:"Native",force:true,onShow:function(F,E,C){var D=C;x.Tips.onShow(F,D,E)}},Events:{enable:true,type:"Native",onClick:function(E,F,C){if(!x.Events.enable){return}var D=F.getContains();x.Events.onClick(D,F,C)},onMouseMove:function(E,F,C){if(!x.hoveredColor){return}if(E){var D=F.getContains();A.select(E.id,D.name,D.index)}else{A.select(false,false,false)}}},onCreateLabel:function(F,E){var C=x.Label;if(x.showLabels){var D=F.style;D.fontSize=C.size+"px";D.fontFamily=C.family;D.color=C.color;D.textAlign="center";F.innerHTML=E.name}},onPlaceLabel:function(S,M){if(!x.showLabels){return}var G=M.pos.getp(true),J=M.getData("dimArray"),P=M.getData("span")/2,H=M.pos.theta,R=H-P,D=H+P,U=new b;var L=x.showLabels,F=x.resizeLabels,I=x.Label;if(J){for(var Q=0,N=J.length,O=0;Q<N;Q++){O+=J[Q]}var T=F?M.getData("normalizedDim"):1,C=(I.size*T)>>0;C=C<+F?+F:C;S.style.fontSize=C+"px";U.rho=O+x.labelOffset+x.sliceOffset;U.theta=(R+D)/2;var G=U.getc(true);var E=A.canvas.getSize();var K={x:Math.round(G.x+E.width/2),y:Math.round(G.y+E.height/2)};S.style.left=K.x+"px";S.style.top=K.y+"px"}}});var z=B.canvas.getSize(),y=Math.min;B.config.levelDistance=y(z.width,z.height)/2-x.offset-x.sliceOffset;this.sb=B;this.canvas=this.sb.canvas;this.canvas.getCtx().globalCompositeOperation="lighter"},loadJSON:function(K){var I=c.time(),C=[],w=this.sb,N=c.splat(K.label),E=N.length,H=c.splat(K.color||this.colors),z=H.length,L=this.config,x=!!L.type.split(":")[1],A=L.animate,G=E==1;for(var J=0,y=K.values,F=y.length;J<F;J++){var M=y[J];var B=c.splat(M.values);C.push({id:I+M.label,name:M.label,data:{value:B,"$valueArray":B,"$colorArray":G?c.splat(H[J%z]):H,"$stringArray":N,"$gradient":x,"$config":L,"$angularWidth":c.reduce(B,function(O,P){return O+P})},children:[]})}var D={id:I+"$root",name:"",data:{"$type":"none","$width":1,"$height":1},children:C};w.loadJSON(D);this.normalizeDims();w.refresh();if(A){w.fx.animate({modes:["node-property:dimArray"],duration:1500})}},updateJSON:function(y,B){if(this.busy){return}this.busy=true;var C=this.sb;var A=C.graph;var x=y.values;var w=this.config.animate;var z=this;c.each(x,function(D){var F=A.getByName(D.label),E=c.splat(D.values);if(F){F.setData("valueArray",E);F.setData("angularWidth",c.reduce(E,function(G,H){return G+H}));if(y.label){F.setData("stringArray",c.splat(y.label))}}});this.normalizeDims();if(w){C.compute("end");C.fx.animate({modes:["node-property:dimArray:span","linear"],duration:1500,onComplete:function(){z.busy=false;B&&B.onComplete()}})}else{C.refresh()}},select:function(y,w){if(!this.config.hoveredColor){return}var x=this.selected;if(x.id!=y||x.name!=w){x.id=y;x.name=w;x.color=this.config.hoveredColor;this.sb.graph.eachNode(function(z){if(y==z.id){z.setData("border",x)}else{z.setData("border",false)}});this.sb.plot()}},getLegend:function(){var y={};var z;this.sb.graph.getNode(this.sb.root).eachAdjacency(function(A){z=A.nodeTo});var x=z.getData("colorArray"),w=x.length;c.each(z.getData("stringArray"),function(B,A){y[B]=x[A%w]});return y},getMaxValue:function(){var w=0;this.sb.graph.eachNode(function(z){var x=z.getData("valueArray"),y=0;c.each(x,function(A){y+=+A});w=w>y?w:y});return w},normalizeDims:function(){var x=this.sb.graph.getNode(this.sb.root),w=0;x.eachAdjacency(function(){w++});var B=this.getMaxValue()||1,A=this.config,y=A.animate,z=this.sb.config.levelDistance;this.sb.graph.eachNode(function(G){var F=0,C=[];c.each(G.getData("valueArray"),function(H){F+=+H;C.push(1)});var E=(C.length==1)&&!A.updateHeights;if(y){G.setData("dimArray",c.map(G.getData("valueArray"),function(H){return E?z:(H*z/B)}),"end");var D=G.getData("dimArray");if(!D){G.setData("dimArray",C)}}else{G.setData("dimArray",c.map(G.getData("valueArray"),function(H){return E?z:(H*z/B)}))}G.setData("normalizedDim",F/B)})}});g.TM={};g.TM.SliceAndDice=new q({compute:function(B){var x=this.graph.getNode(this.clickedNode&&this.clickedNode.id||this.root);this.controller.onBeforeCompute(x);var z=this.canvas.getSize(),y=this.config,A=z.width,w=z.height;this.graph.computeLevels(this.root,0,"ignore");x.getPos(B).setc(-A/2,-w/2);x.setData("width",A,B);x.setData("height",w+y.titleHeight,B);this.computePositions(x,x,this.layout.orientation,B);this.controller.onAfterCompute(x)},computePositions:function(F,D,P,y){var M=0;F.eachSubnode(function(R){M+=R.getData("area",y)});var Q=this.config,N=Q.offset,J=F.getData("width",y),H=F.getData("height",y)-Q.titleHeight,x=F==D?1:(D.getData("area",y)/M);var I,G,L,B,A,E,C;var O=(P=="h");if(O){P="v";I=H;G=J*x;L="height";B="y";A="x";E=Q.titleHeight;C=0}else{P="h";I=H*x;G=J;L="width";B="x";A="y";E=0;C=Q.titleHeight}var w=D.getPos(y);D.setData("width",G,y);D.setData("height",I,y);var K=0,z=this;D.eachSubnode(function(S){var R=S.getPos(y);R[B]=K+w[B]+E;R[A]=w[A]+C;z.computePositions(D,S,P,y);K+=S.getData(L,y)})}});g.TM.Area={compute:function(w){w=w||"current";var C=this.graph.getNode(this.clickedNode&&this.clickedNode.id||this.root);this.controller.onBeforeCompute(C);var y=this.config,F=this.canvas.getSize(),x=F.width,E=F.height,D=y.offset,z=x-D,B=E-D;this.graph.computeLevels(this.root,0,"ignore");C.getPos(w).setc(-x/2,-E/2);C.setData("width",x,w);C.setData("height",E,w);var A={top:-E/2+y.titleHeight,left:-x/2,width:z,height:B-y.titleHeight};this.computePositions(C,A,w);this.controller.onAfterCompute(C)},computeDim:function(B,C,E,A,z,x){if(B.length+C.length==1){var y=(B.length==1)?B:C;this.layoutLast(y,E,A,x);return}if(B.length>=2&&C.length==0){C=[B.shift()]}if(B.length==0){if(C.length>0){this.layoutRow(C,E,A,x)}return}var D=B[0];if(z(C,E)>=z([D].concat(C),E)){this.computeDim(B.slice(1),C.concat([D]),E,A,z,x)}else{var F=this.layoutRow(C,E,A,x);this.computeDim(B,[],F.dim,F,z,x)}},worstAspectRatio:function(x,F){if(!x||x.length==0){return Number.MAX_VALUE}var y=0,G=0,B=Number.MAX_VALUE;for(var D=0,C=x.length;D<C;D++){var z=x[D]._area;y+=z;B=B<z?B:z;G=G>z?G:z}var E=F*F,A=y*y;return Math.max(E*G/A,A/(E*B))},avgAspectRatio:function(B,y){if(!B||B.length==0){return Number.MAX_VALUE}var D=0;for(var z=0,x=B.length;z<x;z++){var C=B[z]._area;var A=C/y;D+=y>A?y/A:A/y}return D/x},layoutLast:function(y,x,B,A){var z=y[0];z.getPos(A).setc(B.left,B.top);z.setData("width",B.width,A);z.setData("height",B.height,A)}};g.TM.Squarified=new q({Implements:g.TM.Area,computePositions:function(A,D,x){var z=this.config;if(D.width>=D.height){this.layout.orientation="h"}else{this.layout.orientation="v"}var w=A.getSubnodes([1,1],"ignore");if(w.length>0){this.processChildrenLayout(A,w,D,x);for(var C=0,B=w.length;C<B;C++){var F=w[C];var G=z.offset,H=F.getData("height",x)-G-z.titleHeight,y=F.getData("width",x)-G;var E=F.getPos(x);D={width:y,height:H,top:E.y+z.titleHeight,left:E.x};this.computePositions(F,D,x)}}},processChildrenLayout:function(G,w,C,x){var A=C.width*C.height;var B,y=w.length,D=0,H=[];for(B=0;B<y;B++){H[B]=parseFloat(w[B].getData("area",x));D+=H[B]}for(B=0;B<y;B++){w[B]._area=A*H[B]/D}var z=this.layout.horizontal()?C.height:C.width;w.sort(function(J,I){var K=I._area-J._area;return K?K:(I.id==J.id?0:(I.id<J.id?1:-1))});var F=[w[0]];var E=w.slice(1);this.squarify(E,F,z,C,x)},squarify:function(y,B,x,A,z){this.computeDim(y,B,x,A,this.worstAspectRatio,z)},layoutRow:function(y,x,A,z){if(this.layout.horizontal()){return this.layoutV(y,x,A,z)}else{return this.layoutH(y,x,A,z)}},layoutV:function(x,I,E,y){var J=0,A=function(w){return w};c.each(x,function(w){J+=w._area});var z=A(J/I),F=0;for(var C=0,B=x.length;C<B;C++){var D=A(x[C]._area/z);var G=x[C];G.getPos(y).setc(E.left,E.top+F);G.setData("width",z,y);G.setData("height",D,y);F+=D}var H={height:E.height,width:E.width-z,top:E.top,left:E.left+z};H.dim=Math.min(H.width,H.height);if(H.dim!=H.height){this.layout.change()}return H},layoutH:function(x,G,C,y){var I=0;c.each(x,function(w){I+=w._area});var H=I/G,D=C.top,z=0;for(var B=0,A=x.length;B<A;B++){var E=x[B];var G=E._area/H;E.getPos(y).setc(C.left+z,D);E.setData("width",G,y);E.setData("height",H,y);z+=G}var F={height:C.height-H,width:C.width,top:C.top+H,left:C.left};F.dim=Math.min(F.width,F.height);if(F.dim!=F.width){this.layout.change()}return F}});g.TM.Strip=new q({Implements:g.TM.Area,computePositions:function(A,D,x){var w=A.getSubnodes([1,1],"ignore"),z=this.config;if(w.length>0){this.processChildrenLayout(A,w,D,x);for(var C=0,B=w.length;C<B;C++){var F=w[C];var G=z.offset,H=F.getData("height",x)-G-z.titleHeight,y=F.getData("width",x)-G;var E=F.getPos(x);D={width:y,height:H,top:E.y+z.titleHeight,left:E.x};this.computePositions(F,D,x)}}},processChildrenLayout:function(G,w,B,x){var z=B.width*B.height;var A,y=w.length,C=0,H=[];for(A=0;A<y;A++){H[A]=+w[A].getData("area",x);C+=H[A]}for(A=0;A<y;A++){w[A]._area=z*H[A]/C}var F=this.layout.horizontal()?B.width:B.height;var E=[w[0]];var D=w.slice(1);this.stripify(D,E,F,B,x)},stripify:function(y,B,x,A,z){this.computeDim(y,B,x,A,this.avgAspectRatio,z)},layoutRow:function(y,x,A,z){if(this.layout.horizontal()){return this.layoutH(y,x,A,z)}else{return this.layoutV(y,x,A,z)}},layoutV:function(x,G,D,y){var H=0;c.each(x,function(w){H+=w._area});var z=H/G,E=0;for(var B=0,A=x.length;B<A;B++){var F=x[B];var C=F._area/z;F.getPos(y).setc(D.left,D.top+(G-C-E));F.setData("width",z,y);F.setData("height",C,y);E+=C}return{height:D.height,width:D.width-z,top:D.top,left:D.left+z,dim:G}},layoutH:function(x,F,C,y){var H=0;c.each(x,function(w){H+=w._area});var G=H/F,D=C.height-G,z=0;for(var B=0,A=x.length;B<A;B++){var E=x[B];var I=E._area/G;E.getPos(y).setc(C.left+z,C.top+D);E.setData("width",I,y);E.setData("height",G,y);z+=I}return{height:C.height-G,width:C.width,top:C.top,left:C.left,dim:F}}});g.Icicle=new q({compute:function(E){E=E||"current";var D=this.graph.getNode(this.root),z=this.config,H=this.canvas.getSize(),w=H.width,G=H.height,A=z.offset,C=z.constrained?z.levelsToShow:Number.MAX_VALUE;this.controller.onBeforeCompute(D);e.Util.computeLevels(this.graph,D.id,0,"ignore");var F=0;e.Util.eachLevel(D,0,false,function(J,I){if(I>F){F=I}});var y=this.graph.getNode(this.clickedNode&&this.clickedNode.id||D.id);var x=Math.min(F,C-1);var B=y._depth;if(this.layout.horizontal()){this.computeSubtree(y,-w/2,-G/2,w/(x+1),G,B,x,E)}else{this.computeSubtree(y,-w/2,-G/2,w,G/(x+1),B,x,E)}},computeSubtree:function(G,I,F,w,L,E,A,H){G.getPos(H).setc(I,F);G.setData("width",w,H);G.setData("height",L,H);var C,K=0,J=0;var z=e.Util.getSubnodes(G,[1,1]);if(!z.length){return}c.each(z,function(x){J+=x.getData("dim")});for(var D=0,B=z.length;D<B;D++){if(this.layout.horizontal()){C=L*z[D].getData("dim")/J;this.computeSubtree(z[D],I+w,F,w,C,E,A,H);F+=C}else{C=w*z[D].getData("dim")/J;this.computeSubtree(z[D],I,F+L,C,L,E,A,H);I+=C}}}});$jit.Icicle=new q({Implements:[d,o,g.Icicle],layout:{orientation:"h",vertical:function(){return this.orientation=="v"},horizontal:function(){return this.orientation=="h"},change:function(){this.orientation=this.vertical()?"h":"v"}},initialize:function(w){var x={animate:false,orientation:"h",offset:2,levelsToShow:Number.MAX_VALUE,constrained:false,Node:{type:"rectangle",overridable:true},Edge:{type:"none"},Label:{type:"Native"},duration:700,fps:45};var z=n("Canvas","Node","Edge","Fx","Tips","NodeStyles","Events","Navigation","Controller","Label");this.controller=this.config=c.merge(z,x,w);this.layout.orientation=this.config.orientation;var y=this.config;if(y.useCanvas){this.canvas=y.useCanvas;this.config.labelContainer=this.canvas.id+"-label"}else{this.canvas=new l(this,y);this.config.labelContainer=(typeof y.injectInto=="string"?y.injectInto:y.injectInto.id)+"-label"}this.graphOptions={complex:true,Node:{selected:false,exist:true,drawn:true}};this.graph=new e(this.graphOptions,this.config.Node,this.config.Edge,this.config.Label);this.labels=new $jit.Icicle.Label[this.config.Label.type](this);this.fx=new $jit.Icicle.Plot(this,$jit.Icicle);this.op=new $jit.Icicle.Op(this);this.group=new $jit.Icicle.Group(this);this.clickedNode=null;this.initializeExtras()},refresh:function(){var w=this.config.Label.type;if(w!="Native"){var x=this;this.graph.eachNode(function(y){x.labels.hideLabel(y,false)})}this.compute();this.plot()},plot:function(){this.fx.plot(this.config)},enter:function(y){if(this.busy){return}this.busy=true;var x=this,w=this.config;var z={onComplete:function(){if(w.request){x.compute()}if(w.animate){x.graph.nodeList.setDataset(["current","end"],{alpha:[1,0]});e.Util.eachSubgraph(y,function(A){A.setData("alpha",1,"end")},"ignore");x.fx.animate({duration:500,modes:["node-property:alpha"],onComplete:function(){x.clickedNode=y;x.compute("end");x.fx.animate({modes:["linear","node-property:width:height"],duration:1000,onComplete:function(){x.busy=false;x.clickedNode=y}})}})}else{x.clickedNode=y;x.busy=false;x.refresh()}}};if(w.request){this.requestNodes(clickedNode,z)}else{z.onComplete()}},out:function(){if(this.busy){return}var B=this,A=e.Util,y=this.config,D=this.graph,x=A.getParents(D.getNode(this.clickedNode&&this.clickedNode.id||this.root)),z=x[0],w=z,C=this.clickedNode;this.busy=true;this.events.hoveredNode=false;if(!z){this.busy=false;return}callback={onComplete:function(){B.clickedNode=z;if(y.request){B.requestNodes(z,{onComplete:function(){B.compute();B.plot();B.busy=false}})}else{B.compute();B.plot();B.busy=false}}};if(y.animate){this.clickedNode=w;this.compute("end");this.clickedNode=C;this.fx.animate({modes:["linear","node-property:width:height"],duration:1000,onComplete:function(){B.clickedNode=w;D.nodeList.setDataset(["current","end"],{alpha:[0,1]});A.eachSubgraph(C,function(E){E.setData("alpha",1)},"ignore");B.fx.animate({duration:500,modes:["node-property:alpha"],onComplete:function(){callback.onComplete()}})}})}else{callback.onComplete()}},requestNodes:function(y,z){var x=c.merge(this.controller,z),w=this.config.constrained?this.config.levelsToShow:Number.MAX_VALUE;if(x.request){var B=[],A=y._depth;e.Util.eachLevel(y,0,w,function(C){if(C.drawn&&!e.Util.anySubnode(C)){B.push(C);C._level=C._depth-A;if(this.config.constrained){C._level=w-C._level}}});this.group.requestNodes(B,x)}else{x.onComplete()}}});$jit.Icicle.Op=new q({Implements:e.Op});$jit.Icicle.Group=new q({initialize:function(w){this.viz=w;this.canvas=w.canvas;this.config=w.config},requestNodes:function(B,A){var z=0,x=B.length,D={};var y=function(){A.onComplete()};var w=this.viz;if(x==0){y()}for(var C=0;C<x;C++){D[B[C].id]=B[C];A.request(B[C].id,B[C]._level,{onComplete:function(F,E){if(E&&E.children){E.id=F;w.op.sum(E,{type:"nothing"})}if(++z==x){e.Util.computeLevels(w.graph,w.root,0);y()}}})}}});$jit.Icicle.Plot=new q({Implements:e.Plot,plot:function(A,y){A=A||this.viz.controller;var w=this.viz,B=w.graph,x=B.getNode(w.clickedNode&&w.clickedNode.id||w.root),z=x._depth;w.canvas.clear();this.plotTree(x,c.merge(A,{withLabels:true,hideLabels:false,plotSubtree:function(C,D){return !w.config.constrained||(D._depth-z<w.config.levelsToShow)}}),y)}});$jit.Icicle.Label={};$jit.Icicle.Label.Native=new q({Implements:e.Label.Native,renderLabel:function(x,y,A){var D=x.getCtx(),w=y.getData("width"),C=y.getData("height"),E=y.getLabelData("size"),z=D.measureText(y.name);if(C<(E*1.5)||w<z.width){return}var B=y.pos.getc(true);D.fillText(y.name,B.x+w/2,B.y+C/2)}});$jit.Icicle.Label.SVG=new q({Implements:e.Label.SVG,initialize:function(w){this.viz=w},placeLabel:function(x,A,y){var C=A.pos.getc(true),z=this.viz.canvas;var w=z.getSize();var B={x:Math.round(C.x+w.width/2),y:Math.round(C.y+w.height/2)};x.setAttribute("x",B.x);x.setAttribute("y",B.y);y.onPlaceLabel(x,A)}});$jit.Icicle.Label.HTML=new q({Implements:e.Label.HTML,initialize:function(w){this.viz=w},placeLabel:function(x,B,y){var D=B.pos.getc(true),z=this.viz.canvas;var w=z.getSize();var C={x:Math.round(D.x+w.width/2),y:Math.round(D.y+w.height/2)};var A=x.style;A.left=C.x+"px";A.top=C.y+"px";A.display="";y.onPlaceLabel(x,B)}});$jit.Icicle.Plot.NodeTypes=new q({none:{render:c.empty},rectangle:{render:function(z,x,K){var y=this.viz.config;var C=y.offset;var w=z.getData("width");var H=z.getData("height");var B=z.getData("border");var G=z.pos.getc(true);var F=G.x+C/2,D=G.y+C/2;var J=x.getCtx();if(w-C<2||H-C<2){return}if(y.cushion){var A=z.getData("color");var I=J.createRadialGradient(F+(w-C)/2,D+(H-C)/2,1,F+(w-C)/2,D+(H-C)/2,w<H?H:w);var E=c.rgbToHex(c.map(c.hexToRgb(A),function(L){return L*0.3>>0}));I.addColorStop(0,A);I.addColorStop(1,E);J.fillStyle=I}if(B){J.strokeStyle=B;J.lineWidth=3}J.fillRect(F,D,Math.max(0,w-C),Math.max(0,H-C));B&&J.strokeRect(G.x,G.y,w,H)},contains:function(y,A){if(this.viz.clickedNode&&!$jit.Graph.Util.isDescendantOf(y,this.viz.clickedNode.id)){return false}var z=y.pos.getc(true),x=y.getData("width"),w=y.getData("height");return this.nodeHelper.rectangle.contains({x:z.x+x/2,y:z.y+w/2},A,x,w)}}});$jit.Icicle.Plot.EdgeTypes=new q({none:c.empty});g.ForceDirected=new q({getOptions:function(D){var B=this.canvas.getSize();var y=B.width,A=B.height;var C=0;this.graph.eachNode(function(w){C++});var E=y*A/C,z=Math.sqrt(E);var x=this.config.levelDistance;return{width:y,height:A,tstart:y*0.1,nodef:function(w){return E/(w||1)},edgef:function(w){return z*(w-x)}}},compute:function(x,y){var z=c.splat(x||["current","start","end"]);var w=this.getOptions();f.compute(this.graph,z,this.config);this.graph.computeLevels(this.root,0,"ignore");this.graph.eachNode(function(A){c.each(z,function(B){var C=A.getPos(B);if(C.equals(p.KER)){C.x=w.width/5*(Math.random()-0.5);C.y=w.height/5*(Math.random()-0.5)}A.disp={};c.each(z,function(D){A.disp[D]=r(0,0)})})});this.computePositions(z,w,y)},computePositions:function(A,y,B){var C=this.config.iterations,x=0,z=this;if(B){(function w(){for(var E=B.iter,D=0;D<E;D++){y.t=y.tstart*(1-x++/(C-1));z.computePositionStep(A,y);if(x>=C){B.onComplete();return}}B.onStep(Math.round(x/(C-1)*100));setTimeout(w,1)})()}else{for(;x<C;x++){y.t=y.tstart*(1-x/(C-1));this.computePositionStep(A,y)}}},computePositionStep:function(D,w){var E=this.graph;var y=Math.min,C=Math.max;var B=r(0,0);E.eachNode(function(G){c.each(D,function(H){G.disp[H].x=0;G.disp[H].y=0});E.eachNode(function(H){if(H.id!=G.id){c.each(D,function(L){var J=G.getPos(L),I=H.getPos(L);B.x=J.x-I.x;B.y=J.y-I.y;var K=B.norm()||1;G.disp[L].$add(B.$scale(w.nodef(K)/K))})}})});var x=!!E.getNode(this.root).visited;E.eachNode(function(G){G.eachAdjacency(function(H){var I=H.nodeTo;if(!!I.visited===x){c.each(D,function(M){var K=G.getPos(M),J=I.getPos(M);B.x=K.x-J.x;B.y=K.y-J.y;var L=B.norm()||1;G.disp[M].$add(B.$scale(-w.edgef(L)/L));I.disp[M].$add(B.$scale(-1))})}});G.visited=!x});var F=w.t,z=w.width/2,A=w.height/2;E.eachNode(function(G){c.each(D,function(J){var H=G.disp[J];var I=H.norm()||1;var J=G.getPos(J);J.$add(r(H.x*y(Math.abs(H.x),F)/I,H.y*y(Math.abs(H.y),F)/I));J.x=y(z,C(-z,J.x));J.y=y(A,C(-A,J.y))})})}});$jit.ForceDirected=new q({Implements:[d,o,g.ForceDirected],initialize:function(x){var w=$jit.ForceDirected;var y={iterations:50,levelDistance:50};this.controller=this.config=c.merge(n("Canvas","Node","Edge","Fx","Tips","NodeStyles","Events","Navigation","Controller","Label"),y,x);var z=this.config;if(z.useCanvas){this.canvas=z.useCanvas;this.config.labelContainer=this.canvas.id+"-label"}else{if(z.background){z.background=c.merge({type:"Circles"},z.background)}this.canvas=new l(this,z);this.config.labelContainer=(typeof z.injectInto=="string"?z.injectInto:z.injectInto.id)+"-label"}this.graphOptions={complex:true,Node:{selected:false,exist:true,drawn:true}};this.graph=new e(this.graphOptions,this.config.Node,this.config.Edge);this.labels=new w.Label[z.Label.type](this);this.fx=new w.Plot(this,w);this.op=new w.Op(this);this.json=null;this.busy=false;this.initializeExtras()},refresh:function(){this.compute();this.plot()},reposition:function(){this.compute("end")},computeIncremental:function(w){w=c.merge({iter:20,property:"end",onStep:c.empty,onComplete:c.empty},w||{});this.config.onBeforeCompute(this.graph.getNode(this.root));this.compute(w.property,w)},plot:function(){this.fx.plot()},animate:function(w){this.fx.animate(c.merge({modes:["linear"]},w||{}))}});$jit.ForceDirected.$extend=true;(function(w){w.Op=new q({Implements:e.Op});w.Plot=new q({Implements:e.Plot});w.Label={};w.Label.Native=new q({Implements:e.Label.Native});w.Label.SVG=new q({Implements:e.Label.SVG,initialize:function(x){this.viz=x},placeLabel:function(H,B,C){var F=B.pos.getc(true),y=this.viz.canvas,z=y.translateOffsetX,x=y.translateOffsetY,G=y.scaleOffsetX,E=y.scaleOffsetY,D=y.getSize();var A={x:Math.round(F.x*G+z+D.width/2),y:Math.round(F.y*E+x+D.height/2)};H.setAttribute("x",A.x);H.setAttribute("y",A.y);C.onPlaceLabel(H,B)}});w.Label.HTML=new q({Implements:e.Label.HTML,initialize:function(x){this.viz=x},placeLabel:function(I,C,D){var G=C.pos.getc(true),z=this.viz.canvas,A=z.translateOffsetX,y=z.translateOffsetY,H=z.scaleOffsetX,F=z.scaleOffsetY,E=z.getSize();var B={x:Math.round(G.x*H+A+E.width/2),y:Math.round(G.y*F+y+E.height/2)};var x=I.style;x.left=B.x+"px";x.top=B.y+"px";x.display=this.fitsInCanvas(B,z)?"":"none";D.onPlaceLabel(I,C)}});w.Plot.NodeTypes=new q({none:{render:c.empty,contains:c.lambda(false)},circle:{render:function(y,x){var A=y.pos.getc(true),z=y.getData("dim");this.nodeHelper.circle.render("fill",A,z,x)},contains:function(x,A){var z=x.pos.getc(true),y=x.getData("dim");return this.nodeHelper.circle.contains(z,A,y)}},ellipse:{render:function(A,y){var B=A.pos.getc(true),z=A.getData("width"),x=A.getData("height");this.nodeHelper.ellipse.render("fill",B,z,x,y)},contains:function(z,B){var A=z.pos.getc(true),y=z.getData("width"),x=z.getData("height");return this.nodeHelper.ellipse.contains(A,B,y,x)}},square:{render:function(y,x){var A=y.pos.getc(true),z=y.getData("dim");this.nodeHelper.square.render("fill",A,z,x)},contains:function(x,A){var z=x.pos.getc(true),y=x.getData("dim");return this.nodeHelper.square.contains(z,A,y)}},rectangle:{render:function(A,y){var B=A.pos.getc(true),z=A.getData("width"),x=A.getData("height");this.nodeHelper.rectangle.render("fill",B,z,x,y)},contains:function(z,B){var A=z.pos.getc(true),y=z.getData("width"),x=z.getData("height");return this.nodeHelper.rectangle.contains(A,B,y,x)}},triangle:{render:function(y,x){var A=y.pos.getc(true),z=y.getData("dim");this.nodeHelper.triangle.render("fill",A,z,x)},contains:function(x,A){var z=x.pos.getc(true),y=x.getData("dim");return this.nodeHelper.triangle.contains(z,A,y)}},star:{render:function(y,x){var A=y.pos.getc(true),z=y.getData("dim");this.nodeHelper.star.render("fill",A,z,x)},contains:function(x,A){var z=x.pos.getc(true),y=x.getData("dim");return this.nodeHelper.star.contains(z,A,y)}}});w.Plot.EdgeTypes=new q({none:c.empty,line:{render:function(x,y){var A=x.nodeFrom.pos.getc(true),z=x.nodeTo.pos.getc(true);this.edgeHelper.line.render(A,z,y)},contains:function(x,A){var z=x.nodeFrom.pos.getc(true),y=x.nodeTo.pos.getc(true);return this.edgeHelper.line.contains(z,y,A,this.edge.epsilon)}},arrow:{render:function(y,z){var D=y.nodeFrom.pos.getc(true),C=y.nodeTo.pos.getc(true),B=y.getData("dim"),A=y.data.$direction,x=(A&&A.length>1&&A[0]!=y.nodeFrom.id);this.edgeHelper.arrow.render(D,C,B,x,z)},contains:function(x,A){var z=x.nodeFrom.pos.getc(true),y=x.nodeTo.pos.getc(true);return this.edgeHelper.arrow.contains(z,y,A,this.edge.epsilon)}}})})($jit.ForceDirected);$jit.TM={};var v=$jit.TM;$jit.TM.$extend=true;v.Base={layout:{orientation:"h",vertical:function(){return this.orientation=="v"},horizontal:function(){return this.orientation=="h"},change:function(){this.orientation=this.vertical()?"h":"v"}},initialize:function(w){var x={orientation:"h",titleHeight:13,offset:2,levelsToShow:0,constrained:false,animate:false,Node:{type:"rectangle",overridable:true,width:3,height:3,color:"#444"},Label:{textAlign:"center",textBaseline:"top"},Edge:{type:"none"},duration:700,fps:45};this.controller=this.config=c.merge(n("Canvas","Node","Edge","Fx","Controller","Tips","NodeStyles","Events","Navigation","Label"),x,w);this.layout.orientation=this.config.orientation;var y=this.config;if(y.useCanvas){this.canvas=y.useCanvas;this.config.labelContainer=this.canvas.id+"-label"}else{if(y.background){y.background=c.merge({type:"Circles"},y.background)}this.canvas=new l(this,y);this.config.labelContainer=(typeof y.injectInto=="string"?y.injectInto:y.injectInto.id)+"-label"}this.graphOptions={complex:true,Node:{selected:false,exist:true,drawn:true}};this.graph=new e(this.graphOptions,this.config.Node,this.config.Edge);this.labels=new v.Label[y.Label.type](this);this.fx=new v.Plot(this);this.op=new v.Op(this);this.group=new v.Group(this);this.geom=new v.Geom(this);this.clickedNode=null;this.busy=false;this.initializeExtras()},refresh:function(){if(this.busy){return}this.busy=true;var x=this;if(this.config.animate){this.compute("end");this.config.levelsToShow>0&&this.geom.setRightLevelToShow(this.graph.getNode(this.clickedNode&&this.clickedNode.id||this.root));this.fx.animate(c.merge(this.config,{modes:["linear","node-property:width:height"],onComplete:function(){x.busy=false}}))}else{var w=this.config.Label.type;if(w!="Native"){var x=this;this.graph.eachNode(function(y){x.labels.hideLabel(y,false)})}this.busy=false;this.compute();this.config.levelsToShow>0&&this.geom.setRightLevelToShow(this.graph.getNode(this.clickedNode&&this.clickedNode.id||this.root));this.plot()}},plot:function(){this.fx.plot()},leaf:function(w){return w.getSubnodes([1,1],"ignore").length==0},enter:function(C){if(this.busy){return}this.busy=true;var y=this,x=this.config,A=this.graph,w=C,z=this.clickedNode;var B={onComplete:function(){if(x.levelsToShow>0){y.geom.setRightLevelToShow(C)}if(x.levelsToShow>0||x.request){y.compute()}if(x.animate){A.nodeList.setData("alpha",0,"end");C.eachSubgraph(function(D){D.setData("alpha",1,"end")},"ignore");y.fx.animate({duration:500,modes:["node-property:alpha"],onComplete:function(){y.clickedNode=w;y.compute("end");y.clickedNode=z;y.fx.animate({modes:["linear","node-property:width:height"],duration:1000,onComplete:function(){y.busy=false;y.clickedNode=w}})}})}else{y.busy=false;y.clickedNode=C;y.refresh()}}};if(x.request){this.requestNodes(w,B)}else{B.onComplete()}},out:function(){if(this.busy){return}this.busy=true;this.events.hoveredNode=false;var A=this,y=this.config,C=this.graph,x=C.getNode(this.clickedNode&&this.clickedNode.id||this.root).getParents(),z=x[0],w=z,B=this.clickedNode;if(!z){this.busy=false;return}callback={onComplete:function(){A.clickedNode=z;if(y.request){A.requestNodes(z,{onComplete:function(){A.compute();A.plot();A.busy=false}})}else{A.compute();A.plot();A.busy=false}}};if(y.levelsToShow>0){this.geom.setRightLevelToShow(z)}if(y.animate){this.clickedNode=w;this.compute("end");this.clickedNode=B;this.fx.animate({modes:["linear","node-property:width:height"],duration:1000,onComplete:function(){A.clickedNode=w;C.eachNode(function(D){D.setDataset(["current","end"],{alpha:[0,1]})},"ignore");B.eachSubgraph(function(D){D.setData("alpha",1)},"ignore");A.fx.animate({duration:500,modes:["node-property:alpha"],onComplete:function(){callback.onComplete()}})}})}else{callback.onComplete()}},requestNodes:function(y,z){var x=c.merge(this.controller,z),w=this.config.levelsToShow;if(x.request){var B=[],A=y._depth;y.eachLevel(0,w,function(D){var C=w-(D._depth-A);if(D.drawn&&!D.anySubnode()&&C>0){B.push(D);D._level=C}});this.group.requestNodes(B,x)}else{x.onComplete()}}};v.Op=new q({Implements:e.Op,initialize:function(w){this.viz=w}});v.Geom=new q({Implements:e.Geom,getRightLevelToShow:function(){return this.viz.config.levelsToShow},setRightLevelToShow:function(x){var y=this.getRightLevelToShow(),w=this.viz.labels;x.eachLevel(0,y+1,function(A){var z=A._depth-x._depth;if(z>y){A.drawn=false;A.exist=false;A.ignore=true;w.hideLabel(A,false)}else{A.drawn=true;A.exist=true;delete A.ignore}});x.drawn=true;delete x.ignore}});v.Group=new q({initialize:function(w){this.viz=w;this.canvas=w.canvas;this.config=w.config},requestNodes:function(B,A){var z=0,x=B.length,D={};var y=function(){A.onComplete()};var w=this.viz;if(x==0){y()}for(var C=0;C<x;C++){D[B[C].id]=B[C];A.request(B[C].id,B[C]._level,{onComplete:function(F,E){if(E&&E.children){E.id=F;w.op.sum(E,{type:"nothing"})}if(++z==x){w.graph.computeLevels(w.root,0);y()}}})}}});v.Plot=new q({Implements:e.Plot,initialize:function(w){this.viz=w;this.config=w.config;this.node=this.config.Node;this.edge=this.config.Edge;this.animation=new u;this.nodeTypes=new v.Plot.NodeTypes;this.edgeTypes=new v.Plot.EdgeTypes;this.labels=w.labels},plot:function(y,x){var w=this.viz,z=w.graph;w.canvas.clear();this.plotTree(z.getNode(w.clickedNode&&w.clickedNode.id||w.root),c.merge(w.config,y||{},{withLabels:true,hideLabels:false,plotSubtree:function(B,A){return B.anySubnode("exist")}}),x)}});v.Label={};v.Label.Native=new q({Implements:e.Label.Native,initialize:function(w){this.config=w.config;this.leaf=w.leaf},renderLabel:function(z,A,B){if(!this.leaf(A)&&!this.config.titleHeight){return}var D=A.pos.getc(true),G=z.getCtx(),w=A.getData("width"),F=A.getData("height"),E=D.x+w/2,C=D.y;G.fillText(A.name,E,C,w)}});v.Label.SVG=new q({Implements:e.Label.SVG,initialize:function(w){this.viz=w;this.leaf=w.leaf;this.config=w.config},placeLabel:function(G,A,B){var E=A.pos.getc(true),x=this.viz.canvas,y=x.translateOffsetX,w=x.translateOffsetY,F=x.scaleOffsetX,D=x.scaleOffsetY,C=x.getSize();var z={x:Math.round(E.x*F+y+C.width/2),y:Math.round(E.y*D+w+C.height/2)};G.setAttribute("x",z.x);G.setAttribute("y",z.y);if(!this.leaf(A)&&!this.config.titleHeight){G.style.display="none"}B.onPlaceLabel(G,A)}});v.Label.HTML=new q({Implements:e.Label.HTML,initialize:function(w){this.viz=w;this.leaf=w.leaf;this.config=w.config},placeLabel:function(H,B,C){var F=B.pos.getc(true),y=this.viz.canvas,z=y.translateOffsetX,x=y.translateOffsetY,G=y.scaleOffsetX,E=y.scaleOffsetY,D=y.getSize();var A={x:Math.round(F.x*G+z+D.width/2),y:Math.round(F.y*E+x+D.height/2)};var w=H.style;w.left=A.x+"px";w.top=A.y+"px";w.width=B.getData("width")*G+"px";w.height=B.getData("height")*E+"px";w.zIndex=B._depth*100;w.display="";if(!this.leaf(B)&&!this.config.titleHeight){H.style.display="none"}C.onPlaceLabel(H,B)}});v.Plot.NodeTypes=new q({none:{render:c.empty},rectangle:{render:function(z,x,M){var D=this.viz.leaf(z),y=this.config,I=y.offset,C=y.titleHeight,H=z.pos.getc(true),w=z.getData("width"),J=z.getData("height"),B=z.getData("border"),L=x.getCtx(),G=H.x+I/2,E=H.y+I/2;if(w<=I||J<=I){return}if(D){if(y.cushion){var K=L.createRadialGradient(G+(w-I)/2,E+(J-I)/2,1,G+(w-I)/2,E+(J-I)/2,w<J?J:w);var A=z.getData("color");var F=c.rgbToHex(c.map(c.hexToRgb(A),function(N){return N*0.2>>0}));K.addColorStop(0,A);K.addColorStop(1,F);L.fillStyle=K}L.fillRect(G,E,w-I,J-I);if(B){L.save();L.strokeStyle=B;L.strokeRect(G,E,w-I,J-I);L.restore()}}else{if(C>0){L.fillRect(H.x+I/2,H.y+I/2,w-I,C-I);if(B){L.save();L.strokeStyle=B;L.strokeRect(H.x+I/2,H.y+I/2,w-I,J-I);L.restore()}}}},contains:function(z,B){if(this.viz.clickedNode&&!z.isDescendantOf(this.viz.clickedNode.id)||z.ignore){return false}var A=z.pos.getc(true),y=z.getData("width"),x=this.viz.leaf(z),w=x?z.getData("height"):this.config.titleHeight;return this.nodeHelper.rectangle.contains({x:A.x+y/2,y:A.y+w/2},B,y,w)}}});v.Plot.EdgeTypes=new q({none:c.empty});v.SliceAndDice=new q({Implements:[d,o,v.Base,g.TM.SliceAndDice]});v.Squarified=new q({Implements:[d,o,v.Base,g.TM.Squarified]});v.Strip=new q({Implements:[d,o,v.Base,g.TM.Strip]});$jit.RGraph=new q({Implements:[d,o,g.Radial],initialize:function(w){var x=$jit.RGraph;var y={interpolation:"linear",levelDistance:100};this.controller=this.config=c.merge(n("Canvas","Node","Edge","Fx","Controller","Tips","NodeStyles","Events","Navigation","Label"),y,w);var z=this.config;if(z.useCanvas){this.canvas=z.useCanvas;this.config.labelContainer=this.canvas.id+"-label"}else{if(z.background){z.background=c.merge({type:"Circles"},z.background)}this.canvas=new l(this,z);this.config.labelContainer=(typeof z.injectInto=="string"?z.injectInto:z.injectInto.id)+"-label"}this.graphOptions={complex:false,Node:{selected:false,exist:true,drawn:true}};this.graph=new e(this.graphOptions,this.config.Node,this.config.Edge);this.labels=new x.Label[z.Label.type](this);this.fx=new x.Plot(this,x);this.op=new x.Op(this);this.json=null;this.root=null;this.busy=false;this.parent=false;this.initializeExtras()},createLevelDistanceFunc:function(){var w=this.config.levelDistance;return function(x){return(x._depth+1)*w}},refresh:function(){this.compute();this.plot()},reposition:function(){this.compute("end")},plot:function(){this.fx.plot()},getNodeAndParentAngle:function(D){var y=false;var C=this.graph.getNode(D);var A=C.getParents();var z=(A.length>0)?A[0]:false;if(z){var w=z.pos.getc(),B=C.pos.getc();var x=w.add(B.scale(-1));y=Math.atan2(x.y,x.x);if(y<0){y+=2*Math.PI}}return{parent:z,theta:y}},tagChildren:function(A,C){if(A.angleSpan){var B=[];A.eachAdjacency(function(D){B.push(D.nodeTo)},"ignore");var w=B.length;for(var z=0;z<w&&C!=B[z].id;z++){}for(var y=(z+1)%w,x=0;C!=B[y].id;y=(y+1)%w){B[y].dist=x++}}},onClick:function(A,x){if(this.root!=A&&!this.busy){this.busy=true;this.root=A;that=this;this.controller.onBeforeCompute(this.graph.getNode(A));var y=this.getNodeAndParentAngle(A);this.tagChildren(y.parent,A);this.parent=y.parent;this.compute("end");var w=y.theta-y.parent.endPos.theta;this.graph.eachNode(function(B){B.endPos.set(B.endPos.getp().add(k(w,0)))});var z=this.config.interpolation;x=c.merge({onComplete:c.empty},x||{});this.fx.animate(c.merge({hideLabels:true,modes:[z]},x,{onComplete:function(){that.busy=false;x.onComplete()}}))}}});$jit.RGraph.$extend=true;(function(w){w.Op=new q({Implements:e.Op});w.Plot=new q({Implements:e.Plot});w.Label={};w.Label.Native=new q({Implements:e.Label.Native});w.Label.SVG=new q({Implements:e.Label.SVG,initialize:function(x){this.viz=x},placeLabel:function(H,B,C){var F=B.pos.getc(true),y=this.viz.canvas,z=y.translateOffsetX,x=y.translateOffsetY,G=y.scaleOffsetX,E=y.scaleOffsetY,D=y.getSize();var A={x:Math.round(F.x*G+z+D.width/2),y:Math.round(F.y*E+x+D.height/2)};H.setAttribute("x",A.x);H.setAttribute("y",A.y);C.onPlaceLabel(H,B)}});w.Label.HTML=new q({Implements:e.Label.HTML,initialize:function(x){this.viz=x},placeLabel:function(I,C,D){var G=C.pos.getc(true),z=this.viz.canvas,A=z.translateOffsetX,y=z.translateOffsetY,H=z.scaleOffsetX,F=z.scaleOffsetY,E=z.getSize();var B={x:Math.round(G.x*H+A+E.width/2),y:Math.round(G.y*F+y+E.height/2)};var x=I.style;x.left=B.x+"px";x.top=B.y+"px";x.display=this.fitsInCanvas(B,z)?"":"none";D.onPlaceLabel(I,C)}});w.Plot.NodeTypes=new q({none:{render:c.empty,contains:c.lambda(false)},circle:{render:function(y,x){var A=y.pos.getc(true),z=y.getData("dim");this.nodeHelper.circle.render("fill",A,z,x)},contains:function(x,A){var z=x.pos.getc(true),y=x.getData("dim");return this.nodeHelper.circle.contains(z,A,y)}},ellipse:{render:function(A,y){var B=A.pos.getc(true),z=A.getData("width"),x=A.getData("height");this.nodeHelper.ellipse.render("fill",B,z,x,y)},contains:function(z,B){var A=z.pos.getc(true),y=z.getData("width"),x=z.getData("height");return this.nodeHelper.ellipse.contains(A,B,y,x)}},square:{render:function(y,x){var A=y.pos.getc(true),z=y.getData("dim");this.nodeHelper.square.render("fill",A,z,x)},contains:function(x,A){var z=x.pos.getc(true),y=x.getData("dim");return this.nodeHelper.square.contains(z,A,y)}},rectangle:{render:function(A,y){var B=A.pos.getc(true),z=A.getData("width"),x=A.getData("height");this.nodeHelper.rectangle.render("fill",B,z,x,y)},contains:function(z,B){var A=z.pos.getc(true),y=z.getData("width"),x=z.getData("height");return this.nodeHelper.rectangle.contains(A,B,y,x)}},triangle:{render:function(y,x){var A=y.pos.getc(true),z=y.getData("dim");this.nodeHelper.triangle.render("fill",A,z,x)},contains:function(x,A){var z=x.pos.getc(true),y=x.getData("dim");return this.nodeHelper.triangle.contains(z,A,y)}},star:{render:function(y,x){var A=y.pos.getc(true),z=y.getData("dim");this.nodeHelper.star.render("fill",A,z,x)},contains:function(x,A){var z=x.pos.getc(true),y=x.getData("dim");return this.nodeHelper.star.contains(z,A,y)}}});w.Plot.EdgeTypes=new q({none:c.empty,line:{render:function(x,y){var A=x.nodeFrom.pos.getc(true),z=x.nodeTo.pos.getc(true);this.edgeHelper.line.render(A,z,y)},contains:function(x,A){var z=x.nodeFrom.pos.getc(true),y=x.nodeTo.pos.getc(true);return this.edgeHelper.line.contains(z,y,A,this.edge.epsilon)}},arrow:{render:function(y,z){var D=y.nodeFrom.pos.getc(true),C=y.nodeTo.pos.getc(true),B=y.getData("dim"),A=y.data.$direction,x=(A&&A.length>1&&A[0]!=y.nodeFrom.id);this.edgeHelper.arrow.render(D,C,B,x,z)},contains:function(x,A){var z=x.nodeFrom.pos.getc(true),y=x.nodeTo.pos.getc(true);return this.edgeHelper.arrow.contains(z,y,A,this.edge.epsilon)}}})})($jit.RGraph);p.prototype.moebiusTransformation=function(y){var w=this.add(y);var x=y.$conjugate().$prod(this);x.x++;return w.$div(x)};e.Util.moebiusTransformation=function(y,A,z,x,w){this.eachNode(y,function(C){for(var B=0;B<z.length;B++){var E=A[B].scale(-1),D=x?x:z[B];C.getPos(z[B]).set(C.getPos(D).getc().moebiusTransformation(E))}},w)};$jit.Hypertree=new q({Implements:[d,o,g.Radial],initialize:function(w){var z=$jit.Hypertree;var x={radius:"auto",offset:0,Edge:{type:"hyperline"},duration:1500,fps:35};this.controller=this.config=c.merge(n("Canvas","Node","Edge","Fx","Tips","NodeStyles","Events","Navigation","Controller","Label"),x,w);var y=this.config;if(y.useCanvas){this.canvas=y.useCanvas;this.config.labelContainer=this.canvas.id+"-label"}else{if(y.background){y.background=c.merge({type:"Circles"},y.background)}this.canvas=new l(this,y);this.config.labelContainer=(typeof y.injectInto=="string"?y.injectInto:y.injectInto.id)+"-label"}this.graphOptions={complex:false,Node:{selected:false,exist:true,drawn:true}};this.graph=new e(this.graphOptions,this.config.Node,this.config.Edge);this.labels=new z.Label[y.Label.type](this);this.fx=new z.Plot(this,z);this.op=new z.Op(this);this.json=null;this.root=null;this.busy=false;this.initializeExtras()},createLevelDistanceFunc:function(){var A=this.getRadius();var C=0,w=Math.max,x=this.config;this.graph.eachNode(function(D){C=w(D._depth,C)},"ignore");C++;var B=function(D){return function(F){F.scale=A;var H=F._depth+1;var G=0,E=Math.pow;while(H){G+=E(D,H--)}return G-x.offset}};for(var z=0.51;z<=1;z+=0.01){var y=(1-Math.pow(z,C))/(1-z);if(y>=2){return B(z-0.01)}}return B(0.75)},getRadius:function(){var w=this.config.radius;if(w!=="auto"){return w}var x=this.canvas.getSize();return Math.min(x.width,x.height)/2},refresh:function(w){if(w){this.reposition();this.graph.eachNode(function(x){x.startPos.rho=x.pos.rho=x.endPos.rho;x.startPos.theta=x.pos.theta=x.endPos.theta})}else{this.compute()}this.plot()},reposition:function(){this.compute("end");var w=this.graph.getNode(this.root).pos.getc().scale(-1);e.Util.moebiusTransformation(this.graph,[w],["end"],"end","ignore");this.graph.eachNode(function(x){if(x.ignore){x.endPos.rho=x.pos.rho;x.endPos.theta=x.pos.theta}})},plot:function(){this.fx.plot()},onClick:function(y,w){var x=this.graph.getNode(y).pos.getc(true);this.move(x,w)},move:function(A,y){var x=r(A.x,A.y);if(this.busy===false&&x.norm()<1){this.busy=true;var w=this.graph.getClosestNodeToPos(x),z=this;this.graph.computeLevels(w.id,0);this.controller.onBeforeCompute(w);y=c.merge({onComplete:c.empty},y||{});this.fx.animate(c.merge({modes:["moebius"],hideLabels:true},y,{onComplete:function(){z.busy=false;y.onComplete()}}),x)}}});$jit.Hypertree.$extend=true;(function(w){w.Op=new q({Implements:e.Op});w.Plot=new q({Implements:e.Plot});w.Label={};w.Label.Native=new q({Implements:e.Label.Native,initialize:function(x){this.viz=x},renderLabel:function(z,B,y){var x=z.getCtx();var C=B.pos.getc(true);var A=this.viz.getRadius();x.fillText(B.name,C.x*A,C.y*A)}});w.Label.SVG=new q({Implements:e.Label.SVG,initialize:function(x){this.viz=x},placeLabel:function(I,C,D){var G=C.pos.getc(true),z=this.viz.canvas,A=z.translateOffsetX,y=z.translateOffsetY,H=z.scaleOffsetX,F=z.scaleOffsetY,E=z.getSize(),x=this.viz.getRadius();var B={x:Math.round((G.x*H)*x+A+E.width/2),y:Math.round((G.y*F)*x+y+E.height/2)};I.setAttribute("x",B.x);I.setAttribute("y",B.y);D.onPlaceLabel(I,C)}});w.Label.HTML=new q({Implements:e.Label.HTML,initialize:function(x){this.viz=x},placeLabel:function(J,D,E){var H=D.pos.getc(true),A=this.viz.canvas,B=A.translateOffsetX,z=A.translateOffsetY,I=A.scaleOffsetX,G=A.scaleOffsetY,F=A.getSize(),x=this.viz.getRadius();var C={x:Math.round((H.x*I)*x+B+F.width/2),y:Math.round((H.y*G)*x+z+F.height/2)};var y=J.style;y.left=C.x+"px";y.top=C.y+"px";y.display=this.fitsInCanvas(C,A)?"":"none";E.onPlaceLabel(J,D)}});w.Plot.NodeTypes=new q({none:{render:c.empty,contains:c.lambda(false)},circle:{render:function(z,x){var y=this.node,B=z.getData("dim"),A=z.pos.getc();B=y.transform?B*(1-A.squaredNorm()):B;A.$scale(z.scale);if(B>0.2){this.nodeHelper.circle.render("fill",A,B,x)}},contains:function(x,A){var y=x.getData("dim"),z=x.pos.getc().$scale(x.scale);return this.nodeHelper.circle.contains(z,A,y)}},ellipse:{render:function(A,y){var B=A.pos.getc().$scale(A.scale),z=A.getData("width"),x=A.getData("height");this.nodeHelper.ellipse.render("fill",B,z,x,y)},contains:function(z,B){var y=z.getData("width"),x=z.getData("height"),A=z.pos.getc().$scale(z.scale);return this.nodeHelper.circle.contains(A,B,y,x)}},square:{render:function(z,x){var y=this.node,B=z.getData("dim"),A=z.pos.getc();B=y.transform?B*(1-A.squaredNorm()):B;A.$scale(z.scale);if(B>0.2){this.nodeHelper.square.render("fill",A,B,x)}},contains:function(x,A){var y=x.getData("dim"),z=x.pos.getc().$scale(x.scale);return this.nodeHelper.square.contains(z,A,y)}},rectangle:{render:function(B,y){var A=this.node,z=B.getData("width"),x=B.getData("height"),C=B.pos.getc();z=A.transform?z*(1-C.squaredNorm()):z;x=A.transform?x*(1-C.squaredNorm()):x;C.$scale(B.scale);if(z>0.2&&x>0.2){this.nodeHelper.rectangle.render("fill",C,z,x,y)}},contains:function(z,B){var y=z.getData("width"),x=z.getData("height"),A=z.pos.getc().$scale(z.scale);return this.nodeHelper.square.contains(A,B,y,x)}},triangle:{render:function(z,x){var y=this.node,B=z.getData("dim"),A=z.pos.getc();B=y.transform?B*(1-A.squaredNorm()):B;A.$scale(z.scale);if(B>0.2){this.nodeHelper.triangle.render("fill",A,B,x)}},contains:function(x,A){var y=x.getData("dim"),z=x.pos.getc().$scale(x.scale);return this.nodeHelper.triangle.contains(z,A,y)}},star:{render:function(z,x){var y=this.node,B=z.getData("dim"),A=z.pos.getc();B=y.transform?B*(1-A.squaredNorm()):B;A.$scale(z.scale);if(B>0.2){this.nodeHelper.star.render("fill",A,B,x)}},contains:function(x,A){var y=x.getData("dim"),z=x.pos.getc().$scale(x.scale);return this.nodeHelper.star.contains(z,A,y)}}});w.Plot.EdgeTypes=new q({none:c.empty,line:{render:function(x,y){var B=x.nodeFrom.pos.getc(true),A=x.nodeTo.pos.getc(true),z=x.nodeFrom.scale;this.edgeHelper.line.render({x:B.x*z,y:B.y*z},{x:A.x*z,y:A.y*z},y)},contains:function(x,B){var A=x.nodeFrom.pos.getc(true),z=x.nodeTo.pos.getc(true),y=x.nodeFrom.scale;this.edgeHelper.line.contains({x:A.x*y,y:A.y*y},{x:z.x*y,y:z.y*y},B,this.edge.epsilon)}},arrow:{render:function(y,z){var E=y.nodeFrom.pos.getc(true),D=y.nodeTo.pos.getc(true),A=y.nodeFrom.scale,C=y.getData("dim"),B=y.data.$direction,x=(B&&B.length>1&&B[0]!=y.nodeFrom.id);this.edgeHelper.arrow.render({x:E.x*A,y:E.y*A},{x:D.x*A,y:D.y*A},C,x,z)},contains:function(x,B){var A=x.nodeFrom.pos.getc(true),z=x.nodeTo.pos.getc(true),y=x.nodeFrom.scale;this.edgeHelper.arrow.contains({x:A.x*y,y:A.y*y},{x:z.x*y,y:z.y*y},B,this.edge.epsilon)}},hyperline:{render:function(x,y){var B=x.nodeFrom.pos.getc(),A=x.nodeTo.pos.getc(),z=this.viz.getRadius();this.edgeHelper.hyperline.render(B,A,z,y)},contains:c.lambda(false)}})})($jit.Hypertree)})();

//}}}
The term Software Development Pattern is used here to mean a set of resources, practices and techniques that shall frame [[SDP]]'s concrete performance. You may think of it in a similar manner as [[Design or Architectural Patterns|Design Patterns]] but applied to Software Development Process performance. In fact we are trying here to provide a set of very good, tested and proved solutions to common, recurrent challenges you will find in any Software Development endeavour. 

!!Why do we need a Development Pattern?
The [[SDP]] establishes a formal software development process that is the basis for certification and performance at an high maturity level. On doing so it, however, usually assumes that all actors, Customer included, will perform at that level, which, many times, is not the case. On the other hand the [[SDP]] "starts" at Specification phase and assumes a proper Inception phase was performed and produced proper results to serve as its input, again, that, many times, is not the case. 
The fact is that the Customer, in many projects, does not want or does not have the resources to produce a proper Inception phase with also proper results and so expects the software development company to help him to deal with the problem. When this fact is not properly acknowledged the risk exists that you will enter a "garbage in - garbage out" process in which everybody will loose. 

It must be clear that an [[SDP]] that "starts" at Software Requirements Specification is assuming the Inception phase was properly performed and produced adequate results. The scenario where those results are not available or are not adequate is frequent, specially when dealing with customers whose primary concern is not software development, in these cases the assumption that "//the Customer does not know what he wants//" is a very dangerous one and a severe mistake. Of course the Customer knows what he want, we, the software development team, are the ones that do not know what the Customer want.

On the other hand, technical communication, effective technical communication, is a difficult task where mistakes are paid high. A development pattern may help in providing a common vocabulary and in making outcomes more predictable and homogeneous. See, for instance, <<quote 'Brad Appleton on patterns and communication' 'Brad Appleton on patterns and communication'>>

!!A Software Development Pattern

<<quote 'Henry L. Mencken on simplicity' 'Henry L. Mencken on simplicity' 'open'>>

A Software Development Pattern presents, for a domain (technical, business or other) and a known context, a set of proved and coherent choices on ''__how__''&nbsp;to do it in order to produce excellent quality and predictable and reusable results.

Software Development Pattern is an integrated view of and comprises the process performance guidelines, techniques and infrastructure. It is a low-level technical asset not a management tool although it does have radical impacts in management concerns.
The Software Development Process is a rule, the Software Development Pattern is a guideline. You may override it in particular cases if you have a solid reason to do it.

The following topics address some of my findings, study and conclusions about success factors on software development projects for different Customers of an high maturity ([[CMMI|http://www.sei.cmu.edu/cmmi/]] level 5) company. Although the Company works with Customers like [[ESA|http://www.esa.int]], the scenarios I'm addressing here are the ones involving customers from industry, services, government or finance on medium size and criticality projects.

These projects often present enormous challenges, specially at Inception level, due to time and specification detail constraints. If you ever worked in one of these you know the feeling of being asked to produce a Technical Proposal, in a week, to compete with several other proponents. Of course you must be [[agile|Agile Methodologies]] ... but you also must get it right at the first attempt, you will not have another.

[[Systematic Reuse]], [[Opportunistic Productization]] and [[Continuous Improvement]] are the goals to pursue here. First objectives should be establishing a [[meta-model|http://en.wikipedia.org/wiki/Metamodeling]] for project full lifecycle (from Inception to Maintenance, Productization and Reuse) documentation (probably on [[EA|Sparx Enterprise Architect]]) and to establish a "[[Single Version of the Truth|http://en.wikipedia.org/wiki/Single_Version_of_the_Truth]]" (again probably on [[EA|Sparx Enterprise Architect]]).

* [[Business Analysis]] - first the problem then the solution.
* [[Software Specification]] - ask for things in the right way if you want them to be done well.

An important foreword on this subject is that the execution pattern we are proposing works in a ''fall-back mode'', that is, although there are ideal moments and even sequences identified to perform these activities it is not always possible to perform them on those recommended moments. This does not mean that we just give up of doing them, we shall perform them as soon as possible! If I can't produce a good [[DFD|Data Flow Diagram]] at [[RFP]] Analysis I still shall do it at a later time, even if I did produce a DFD at Proposal I shall maintain and update it along all the project. 

----
Back to [[Software Development]]
----
@@color:#c4d6ed; ^^
Description: a set of resources, practices and techniques that shall frame SDP's concrete performance
^^@@
A Software Development Process (SDP) intends to establish ''__when__''&nbsp;and ''__what__''&nbsp;has to be done in order to produce minimum quality assured and repeatable results. 

This is not the main focus of this site as there are plenty process definitions available, our focus is more on the [[Software Development Pattern]] used when instantiating a defined [[SDP]].
----
/%
@@color:#c4d6ed; ^^
Description: Software Development Process (SDP)
^^@@
%/
{{tw_ttoc{}}}
!Why writing good requirements is important
A good, validated, requirements catalogue is what assures your solution will meet Customer's expectations and Project Management's deadlines. 

<<quote 'Frederick P. Brooks on analysis relevance' 'Frederick P. Brooks on analysis relevance' 'open'>>

<<quote 'Mannion and Keepence on requirements effort' 'Mannion and Keepence on requirements effort' 'open'>>

I learned that ''you may build a bad solution over a good specification but you will never build a good solution over a bad specification''. [[Validation]] by the stakeholders plays a fundamental role in assuring you have a good specification, however, this requires that the stakeholders indeed read the proposed specification and, more, that they understand it, in order to provide valuable feed-back that you can use to improve it. "Garbage in - garbage out" processes are just a way to postpone problems to development or, worst, to acceptance.

Specification is a Software Engineering process just like coding, it can, and many times will, be late. Acknowledge it and act accordingly. Project Management will press you to "deliver something" to meet the deadline. They don't believe anyone will really read the specification anyway. This is the worst mistake, even if nobody else reads the specification, you did, and that is a very important success factor. ''Projects shall be late at their beginning, while you still can do something about it, not at their end.'' 
I also learned that ''stress at the beginning is motivation, at the end is  despair''. 

One very important aspect is that [[Requirements Specification|Software Requirements Specification Guidelines]] is a step in a process and is, definitely, not the first one. To be able to produce a good requirements specification you must have previous work done at [[RFP Analysis|RFP Analysis Guidelines]] and [[Technical Proposal|Technical Proposal Production Guidelines]]. Without this previous work, or if you disregard it, you will, most of the times, be engulfed in a scope and out of context detail nightmare and will, probably, build a very poor system.

!Anatomy of a requirement
A <<quote 'Software Requirement' 'Software Requirement'>> is composed of several parts, each one fulfilling specific goals. It is important to consider all these parts on each and every requirement you write.
!!Context
A requirement shall be as simple and short as possible therefore establishing a proper context for its statement is essential. 

<<Image "FR" "640" "Requirements_00.JPG" "https://dl.dropbox.com/" "s/xaxxtkwzahyfimk/" "?dl=1" "Package notes as context for requirements.">>
In [[EA|Sparx Enterprise Architect]] the first natural context provider is the Package element. Packages structure and group Requirements but they also provide a textual note where you shall describe the intent and the vision where the enclosed requirements fit. The purpose is to avoid having to repeat context information on each and every requirement. Here you can explain and guide your reader to allow him to perform a true [[Validation]] of the requirements. A good context provides a way to assure your reader understands the requirements and, more, understands them the same way you do : __this is crucial to avoid ambiguity__.

Other context providers are the [[traceability|Traceability]] relationships to <<quote 'Proposed Features' 'Feature'>>. You shall establish the scope of each topic in specification by identifying the related features it responds to. The Customer shall be able to clearly identify which features (requested and proposed) the requirements respond to in order to understand their impact, trade-offs and practical significance.
!!Title
Title is a very important part of a requirement. First it is the only visible part when you look at a requirements diagram, second it acts as a table of content and as a secondary structure by grouping and sorting the requirements, third, but not less important, it provides context and focus for the requirement statement. This last characteristic is the most important in what concerns validability of the requirement. The title is intended to define a clear scope and determine an unambiguous point of view for the statement, effectively leading the reader towards a common comprehension of the requirement statement.

<<Image "FR" "640" "Requirements_01.JPG" "https://dl.dropbox.com/" "s/qv9xohgby8anog7/" "?dl=1" "Structure, traceability and title as context providers for requirements.">>
A requirement's title is also very useful in assuring the requirement is <<quote 'specific' 'SMART Requirements'>> as it shall be short and direct and establish precisely what the statement is about. A short title for a specific statement is easier than for a complex, multi-targeted statement. As a rule of thumb, if you can not find a proper short title for your requirement then its statement is too complex and not specific.

A very good way of preparing and conducting a requirements specification meeting with the stakeholders is to produce a package structure and a set of requirements with just titles and use them as a topic roadmap and check list during the meeting. Better yet, you shall also identify the [[Proposed Features|Feature]] each requirement is addressing.

A requirement title shall be divided in two parts : Numbering and Name.
An example of a requirement title is : ''~SR-10.10.010 - Authentication''
!!!Numbering
Numbering is essential to make the requirement's reference unequivocal. We suggest that you use hierarchical numbering as it eases referencing and locating requirements in [[EA|Sparx Enterprise Architect]] in a great extent.
Numbering shall follow the format :
''{Prefix}-{Hierarchy Numbers}.{Requirement Number}'' - {Requirement Name}
*''Prefix'' shall be ''SR'' for Software Requirements
*''Hierarchy Numbers'' shall reflect package hierarchical placement of the requirement.
*''Requirement Number'' shall be a sequential, unique (in the hierarchy), gaped and zero padded number that, apart from uniquely identifying the requirement also assures its sort order in [[EA|Sparx Enterprise Architect]]'s Project Browser and generated documentation.
Numbering shall use gap numbering (10 steps) in order to ease renumbering and "in between" insertion.
Take notice that, after the first release of the specification for the stakeholders you shall not modify any requirement's number.
!!!Name

<<Image "FR" "" "Requirements_02.JPG" "https://dl.dropbox.com/" "s/alwsr88cd6cjbkg/" "?dl=1" "Document generated from the above structure">>
The name of the requirement is the first thing your reader reads. It will condition and orient his understanding of the statement and focus its scope. Name is the subject of the statement and you shall use it to check if the statement is, or not, [[specific|SMART Requirements]]. If your statement says much more than the name's subject covers then you shall split your statement in several requirements.


The name may also be used to produce sub-grouping in the requirements, for instance you may use :
''~SR-10.10.020 - Login'' and ''~SR-10.10.030 - Login - Intrusion detection'' to group several related requirements without having to create too many sub-packages. Be sure to not abuse this technique, if you have several closely related requirements it is probably better to group them in a dedicated package.


Sub-grouping also leads us to another important topic : ''structure'' and ''order''. Do not forget that the validatable item for stakeholders will be a document. As in any other document, structure and sequence play a decisive role in readability. A clean, well structured and with proper sequence document promotes understanding and validation.

Think of names as topics in a table of content, this will help in preparing and conducting requirements specification meetings with the stakeholders. With time and experience you will also build a kind of standard template or check list of topics, in each common subject, that can be improved from project to project and that will greatly improve completeness of your specifications. You will be surprised with how much you can reuse from one project to another.





!!Statement
The fundamental reference for requirement's statement writing is <<quote 'SMART Requirements' 'SMART Requirements'>> by <<BibRef "Mannion,Keepence 1995">>. Be sure to read it before anything else, it is a short, very well written paper that any practitioner should know.

A good starting guide for requirement statement expression may be found at <<quote 'Requirements Boilerplates' 'Requirement Boilerplate'>>. 

There are many guidelines for quality requirements. Experience will give you the main ones, the next topics, however, shall always be considered when writing requirements.
* keep it short and direct
** the reader must be able to remember the beginning of the statement when reading its end
** the statement's content must be contained in the title's subject
** use imperative mood
** remember context shall be established on package not on requirement's statement
* respect atomicity
** don't say two things that can change autonomously in the same requirement
** check that you can always answer in a Boolean manner to the question about if the system respects the requirement
** do not cross-relate requirements, this will lead to a status and dependency nightmare. Use Packages for aggregation of interdependent requirements and always evaluate a requirement in the context of its Package and sibling requirements.
* use proper vocabulary and be consistent
** use, and, when needed, establish, business concepts
** beware of synonymy traps (you are in a specific business context)
** build a complete glossary (business and technical)
* don't repeat yourself
** do not repeat statements in different requirements (that's the context's job)
* trace your requirements
** trace each and every requirement to your contractual proposal
** the ones you can not trace are inception mistakes or change requests

As with any other guideline take these with intelligence and consideration. For instance the example requirement ~SR-10.10.030 above could have been split in three different requirements but would that be more readable or maintainable?

!!Other attributes
[[EA|Sparx Enterprise Architect]] provides many other attributes for requirement element and you shall take advantage of some of them :
* [[Status|EA Usage - Attribute Status]] : is a list of states that can be used to classify a requirement as Draft, Proposed, Validated, Implemented, Tested, etc.
* [[Dificulty|EA Usage - Attribute Difficulty]] : The difficulty attribute shall be used to identify areas (features, requirements, modules) that present major challenges to the project.
* [[Priority|EA Usage - Attribute Priority]] : shall be used to distinguish essential, required and nice-to-have elements (must, shall and nice-to-have).
* [[Type|EA Usage - Attribute Type]] : shall be used to denote an appropriate typology for each element.
* [[Version|EA Usage - Attribute Version]] : shall be used to denote changes to requirement after it is validated by stakeholders.
* [[Phase|EA Usage - Attribute Phase]] : can be used to define a staged delivery of the project

!Requirements Specification
Requirements Specification is an engineering process like any other. This means that, professionally, it shall be performed by a team where there are defined roles and that follows a defined process with the proper techniques and tools.

!!The Requirements Team
The team part of the above statement is very important. Requirements gathering is a very stressful task with huge amounts of information, not always coherent, that is obtained in a disperse and, many times, unstructured way. A single person can never grasp that volume of information alone. Requirements gathering shall always be performed by, at least, a two persons team. And I mean two analysts, not a PM and an analyst. This is an essential factor for correctness, completeness and readability of a Requirements Specification. It is also the best way to promote maturity in your company as these teams shall be composed by a more senior analyst and a more junior one.
Also one of the more common problems in requirements is ambiguity and there is no better weapon against it than a discussed, shared and agreed expression and this means that the requirement expression shall be produced, not only reviewed, by more than one person.

!!The Requirements Gathering Process
!!!Preparation
The Requirements Process involves Customer interaction and access to scarce resources (the Customer's experts) and, as such, it shall be planed and prepared with all the care possible to not waste opportunities and to optimize each and every interaction.

Remember that, during Requirements Specification you must also protect the proposed scope in order to keep focus and not risk project's success. To do this you must prepare the list of subjects to address in each meeting and with each stakeholder. A good way of doing this is by creating a specification structure (Packages in EA) to address each subject of the Proposed Features. The [[Technical Proposal|Technical Proposal Production Guidelines]] shall be your initial roadmap, although you'll need to add more detail and refinement to its structure and, probably, add some more technical subjects not explicitly on the Proposal, you must remember that scope was established on Proposal and shall not be modified on Requirements without a formal Change Procedure.

Start by creating your package structure (an evolution of the one in your Proposal, don't worry, you will refactor it more than a couple of times during this phase), then drag your Proposed Features to it and start asking yourself : "What information will I need to develop this Feature?". Create a Software Requirement with only a title for each one of your questions or answers and [[trace|Traceability]] it to the correspondent Proposed Feature. 
On a second iteration try to add some content to the proposed requirements you have. This content is your preliminary view and shall be confirmed or refuted by the stakeholders but will serve as a starting point and checklist. This is also a very good time to access reusable requirements sets, or even solutions, that you may have.

Depending on the size of the project this phase shall take from some days to some weeks. Be careful to not take too much time without validating your view with the Customer, you may be completely wrong. But also consider that jumping directly to stakeholder interview at the beginning of a project without proper preparation is foolish and involves the risk of loosing control of the specification process and project's scope as well as Customer's respect.

Again, remember this shall be a team effort and that this is extremely difficult to perform alone as most of the information shall be obtained, clarified and detailed in a dialog process inside the team. 

After some iterations and lots of brainstorming you shall have a fairly decent structure of topics to be addressed and also some insight on which stakeholders you need to interview for each subject. Build an interview plan, with detailed schedule, and propose it to the Customer remember to include Interview and Consolidation time. After obtaining agreement on the schedule prepare meeting invites with detailed explanation of the subjects to be addressed, also include all information requests (Customer's documents, other systems specifications, etc.) you can anticipate you will need. This will allow the stakeholders to prepare themselves (possibly aligning their own team views and gathering needed information) prior to the meeting and make this one much more effective. Be prepared to face some stakeholders that  will not prepare the meeting. That's life and they are the Customer...

!!!Interview
Interview time shall not go on for more than 4 hours a day. In my experience, more than this is a waste of time and jeopardizes consolidation efforts.
When you have to travel to Customer's premises, your management will pressure to do all the interviews in the shortest time possible and then return home and consolidate. This is a severe mistake, you will loose half of the information gathered and will be sure of none.

Start the interview by explaining your methodology and its goals then ask the stakeholders to briefly address their view of the subject to handle. Be ready to adjust, on the fly, the structure and information you prepared. Then start, on a topic by topic approach, to detail, validate and complete your prepared information. When you reach a statement on a subject be sure to clearly state it for all the attendees to understand and validate.

Be sure to update and correct your Glossary in every opportunity. Every time a new concept emerges don't be afraid to ask what it means and record its meaning.

I prefer to record most of the information in my [[CASE]] tool directly (it offers a lot of functionality like relationship, state, atomic elements, etc. that help the recording process) but you may use other methods if you want. The point here is to effectively and completely record the information. Don't waste time in giving it a final form, you will have Consolidation for that, but also do not postpone important issues and make sure you understand the stakeholders point. Your questions are not dumb nor are the Customer's representatives, they are experts in their fields and they understand that you are not, and most people likes to teach things they are good at. Show that you are good at learning and that you preserve the information they give you and you will earn their respect. That's the first step for project's success.

!!!Consolidation
Consolidation means to structure, persist, normalize, disambiguate, discuss, understand and establish the requirements.

After stakeholder interview a consolidation meeting within the analysis team is essential. These meetings shall take place as soon as possible after the interview and shall persist the information gathered in the requirements tool. The consolidation meeting shall take, at least, as many time as the interview, most of the times it will take more. You shall review the statements expression and complement them with auxiliary diagrams (a business process, an improved DFD or a GUI mock-up for instance). You shall also take the time to make the requirements [[SMART|SMART Requirements]] and to assure they are coherent in the full system.

As soon as possible after the consolidation meeting, its results, in a draft form, shall be informally [[validated|Validation]] with the stakeholders from the interview. The subject will be fresh in their minds and they can immediately correct any errors or omissions on your interpretation. Also the information volume will be more manageable in small chunks of 10 pages than when you only present a final 200 pages document that nobody has the time, or will, to fully and deeply validate. This will assure an informal preliminary acceptance of the analysis team view and also assure you are preventing rolling errors. It is also very important in aligning expectations when you have to compatibilize different views of the system from different stakeholders.

!!!Review
A peer review is essential in any professionally produced product. It is even more important in Requirements Specification. But not less important is Customer validation of the proposed specification. For this to happen your specification must be readable. If it is not, you'll get a "postponed agreement" that, you may be sure, will get on you as soon as anything goes wrong and, as soon as it starts, rest assured it will not stop and you'll be in "scope hell" and will spend most of your time discussing, justifying and arguing about scope.

!The analyst role
Finally you should always take good notice on what says <<quote 'Tom DeMarco on the Software Analyst role' 'Tom DeMarco on the Software Analyst role' 'open'>>

----
See also : [[Software Requirement]] [[SMART Requirements]] [[EA Usage - Requirements Diagram]]
----
<<TiddlerToC min-entries:1>>
@@color:#c4d6ed; ^^
Description: Writing Good Requirements guideline
^^@@
/***
|Name|GotoPluginInfo|
|Source|http://www.TiddlyTools.com/#GotoPlugin|
|Documentation|http://www.TiddlyTools.com/#GotoPluginInfo|
|Version|1.9.2|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|documentation|
|Description|Documentation for GotoPlugin|
''View a tiddler by typing its title and pressing //enter//.''  As you type, a list of possible matches is displayed.  You can scroll-and-click (or use arrows+enter) to select/view a tiddler, or press escape to close the listbox to resume typing.  When the listbox is not displayed, pressing //escape// clears the current input.
!!!!!Usage/Examples
<<<
syntax: {{{<<gotoTiddler quiet search inputstyle:... liststyle:... filter:...>>}}}
All parameters are optional.
* ''quiet'' (//keyword//)<br>list will not be automatically display as each character is typed.  Use //down// or //enter// to view the list.
* ''showlist'' (//keyword//)<br>list will always be displayed, inline, directly below the input field.
* ''search'' (//keyword//)<br>adds an extra 'command item' to the list that can be used to invoke a full-text search using the entered value.  This can be especially useful when no matching tiddler titles have been found.
* ''inputstyle:'' and ''liststyle:''<br>are CSS declarations that modify the default input and listbox styles, respectively.  Note: the CSS styles must be surrounded by ({{{"..."}}} or {{{'...'}}}) or ({{{[[...]]}}}) (e.g., {{{liststyle:"border:1px dotted blue;color:green;..."}}}.
* ''filter:''<br>is a single tag value (or a boolean tag expression if MatchTagsPlugin is installed), and is used to limit the search to only those tiddlers matching the indicated tag or tag expression (e.g., {{{<<gotoTiddler filter:"faq or help">>}}})
{{{<<gotoTiddler>>}}}
<<gotoTiddler>>
{{{<<gotoTiddler search>>}}}
<<gotoTiddler search>>
{{{<<gotoTiddler showlist filter:"pluginInfo" liststyle:"height:10em;width:auto;">>}}}
<<gotoTiddler showlist filter:"pluginInfo" liststyle:"height:10em;width:auto;">>
<<<
!!!!!Configuration
<<<
*Match titles only after {{twochar{<<option txtIncrementalSearchMin>>}}} or more characters are entered.<br>Use down-arrow to start matching with shorter input.  //Note: This option value is also set/used by [[SearchOptionsPlugin]]//.
*To set the maximum height of the listbox, you can create a tiddler tagged with <<tag systemConfig>>, containing:
//{{{
config.macros.gotoTiddler.listMaxSize=10;  // change this number
//}}}
<<<
!!!!!Revisions
<<<
2009.05.22 1.9.2 use reverseLookup() for IncludePlugin
2009.04.12 1.9.1 support multiple instances with different filters by using per-element tiddler cache instead of shared static cache
2009.04.05 1.9.0 added 'showlist' parameter for inline display with listbox always visible.
2009.03.23 1.8.0 added txtIncrementalSearchMin (default=3).  Avoids fetching long lists.  Use down arrow to force search with short input.
2008.12.15 1.7.1 up arrow from input field now moves to end of droplist (search for input).  Also, shift+enter cam now be used to quickly invoke search for text.
2008.10.16 1.7.0 in macro handler(), changed to use //named// params instead of positional params, and added optional "filter:" param for tag filtering.  Removed 'insert' handling (now provided by [[QuickEditPlugin]]).
2008.10.02 1.6.1 for IE, wrap controls in a table.  Corrects placement of listbox so it is below input field.
2008.10.02 1.6.0 added 'search' param for optional "Search for:" item that invokes full text search (especially useful when no title matches are found)
2008.02.17 1.5.0 ENTER key always displays tiddler based on current input regardless of whether input matches any existing tiddler
2007.10.31 1.4.3 removed extra trailing comma on last property of config.macros.gotoTiddler object.  This fixes an error under InternetExplorer that was introduced 6 days ago... sure, I should have found it sooner, but... WHY DON'T PEOPLE TELL ME WHEN THINGS ARE BROKEN!!!!
2007.10.25 1.4.2 added onclick handler for input field, so that clicking in field hides the listbox.
2007.10.25 1.4.1 re-wrote getItems() to cache list of tiddlers/shadows/tags and use case-folded simple text match instead of regular expression to find matching tiddlers.  This *vastly* reduces processing overhead between keystrokes, especially for documents with many (>1000) tiddlers.  Also, removed local definition of replaceSelection(), now supported directly by the TW2.2+ core, as well as via backward-compatible plugin
2007.04.25 1.4.0 renamed macro from "goto" to "gotoTiddler".  This was necessary to avoid a fatal syntax error in Opera (and other browsers) that require strict adherence to ECMAScript 1.5 standards which defines the identifier "goto" as "reserved for FUTURE USE"... *sigh*
2007.04.21 1.3.2 in html definition, removed DIV around droplist (see 1.2.6 below).  It created more layout problems then it solved. :-(
2007.04.01 1.3.1 in processItem(), ensure that correct textarea field is found by checking for edit=="text" attribute
2007.03.30 1.3.0 tweak SideBarOptions shadow to automatically add {{{<<goto>>}}} when using default sidebar content
2007.03.30 1.2.6 in html definition, added DIV around droplist to fix IE problem where list appears next to input field instead of below it.  
2007.03.28 1.2.5 in processItem(), set focus to text area before setting selection (needed for IE to get correct selection 'range')
2007.03.28 1.2.4 added prompt for 'pretty text' when inserting a link into tiddler content
2007.03.28 1.2.3 added local copy of core replaceSelection() and modified for different replace logic
2007.03.27 1.2.2 in processItem(), use story.getTiddlerField() to retrieve textarea control
2007.03.26 1.2.1 in html, use either 'onkeydown' (IE) or 'onkeypress' (Moz) event to process <esc> key sooner, to prevent <esc> from 'bubbling up' to the tiddler (which will close the current editor).
2007.03.26 1.2.0 added support for optional "insert" keyword param.
2006.05.10 1.1.2 when filling listbox, set selection to 'heading' item... auto-select first tiddler title when down/enter moves focus into listbox
2006.05.08 1.1.1 added accesskey ("G") to input field html (also set when field gets focus).  Also, inputKeyHandler() skips non-printing/non-editing keys. 
2006.05.08 1.1.0 added heading to listbox for better feedback (also avoids problems with 1-line droplist)
2006.05.07 1.0.0 list matches against tiddlers/shadows/tags.  input field auto-completion... 1st enter=complete matching input (or show list)... 2nd enter=view tiddler.  "quiet" param controls when listbox appears.  handling for enter (13), escape(27), and down(40) keys.   Change 'ondblclick' to 'onclick' to avoid unintended triggering of tiddler editor).  Shadow titles inserted into list instead of appended to the end.
2006.05.05 0.0.0 started
<<<
!Self-balanced Parallel Asynchronous Processor (SBPAP)

Provide a reusable platform and architectural guidance for self-balanced parallel asynchronous processing of variable data objects in order to increase applications performance and leverage actual multiprocessor environments full potential.
Self-balancing means that the system is able to adjust itself to load and available resources during its operation.
Parallel means that the system is able to process each data object in different parallel threads taking full advantage of multi-processor environments.
Asynchronous means that the system is intended for asynchronous usage, that is, it is not intended for scenarios where an immediate response is needed from processing (although it can also be used that way, probably with some performance and architectural advantages).

You may download the full article [[here|https://www.dropbox.com/s/luehyrcvmpeq8yd/Self-balanced%20Parallel%20Asynchronous%20Processor%20%28SBPAP%29.docx?dl=1]]


----
/%
@@color:#c4d6ed; ^^
Description: Self-balanced Parallel Asynchronous Processor (SBPAP)
^^@@
%/
!Welcome to André de Carvalho's Wiki home page.

I'm involved with [[Software Development]] since the 80's and have worked from Turbo Pascal (3.01a), Clipper and Fox Pro (on SCO Xenix ;), through Delphi and now I mostly use C#.

I'm clearly a data-oriented ~WinForms guy that hates to "//program in XML//" and has not too much patience for browser limitations. 

Maybe I'm old fashioned but I do like good conceptual data models ( [[Sybase|http://www.sybase.com/]] [[Power Designer|http://www.sybase.com/products/modelingdevelopment/powerdesigner]] is my tool), the challenge of investigating a business problem and produce an elegant object oriented architectural solution ( [[Sparx Enterprise Architect]] is essential) and then to implement a robust and performance wise application that is expandable and reusable.

Wikis, and specially [[TiddlyWiki|http://www.tiddlywiki.com/]], were the first browser application that really interested me and now I'm starting to discover [[TiddlySpace|http://tiddlyspace.com/]]...
!Last content updates
|Last 5 tiddlers created|Last 5 tiddlers modified|h
|<<ContentTimeline created 5>>|<<ContentTimeline modified 5>>|
 See more in [[Last Updates|LastUpdates]]

__You may subscribe an RSS feed for this site in [[this link|http://tiddlyspace.com/profiles/acarvalho.atom]].__

!Tagcloud
<<tagCloud excludeLists excludeSearch systemConfig systemServer PluginInfo Plugin excludeMissing excludePublisher takenotepackage app DiscoveryPackage NavigationPackage IconPackage TidIDEPackage TaskPackage ScrollbarPackage MediaPackage pluginInfo @cdent @developers @ricardoperes Administration follow tips Content System>>
''Also check TagPolicy for a resume of the more important subject tags used in this space. They can help you navigate the information.''
!~TiddliWiki
''
~TiddliWiki is a __non linear structure__, that is, there is not a fixed order to read its contents. For instance, if you are interested in my thoughts about [[Software Development]] you shall get to that tiddler then close all other opened tiddlers and start reading. You will find links to other tiddlers (concept definitions or detailed information about referred topics). If you hoover over links you will see a short description of its content, if you click it will open, you can read and then close it to go back to your main topic.
If you are new to ~TiddlyWiki my advice is that you keep only two tiddlers opened at the same time : your main topic one and the one that you followed to, when finished reading the second close it.
Be sure to explore the tiddler menu functionality and the tags also.

A note about most images in this site : if you ~Shift-Click on them they will zoom to their original (bigger) size.

If you are not comfortable with multiple tiddler navigation you may check <<option chkEnableTabsBar>> __Tabbed navigation__ or tune other DisplayOptions in this space. 
''
!General
You may also be interested in other [[Sites I Like]] or in [[Development Links]]
----
If you are seeing this page in the "bag" without images, you may prefer to access the full version [[here|http://acarvalho.tiddlyspace.com/]].
----
I may be contacted on ''Gmail'' as //andre.d.a.carvalho// and you can also check [[TiddlySpace collaboration]].
----
@@color:#c4d6ed; ^^
Description: The main entry point in this wiki. 
^^@@
Business analysis literature commonly refers to ''Requirements'' (User, System and Software). See, for instance, <<BibRef "BABOK 2008">>. But, in the software world, ''Requirements'' have a very specific meaning and several conditions to be considered as such. The best characterization is in ''[[SMART Requirements]]'' <<BibRef "Mannion,Keepence 1995">>.

"//A great deal of formal and anecdotal evidence exists that the typical quality of actual requirement specifications today is embarrassingly poor. In practice, far too many requirements are ambiguous, incomplete, infeasible, unverifiable, inadequately prioritized, and mutually inconsistent [Firesmith 2003a]. In fact, this poor quality of individual requirements and the requirements specifications that document them is a primary reason why so many projects continue to fail [Standish 1994].//"
Donald G. Firesmith: “Quality Requirements Checklist”, in [[Journal of Object Technology, vol. 4|http://www.jot.fm/issues/issue_2005_11/column4]], no. 9 November - December 2005, pp. 31 - 38

Experience tells us that it is not so often that we find SMART requirements in ''Requests for Proposal'' or even in ''Technical Proposals'', they usually only appear, if they do at all, on the ''Specification Phase'' in ''Requirements Gathering''. Using the ''Requirements'' concept in a superficial and stressed phase, as the ''Inception'' usually is, is dangerous as it implies a concreteness degree that is seldom or never achieved. This leads to misunderstandings and miscalculations that may be very hard to solve. It also increases the risk of expressing artificial requirements that do not correspond to an effective need but will condition architecture sometimes preventing the best choices.

<<Image "FR" "250" "Requirements-Elements.png" "https://dl.dropbox.com/" "s/o4ewv8nlr4vfb7w/" "?dl=1" "Feature element in EA.">>
''[[Feature]]s'' are an higher abstraction level towards ''[[Software Requirement]]s'' in the sense that they allow a more relaxed expression of a need or of a commitment. Features can be as [[SMART|SMART Requirements]] as Requirements but they need not to be. The required characteristics of a feature are :
* ''Need oriented'' : A [[feature|Feature]] is a service that the system provides to fulfil one or more stakeholder needs.
* ''Specific enough'' : they are atomic to the granular level possible at the circumstances.
* ''Reasonable scope'' : they provide a reasonable scope delimitation for the request or proposal.
* ''Support estimation'' : they provide support for estimation within the accepted risk levels.
* ''Support Validation'' : they support Customer [[validation|Validation]] of Proposal understanding, adequacy, completeness and contractual commitment.
* ''[[Traceable|Traceability]]'' : uniquely identified and relatable to stakeholders, between request and proposal and between proposal and requirements.

Features concreteness level may range from very specific user requirement ("The system shall support IE 6.0.") to very diffuse problem statements ("The system shall optimize data entry effort.") to which the software company is expected to give the best possible answer. Of course Proposed Features shall narrow Requested Feature's scope in order to provide a validateable direction to proposed solution and a [[controlled scope|Scope Management]] for the Proposal.


----
Back to [[Business Analysis]]
See also [[Feature]]
----
@@color:#c4d6ed; ^^
Description: definition and discussion of the two concepts and their usage.
^^@@
"//''My final point (my loss of faith that “the customer is king”) is not just a change in my own thinking, but a sign of the maturing of IT in specific and of the business climate in general. In 1975, the typical commercial system we built was a first time automation of what had before been done manually. The customer, of course, was the only one who knew what this was all about and his/her sense of what the automated version would have to do was prime. 
Today we are building third and fourth generation automated systems, and IT personnel are often as well or better informed about how the existing system works as their business partners. More important, the meaningful successes of IT today are no longer to be achieved by simple automation or re-automation of existing process. We have moved on to a new era: Our challenge today is to combine improved information technology and market opportunity in order to create product that is radically different from what could have been achieved in a less connected world. This tells us that the new king is neither client nor technologist, but their partnership: the tightly merged amalgam of business and technological expertise. Companies that achieve and maintain such a partnership are the ones who will prosper.''//"

[[Structured Analysis: Beginnings of a New Discipline|http://cs.txstate.edu/~rp31/papersSP/TDMSpringer2002.pdf]]
[[Tom DeMarco|http://en.wikipedia.org/wiki/Tom_DeMarco]]
sd&m Conference 2001, Software Pioneers
Eds.: M. Broy, E. Denert, Springer 2002
----
/%
@@color:#c4d6ed; ^^
Description: Quote of Tom DeMarco opinion on modern Software Analyst role
^^@@
%/
(function() {
var getCSRFToken = function(window) {
	// XXX: should not use RegEx - cf.
	// http://www.quirksmode.org/js/cookies.html
	// https://github.com/TiddlySpace/tiddlyspace/commit/5f4adbe009ed4bda3ce39058a3fb07de1420358d
	var regex = /^(?:.*; )?csrf_token=([^(;|$)]*)(?:;|$)/;
	var match = regex.exec(document.cookie);
	var csrf_token = null;
	if (match && (match.length === 2)) {
		csrf_token = match[1];
	}

	return csrf_token;
};

if (typeof config !== 'undefined' && config.extensions &&
		config.extensions.tiddlyspace &&
		config.extensions.tiddlyspace.getCSRFToken === null) {
	config.extensions.tiddlyspace.getCSRFToken = getCSRFToken;
} else {
	window.getCSRFToken = getCSRFToken;
}
})(window);
Project Manager
----
/%
@@color:#c4d6ed; ^^
Description: Project Manager
^^@@
%/
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xl="http://www.w3.org/1999/xlink" version="1.1" viewBox="434 218 68 68"
width="30" height="30">
<g stroke="none" stroke-opacity="1" stroke-dasharray="none" fill="none" fill-opacity="1">
	<g>
		<path d="M 478.39694 232.53705 L 478.39694 232.53705 
		C 477.1145 231.85132 475.77875 231.30147 474.41058 230.88734 L 474.41058 218.24994 L 461.58942 218.24994 
		L 461.58942 230.88734 C 460.22125 231.30147 458.8855 231.85132 457.60306 232.53705 L 448.66824 223.60214 
		L 439.6022 232.66814 L 448.53717 241.60304 C 447.8515 242.8854 447.30157 244.22116 446.88745 245.58936 
		L 434.25 245.58936 L 434.25 258.41052 L 446.88745 258.41052 
		C 447.30157 259.77869 447.8515 261.11447 448.53717 262.39688 L 439.6022 271.33173 L 448.66824 280.3978 
		L 457.60306 271.46283 C 458.8855 272.14862 460.22125 272.69846 461.58942 273.11252 L 461.58942 285.74988 
		L 474.41058 285.74988 L 474.41058 273.11252 C 475.77875 272.69846 477.1145 272.14862 478.39694 271.46283 
		L 487.33176 280.3978 L 496.39767 271.33173 L 487.46286 262.39688 
		C 488.14853 261.11447 488.69836 259.77869 489.11255 258.41052 L 501.74988 258.41052 L 501.74988 245.58936 
		L 489.11255 245.58936 C 488.69836 244.22116 488.14853 242.8854 487.46286 241.60304 L 496.39767 232.66814 
		L 487.33176 223.60214 Z M 475.3328 244.66714 C 479.3825 248.71698 479.3825 255.2829 475.3328 259.33273 
		C 471.28296 263.3826 464.71704 263.3826 460.66724 259.33273 
		C 456.61737 255.2829 456.61737 248.71698 460.66724 244.66714 
		C 464.71704 240.61734 471.28296 240.61734 475.3328 244.66714" fill="#111"
		class="glyph"/>
	</g>
</g>
</svg>
!An incremental approach
Implementing [[Systematic Reuse]] is an engineering improvement process, much like the ones performed to achieve maturity levels (CMMI for instance). This means that there are areas where you should invest first and that are pre-conditions to the more evolved ones. An incremental approach, where you progress in phases in your ability to perform and on the return of your performance, is, thus, recommended. 

Before you start you should access if your organization is ready for such an initiative.

"//It is believed that until CMM Level 3 ("Defined Process") is achieved, when the entire organization is able to follow an explicitly defined process, it is hard to systematically make sweeping process and technology changes. In particular, effective pervasive software reuse requires many, if not most, projects in the organization to follow compatible managed processes to create, support or reuse assets. CMM Level 3 is a significant indicator that the organization has achieved a process maturity and readiness for change to this level of formal multi-project coordination.//"
(…)
"//First and foremost, introducing systematic software reuse is a significant process improvement, driven by critical business need. The CMM is a process improvement framework that summarizes key guidelines about mature software process, which can be directly applied to improved reuse practice. The change to a set of concurrent, managed and supported multi-project creator/reuser process demands significant organization changes and standardized process throughout the organization.//"
Reuse Strategies [[CMM as a Framework for Adopting Systematic Reuse|http://martin.griss.com/pubs/obm10.htm]], Martin L. Griss, Object Magazine, March, 1998, pp. 60-62,69.

Also make sure that the effort, time and expected return of the investment is well understood by your top and middle management as medium-term support will be essential to achieve any significant goals. Accountancy, that is, the ability to objectively demonstrate profitability of the initiative, is essential to keep it running, and funded, on the medium-term.

Below we will propose a Reuse Maturity Model (RMM) that you may use to plan and evaluate your reuse improvement programme but first you shall determine your goals, targets and actors in this endeavour.

!Improvement targets, goals and actors
Reuse targets are not only, nor even mainly, software code assets. Reuse is easier towards abstraction and, as such, specifications, techniques, architectures, know-how and many other tangible and intangible assets shall be considered when planning [[Systematic Reuse]] implementation. Probably it is much more rewarding to start by reusing an [[archetype|Application Archetype]] catalogue or a [[filesystem and namespace guideline|Namespace and Filesystem Guidelines]] than a specific code library. Consider this when planning your move towards systematic reuse and consider that you shall start by removing [[reuse obstacles|Reuse Obstacles]].

The goals of the improvement programme are to remove obstacles and to promote reuse and to achieve better and better reuse levels across all your software development activities thus achieving the known [[reuse advantages|Reuse Advantages]].

Actors of this improvement process are each and every person involved in the development process from management and sales, through development teams to designers and quality assurance among many others. This must be seen as a company wide pervasive endeavour. Of course that management sponsorship is essential but also direct project management is a condition for reuse to succeed. The first is quite easy to get but the last one is harder. [[PM]]s are usually much more concerned with the short-term than with medium or long-term benefits they will not willingly accept to divert a few resources from the immediate project goals to a medium-term target unless that is planned and paid for in advance and they are also rewarded for future earnings. [[PM]]s like to reuse they do not like to produce for reuse.

!A Reuse Maturity Model (RMM)
|Stage|Description|h
|Individual|Individual reuse is the first stage. This is the personal reuse every programmer or analyst does.|
|Processual|Processual stage is the one where a mature software company has established development processes and provides structural templates for most of its work products. Mandatory guidelines for [[Namespace and Filesystem Guidelines]], for instance, start to be established|
|Methodological|At this stage a software company provides a full lifecycle [[meta-model|http://en.wikipedia.org/wiki/Metamodeling]] and promotes a "[[Single Version of the Truth|http://en.wikipedia.org/wiki/Single_Version_of_the_Truth]]", content templates and methodological orientation and examples that actively fight [[reuse obstacles|Reuse Obstacles]]. Coherent metrics on reuse start to be established and dedicated effort is allocated to promote reuse.|
|Systematic|[[Reuse by copy|Reuse by Reference]] is reduced and [[Continuous Improvement]] is promoted. Reuse profitability is established. Dissemination practices and infrastructures are put in place. Reuse is considered and performed across all phases. Dedicated and formal roles are established for reuse. Permanent and stable funding. Medium / long term planning.|
----
@@color:#c4d6ed; ^^
Description: Guidelines on implementing a Systematic Reuse improvement process.
^^@@
Request for Proposal
----
See also : [[RFP Analysis Guidelines]]
----
/%
@@color:#c4d6ed; ^^
Description: Request for Proposal
^^@@
%/
/***
|''Name''|TiddlySpaceFollowingWizard|
|''Version''|0.7.0|
|''Description''|Provides a following wizard macro and deleteButton view type|
|''Author''|Jon Robson|
|''Requires''|TiddlySpaceConfig TiddlySpaceFollowingPlugin TiddlySpaceTiddlerIconsPlugin|
|''License''|[[BSD|http://www.opensource.org/licenses/bsd-license.php]]|
!Usage
{{{ <<followWizard>> }}}
!StyleSheet
.followWizard ul,
.followWizard li .siteIcon,
.followWizard li {
	list-style: none;
	display: inline-block;
}

.followWizard li {
	margin-right: 8px;
	background-color: #eee;
	-moz-border-radius: 5px;
	-webkit-border-radius: 5px;
	padding: 4px;
}
!Code
***/
//{{{
(function($) {

var tweb = config.extensions.tiddlyweb;
var tiddlyspace = config.extensions.tiddlyspace;
var currentSpace = tiddlyspace.currentSpace.name;

var shadows = config.shadowTiddlers;
shadows.FollowersTemplate = "<<view server.bag SiteIcon width:24 height:24 spaceLink:yes label:no>> <<view server.bag spaceLink>>";
shadows.FollowingTemplate = "<<view title SiteIcon width:24 height:24 spaceLink:yes label:no>> <<view title spaceLink>> <<view title deleteButton>>";

var name = "StyleSheetFollowingWizard";
shadows[name] = "/*{{{*/\n%0\n/*}}}*/".
	format(store.getTiddlerText(tiddler.title + "##StyleSheet"));
store.addNotification(name, refreshStyles);

var wizard = config.macros.followWizard = {
	locale: {
		mission: "Which user or space would you like to follow?",
		badpermissions: "Only members of the space can maintain followers.",
		follow: "follow"
	},
	handler: function(place, macroName, params, wikifier, paramString, tiddler) {
		var locale = wizard.locale;
		var container = $("<div />").addClass("followWizard").appendTo(place)[0];
		if(!readOnly) {
			var form = $("<form />").addClass("followForm").appendTo(container)[0];
			$("<span />").text(locale.mission).appendTo(form);
			var input = $("<input />").attr("name", "space").attr("type", "text").appendTo(form);
			$("<input />").attr("type", "submit").val(locale.follow).appendTo(form).click(function(ev) {
				wizard.addFollowing(ev, input.val());
				ev.preventDefault();
			});
		} else {
			$(container).addClass("annotation").text(locale.badpermissions);
		}
	},
	addFollowing: function(ev, space) {
		var name = tiddlyspace.resolveSpaceName(space);
		if(!name) {
			alert("That doesn't appear to be a valid space name. Please check and try again.");
			return;
		}
		var title = "@" + name;
		var tiddler = store.getTiddler(title);
		if(tiddler) {
			tiddler.tags.push("follow");
		} else {
			tiddler = new Tiddler(title);
			tiddler.tags.push("follow");
			merge(tiddler.fields, config.defaultCustomFields);
		}
		store.saveTiddler(tiddler);
		autoSaveChanges();
	}
};

config.macros.view.views.deleteButton = function(value,place,params,wikifier,paramString,tiddler) {
	var tid = store.getTiddler(value)
	if(tid && config.commands.deleteTiddler.isEnabled(tid)) {
		var handler = function(ev) {
			config.commands.deleteTiddler.handler(ev,ev.target,value);
		};
		createTiddlyButton(place, "X", "delete this tiddler", handler);
	}
};

})(jQuery);
//}}}
!Followers
<<followers>>
!Activity
[[Replies and Notifications]]

<<activity>>
!Following
All spaces tagged follow
<<list filter [tag[follow]][sort[title]]>>

<<followSuggestions>>
*[[Database Programming|Programming Database]]

----
* [[Object Oriented Programming (OOP)|ObjectOrientedProgramming]] - concepts and thoughts about this essential paradigm.
* [[Development Links]] - a collection of worth visiting links.

Some tools I made that you may find interesting
* [[ASPerfBench]] - small tool to allow for quick assessment of .Net code relative performance.
----
@@color:#c4d6ed; ^^
Description: Programming main page
^^@@
The activity feed is best for sharing opinions on something. To make best use of it create a tiddler and tag it with a username you would like to share thought with on this subject.

For instance I might create a tiddler called [[Animal I'd least like to be stuck in a cage with]]. I might say 
<<<
I would least like to be stuck in a cage with a lion as it could tear me apart amongst other reasons.
<<<
I then tag it @matias to get @matias's attention to see what he think. This flags it in @matias's activity feed and tells him that I am interested in his thoughts. Of course @matias can ignore it, and if he is not using the activity feed feature he may not even know about the message. If he wants to respond all @matias then has to do is create his own tiddler [[Animal I'd least like to be stuck in a cage with]]. Matias might say
<<<
A lion would be not as bad as a great white shark... not only would you be stuck in a cage with it but you would  be underwater with a likelihood of drowning to increase suffering.
<<<
It's not over yet.. now I can refine my original post with the thoughts of Matias. I might think mm, @matias has got a point there with the water, but I think a crocodile would more likely eat me then a great white shark and I fancy my chances with the great white.

I then update my tiddler to say 
<<<
I would least like to be stuck in a cage with a crocodile as it could tear me apart amongst other reasons. A lion would also be scary however I'm not a good swimmer so would be less likely to be able to make an escape. A crocodile is worse than a shark as shark attacks on humans are rare, so I'd fancy my chances.
<<<

We continue replying this way revising our tiddlers till the process finishes and I have a tiddler which clearly explains the [[Animal I'd least like to be stuck in a cage with]] with very detailed reasoning.
/***
|''Name:''|TiddlersBarPluginMP|
|''Description:''|A bar to switch between tiddlers through tabs (like browser tabs bar).|
|''Version:''|1.2.5|
|''Date:''|Jan 18,2008|
|''Source:''|http://visualtw.ouvaton.org/VisualTW.html|
|''Author:''|Pascal Collin|
|''License:''|[[BSD open source license|License]]|
|''~CoreVersion:''|2.1.0|
|''Browser:''|Firefox 2.0; InternetExplorer 6.0, others|
!Attention
This plugin contains some changings, at the end of the plugin marked with !!MP!!

!Demos
On [[homepage|http://visualtw.ouvaton.org/VisualTW.html]], open several tiddlers to use the tabs bar.
!Installation
#import this tiddler from [[homepage|http://visualtw.ouvaton.org/VisualTW.html]] (tagged as systemConfig)
#save and reload
#''if you're using a custom [[PageTemplate]]'', add {{{<div id='tiddlersBar' refresh='none' ondblclick='config.macros.tiddlersBar.onTiddlersBarAction(event)'></div>}}} before {{{<div id='tiddlerDisplay'></div>}}}
#optionally, adjust StyleSheetTiddlersBar
!Tips
*Doubleclick on the tiddlers bar (where there is no tab) create a new tiddler.
*Tabs include a button to close {{{x}}} or save {{{!}}} their tiddler.
*By default, click on the current tab close all others tiddlers.
!Configuration options 
<<option chkDisableTabsBar>> Disable the tabs bar (to print, by example).
<<option chkHideTabsBarWhenSingleTab >> Automatically hide the tabs bar when only one tiddler is displayed. 
<<option txtSelectedTiddlerTabButton>> ''selected'' tab command button.
<<option txtPreviousTabKey>> previous tab access key.
<<option txtNextTabKey>> next tab access key.
!Code
***/
//{{{
config.options.chkEnableTabsBar = config.options.chkEnableTabsBar ? config.options.chkEnableTabsBar : true;
config.options.chkHideTabsBarWhenSingleTab  = config.options.chkHideTabsBarWhenSingleTab  ? config.options.chkHideTabsBarWhenSingleTab  : true;
config.options.txtSelectedTiddlerTabButton = config.options.txtSelectedTiddlerTabButton ? config.options.txtSelectedTiddlerTabButton : "closeOthers";
config.options.txtPreviousTabKey = config.options.txtPreviousTabKey ? config.options.txtPreviousTabKey : "";
config.options.txtNextTabKey = config.options.txtNextTabKey ? config.options.txtNextTabKey : "";
config.macros.tiddlersBar = {
	tooltip : "see ",
	tooltipClose : "click here to close this tab",
	tooltipSave : "click here to save this tab",
	promptRename : "Enter tiddler new name",
	currentTiddler : "",
	previousState : false,
	previousKey : config.options.txtPreviousTabKey,
	nextKey : config.options.txtNextTabKey,	
	tabsAnimationSource : null, //use document.getElementById("tiddlerDisplay") if you need animation on tab switching.
	handler: function(place,macroName,params) {
		var previous = null;
		if (config.macros.tiddlersBar.isShown())
			story.forEachTiddler(function(title,e){
				if (title==config.macros.tiddlersBar.currentTiddler){
					var d = createTiddlyElement(null,"span",null,"tab tabSelected");
					config.macros.tiddlersBar.createActiveTabButton(d,title);
					if (previous && config.macros.tiddlersBar.previousKey) previous.setAttribute("accessKey",config.macros.tiddlersBar.nextKey);
					previous = "active";
				}
				else {
					var d = createTiddlyElement(place,"span",null,"tab tabUnselected");
					var btn = createTiddlyButton(d,title,config.macros.tiddlersBar.tooltip + title,config.macros.tiddlersBar.onSelectTab);
					btn.setAttribute("tiddler", title);
					if (previous=="active" && config.macros.tiddlersBar.nextKey) btn.setAttribute("accessKey",config.macros.tiddlersBar.previousKey);
					previous=btn;
				}
				var isDirty =story.isDirty(title);
				var c = createTiddlyButton(d,isDirty ?"!":"x",isDirty?config.macros.tiddlersBar.tooltipSave:config.macros.tiddlersBar.tooltipClose, isDirty ? config.macros.tiddlersBar.onTabSave : config.macros.tiddlersBar.onTabClose,"tabButton");
				c.setAttribute("tiddler", title);
				if (place.childNodes) {
					place.insertBefore(document.createTextNode(" "),place.firstChild); // to allow break line here when many tiddlers are open
					place.insertBefore(d,place.firstChild); 
				}
				else place.appendChild(d);
			})
	}, 
	refresh: function(place,params){
		removeChildren(place);
		config.macros.tiddlersBar.handler(place,"tiddlersBar",params);
		if (config.macros.tiddlersBar.previousState!=config.macros.tiddlersBar.isShown()) {
			story.refreshAllTiddlers();
			if (config.macros.tiddlersBar.previousState) story.forEachTiddler(function(t,e){e.style.display="";});
			config.macros.tiddlersBar.previousState = !config.macros.tiddlersBar.previousState;
		}
	},
	isShown : function(){
		if (! config.options.chkEnableTabsBar) return false;
		if (!config.options.chkHideTabsBarWhenSingleTab) return true;
		var cpt=0;
		story.forEachTiddler(function(){cpt++});
		return (cpt>1);
	},
	selectNextTab : function(){  //used when the current tab is closed (to select another tab)
		var previous="";
		story.forEachTiddler(function(title){
			if (!config.macros.tiddlersBar.currentTiddler) {
				story.displayTiddler(null,title);
				return;
			}
			if (title==config.macros.tiddlersBar.currentTiddler) {
				if (previous) {
					story.displayTiddler(null,previous);
					return;
				}
				else config.macros.tiddlersBar.currentTiddler=""; 	// so next tab will be selected
			}
			else previous=title;
			});		
	},
	onSelectTab : function(e){
		var t = this.getAttribute("tiddler");
		if (t) story.displayTiddler(null,t);
		return false;
	},
	onTabClose : function(e){
		var t = this.getAttribute("tiddler");
		if (t) {
			if(story.hasChanges(t) && !readOnly) {
				if(!confirm(config.commands.cancelTiddler.warning.format([t])))
				return false;
			}
			story.closeTiddler(t);
		}
		return false;
	},
	onTabSave : function(e) {
		var t = this.getAttribute("tiddler");
		if (!e) e=window.event;
		if (t) config.commands.saveTiddler.handler(e,null,t);
		return false;
	},
	onSelectedTabButtonClick : function(event,src,title) {
		var t = this.getAttribute("tiddler");
		if (!event) event=window.event;
		if (t && config.options.txtSelectedTiddlerTabButton && config.commands[config.options.txtSelectedTiddlerTabButton])
			config.commands[config.options.txtSelectedTiddlerTabButton].handler(event, src, t);
		return false;
	},
	onTiddlersBarAction: function(event) {
		var source = event.target ? event.target.id : event.srcElement.id; // FF uses target and IE uses srcElement;
		if (source=="tiddlersBar") story.displayTiddler(null,'New Tiddler',DEFAULT_EDIT_TEMPLATE,false,null,null);
	},
	createActiveTabButton : function(place,title) {
		if (config.options.txtSelectedTiddlerTabButton && config.commands[config.options.txtSelectedTiddlerTabButton]) {
			var btn = createTiddlyButton(place, title, config.commands[config.options.txtSelectedTiddlerTabButton].tooltip ,config.macros.tiddlersBar.onSelectedTabButtonClick);
			btn.setAttribute("tiddler", title);
		}
		else
			createTiddlyText(place,title);
	}
}

story.coreCloseTiddler = story.coreCloseTiddler? story.coreCloseTiddler : story.closeTiddler;
story.coreDisplayTiddler = story.coreDisplayTiddler ? story.coreDisplayTiddler : story.displayTiddler;

story.closeTiddler = function(title,animate,unused) {
	if (title==config.macros.tiddlersBar.currentTiddler)
		config.macros.tiddlersBar.selectNextTab();
	story.coreCloseTiddler(title,false,unused); //disable animation to get it closed before calling tiddlersBar.refresh
	var e=document.getElementById("tiddlersBar");
	if (e) config.macros.tiddlersBar.refresh(e,null);
}

story.displayTiddler = function(srcElement,tiddler,template,animate,unused,customFields,toggle){
	story.coreDisplayTiddler(config.macros.tiddlersBar.tabsAnimationSource,tiddler,template,animate,unused,customFields,toggle);
	var title = (tiddler instanceof Tiddler)? tiddler.title : tiddler;  
	if (config.macros.tiddlersBar.isShown()) {
		story.forEachTiddler(function(t,e){
			if (t!=title) e.style.display="none";
			else e.style.display="";
		})
		config.macros.tiddlersBar.currentTiddler=title;
	}
	var e=document.getElementById("tiddlersBar");
	if (e) config.macros.tiddlersBar.refresh(e,null);
}

var coreRefreshPageTemplate = coreRefreshPageTemplate ? coreRefreshPageTemplate : refreshPageTemplate;
refreshPageTemplate = function(title) {
	coreRefreshPageTemplate(title);
	/*-- new --*/
	var e = document.getElementById("tiddlersBar");
	if (config.macros.tiddlersBar && e) config.macros.tiddlersBar.refresh(e);

// !!MP!! old prevents a theme, which has no div id=tiddlersBar from loading.
//old	if (config.macros.tiddlersBar && e) config.macros.tiddlersBar.refresh(document.getElementById("tiddlersBar"));
}

// !!MP!! removed this line because it causes a scroll to top if a popup opens.
// ensureVisible=function (e) {return 0}

config.shadowTiddlers.StyleSheetTiddlersBar = "/*{{{*/\n";
config.shadowTiddlers.StyleSheetTiddlersBar += "#tiddlersBar .button {border:0}\n";
config.shadowTiddlers.StyleSheetTiddlersBar += "#tiddlersBar .tab {white-space:nowrap}\n";
config.shadowTiddlers.StyleSheetTiddlersBar += "#tiddlersBar {padding : 1em 0.5em 2px 0.5em}\n";
config.shadowTiddlers.StyleSheetTiddlersBar += ".tabUnselected .tabButton, .tabSelected .tabButton {padding : 0 2px 0 2px; margin: 0 0 0 4px;}\n";
config.shadowTiddlers.StyleSheetTiddlersBar += ".tiddler, .tabContents {border:1px [[ColorPalette::TertiaryPale]] solid;}\n";
config.shadowTiddlers.StyleSheetTiddlersBar +="/*}}}*/";
store.addNotification("StyleSheetTiddlersBar", refreshStyles);

config.refreshers.none = function(){return true;}
config.shadowTiddlers.PageTemplate=config.shadowTiddlers.PageTemplate.replace(/<div id='tiddlerDisplay'><\/div>/m,"<div id='tiddlersBar' refresh='none' ondblclick='config.macros.tiddlersBar.onTiddlersBarAction(event)'></div>\n<div id='tiddlerDisplay'></div>");

//}}}
*2012
** [[Mozambique and South Africa|2012 Mozambique and South Africa]]

----
@@color:#c4d6ed; ^^
Description: Travels page, photos and other things
^^@@
I do develop software for living and even get paid for it ;) .

"//I was to learn later in life that, perhaps because we are so good at organising, we tend as a nation to meet any new situation by reorganising; and a wonderful method it can be for creating the illusion of progress while producing confusion, inefficiency and demoralization.//"
[[Charlton Ogburn|http://en.wikipedia.org/wiki/Charlton_Ogburn,_Jr.]] (1911-1998)

I do not intend to present any new software development methodology. There are already many deserving that title and each one has its own strengths depending on the scenario you want to use it in. But I do want to present a comprehensive view of Software Development that focus on practical performance aspects of the domain.

# [[Software Development Process]] (SDP) - concepts and thoughts about software development as a process.
# [[Software Development Pattern]] - concepts and thoughts about Software Development practices, techniques, tools, methods, etc.
## [[Business Analysis]] - first the problem then the solution.
### [[RFP Analysis Guidelines]]
#### [[Traceability]]
#### [[Data Flow Diagram]]
### [[Technical Proposal Production Guidelines]]
#### [[Software Requirement vs. Feature]]
#### [[Validation]]
#### [[Application Archetype]]
## [[Software Specification]] - ask for things in the right way if you want them to be done well.
### [[Software Requirements Specification Guidelines]]
#### [[Writing Good Requirements]]
#### [[SMART Requirements]]
#### [[Requirement Boilerplate]]
### [[Software Architecture Specification Guidelines]]
## [[Software Construction]]
### [[Software System Documentation]]
## [[Software Maintenance]]
# [[High Maturity Practices]] - software development high maturity practices.
## [[Configuration Management]]
###[[Concurrent Versioning System]]
###[[Reuse oriented CVS]]
## [[Continuous Integration]]
## [[Static Analysis]]
###[[Implementing Static Analysis]]
## [[Unit Testing]]
## [[Peer Review]]
## [[Systematic Reuse]]
## [[Issue Management]]

----
@@color:#c4d6ed; ^^
Description: The main page for software development matters. 
^^@@
/***
|''Name:''|TiddlySpaceIntraSpaceInclusion|
|''Description:''|Provides support for {{{<<tiddler Foo@bar>>}}} and {{{<<tiddler [[Foo]]@bar>>}}}|
|''Author:''|Jon Robson|
|''Source:''|https://github.com/jdlrobson/TiddlyWikiPlugins/raw/master/plugins/TiddlySpaceIntraSpaceInclusion/TiddlySpaceIntraSpaceInclusion.js|
|''Version:''|0.3.8a|
|''License:''|[[BSD License|http://www.opensource.org/licenses/bsd-license.php]] |
|''Comments:''|Please make comments at http://groups.google.co.uk/group/TiddlyWikiDev |
|''~CoreVersion:''|2.4|
***/
//{{{
(function() {
	var _tidtext = TiddlyWiki.prototype.getTiddlerText;
	var cache = {};

	// allmost the same regExp as in TiddlySpaceLinkPlugin but .. no "mg" parameter, because it didn't work for this usecase.
	config.textPrimitives.spacenameLinkRegExp = new RegExp(config.textPrimitives.unWikiLink + 
													 "?(" + config.textPrimitives.bareTiddlerLetter + "*)@(" + config.textPrimitives.spaceName + ")", "");
	config.textPrimitives.tiddlyLinkSpacenameLinkRegExp = new RegExp("\\[\\[(.*?)(?:\\|(.*?))?\\]\\]@(" + config.textPrimitives.spaceName + ")", "");
	
	TiddlyWiki.prototype.getTiddlerText = function(title, defaultText) {
		var ct = config.textPrimitives;
		var match = ct.spacenameLinkRegExp.exec(title);	// foo@bar
		var match2 = ct.tiddlyLinkSpacenameLinkRegExp.exec(title); 	// [[foo]]@bar
		
		if(match || match2) {
		//	console.log('inner: ', 'spacename: ', match, 'tiddlyLink: ', match2, 'place: ');
			var tidtitle, space;
			if(match[1] && match.length === 3) {
				tidtitle = match[1];
				space = match[2];
			} else if(match2 && match2.length === 4) {
				tidtitle = match2[1];
				space = match2[3];
			}
			var newtitle = tidtitle + "@" + space;
			if(tidtitle && space) {
				title = newtitle;
			}
			if(tidtitle && space && !store.getTiddler(newtitle)) {
				var tiddler = new Tiddler(title);
				// get the tiddler, where the macro is rendered. //XXX will need more testing
				var el = story.findContainingTiddler(place);
				var refreshTitle = (el) ? el.getAttribute('tiddler') : null;

				tiddler.text = "//retrieving from server//";
				tiddler.fields.doNotSave = "true";
				tiddler.tags = ["excludeLists", "excludeSearch", "excludeMissing"];
				merge(tiddler.fields, config.defaultCustomFields);
				tiddler.fields["server.bag"] = space + "_public";
				tiddler = store.addTiddler(tiddler);
				ajaxReq({ url: "/bags/" + space + "_public/tiddlers/" + tidtitle,
					dataType: "json",
					success: function(tid) {
						var tiddler = store.getTiddler(title);
						tiddler.text = tid.text;
						store.addTiddler(tiddler);
						// store.notify(title,true);
						story.refreshTiddler(refreshTitle,null,true);
						// story.refreshAllTiddlers(); // hacky but above link doesn't always seem to work!
					},
					error: function() {
						var tiddler = store.getTiddler(title);
						tiddler.text = "//error retrieving tiddler {{{" + title + "}}} from space @" + space + "//";
						store.addTiddler(tiddler);
						// store.notify(title,true);
						story.refreshTiddler(refreshTitle,null,true);
						// story.refreshAllTiddlers(); // hacky but above link doesn't always seem to work!
					}
				});
			}
		}
		return _tidtext.apply(this, [title, defaultText]);
	}
})();
//}}}
!! <html><a name="Architecture" /></html> Architecture
* [[Bredemeyer Consulting - Software Architecture, Architects and Architecting|http://www.bredemeyer.com/]] - This site organizes a variety of resources to help enterprise architects and software architects deepen and expand their understanding of architecture and the role of the architect.
* [[MS The Architecture Journal|http://www.architecturejournal.net]] - Microsoft's Architecture Journal.
* [[The Open Group|http://www.opengroup.org/]] - 

!! <html><a name="BusinessAnalysis" /></html> Business Analysis
* [[A Guide to the Business Analysis Body of Knowledge® (BABOK® Guide)|http://www.iiba.org/imis15/IIBA/Professional_Development/Business_Analysis_Body_of_Knowledge/IIBA_Website/Professional_Development/Business_Analysis_Body_of_Knowledge_pages/Business_Analysis_Body_of_Knowledge.aspx?hkey=d0891e0a-996a-431f-a6f5-a7d644e23a5c]] - is the collection of knowledge within the profession of business analysis and reflects current generally accepted practices. As with other professions, the body of knowledge is defined and enhanced by the business analysis professionals who apply it in their daily work role. 

!! <html><a name="OOP" /></html> OOP (Object Oriented Programming)
* [[JOT|http://www.jot.fm]] - Journal of Object Technology (JOT) is an on-line peer-reviewed publication, published six times per year by the ETH Swiss Federal Institute of Technology, aimed at intermediate to advanced practitioners, educators and researchers in the field of object technology.
* [[Object Mentor|http://www.objectmentor.com/index.html]] - Founded in 1991 by Robert C. Martin, Object Mentor is a team of highly experienced software professionals specializing in object-oriented technologies and [[Agile|Agile Methodologies]]/XP development methodologies. 

!! <html><a name="Reuse" /></html> Reuse
* [[Art of Software Reuse|http://artofsoftwarereuse.com/]] - by Vijay Narayanan, a site dedicated to developers, designers, and architects aspiring to create better software.

----
@@Please do not modify this tiddler; it was created automatically upon space creation.@@
A collection of practical development guidelines.

|Guideline|h
|<<list filter [tag[Guideline]]>>|
----
@@color:#c4d6ed; ^^
Description: A collection of practical development guidelines.
^^@@
* http://tiddlyspace.com/search?q=tag:@acarvalho
* http://acarvalho.tiddlyspace.com/activity

<<activity show:reply show:notify>>

!!acarvalho
<<tsScan url:"/search?q=tag:@acarvalho _limit:100" template:"SearchTemplate" sort:-modified>>
!!pmario
<<tsScan url:"/search?q=tag:@pmario _limit:5" template:"SearchTemplate" sort:-modified>>
/***
|''Name''|TiddlySpaceFollowingSuggestions|
|''Version''|0.2.5dev|
|''Description''|Provides a following macro|
|''Author''|Jon Robson|
|''Requires''|TiddlySpaceFollowingPlugin|
|''License''|[[BSD|http://www.opensource.org/licenses/bsd-license.php]]|
!Usage

!Code
***/
//{{{
(function($) {

var tweb = config.extensions.tiddlyweb;
var tiddlyspace = config.extensions.tiddlyspace;
var followMacro = config.macros.followTiddlers;

var followSuggestions = config.macros.followSuggestions = {
	cache: {},
	handler: function(place, macroName, params) {
		// to do - limit results
		place = $('<div class="suggestions" />').appendTo(place)[0];
		var currentSpace = tiddlyspace.currentSpace.name;
		var user = params[0] || currentSpace;
		var pleaseWait = $("<div class='loading' />").text("please wait..").appendTo(place);
		tweb.getUserInfo(function(activeUser) {
			if(activeUser.name != tiddlyspace.currentSpace.name) {
				pleaseWait.hide();
				return;
			}
			followMacro.getFollowers(function(users) {
				// suggestions are followers of people that you follow that you don't follow
				var bags = followMacro._getFollowerBags(users);
				var _bags = [];
				for(var i = 0; i < bags.length; i++) {
					_bags.push("bag:%0".format([bags[i]]));
				}
				var bagString = _bags.join(" OR ");
				ajaxReq({
					beforeSend: followMacro.beforeSend,
					url: "/search?q=(%0)&select=title:!%1&select=title:!@%1".format([bagString, activeUser.name]),
					dataType: "json",
					success: function(tiddlers) {
						pleaseWait.hide();
						var suggestions = [];
						for(var i = 0; i < tiddlers.length; i++) {
							var tiddler = tiddlers[i];
							if(tiddler.tags.contains("follow")) {
								var title = tiddler.title;
								if(title.indexOf("@") === 0) {
									title = title.substr(1);
								}
								if(!users.contains(title)) {
									suggestions.pushUnique(title);
								}
							}
						}
						$(place).append("<div>suggestions:</div>");
						var suggestionArea = $("<div class='suggestionArea' />").appendTo(place)[0];
						var id = "more_%0".format([Math.random()]);
						var more = $("<div class='moreButton' />").text("more...").appendTo(place).attr("id", id);
						followSuggestions.cache[id] = suggestions;
						var limit = suggestions.length;
						more.click(function(ev) {
							var suggestions = config.macros.followSuggestions.cache[id];
							var newSuggestions = followSuggestions.suggest(place, suggestions, limit);
							config.macros.followSuggestions.cache[id] = newSuggestions;
						});
						followSuggestions.suggest(place, suggestions, limit);
					
					}
				});
			
			}, user);
		});
	},
	randomize: function(a, b) {
		if(Math.random() < Math.random()) {
			return -1;
		} else {
			return 1;
		}
	},
	suggest: function(place, suggestions, limit) {
		var currentSpace = tiddlyspace.currentSpace.name;
		suggestions = suggestions.sort(followSuggestions.randomize);
		var suggestionsArea = $(".suggestionArea", place)[0];
		if(suggestions.length === 0) {
			$("<span />").text("no suggestions..").appendTo(suggestionsArea);
			return;
		}
		limit = limit < suggestions.length ? limit : suggestions.length;
		for(var j = 0; j < limit; j++) {
			var link = $("<span />").appendTo(suggestionsArea)[0];
			var title = suggestions[j];
			var newTiddler = '@%0 <<newTiddler title:"@%0" fields:"server.workspace:bags/%1_public" tag:follow label:"follow">>\n'.format([title, currentSpace]);
			wikify(newTiddler, link);
		}
		var newSuggestions = suggestions.slice(limit, suggestions.length);
		var more = $(".moreButton", place);
		if(newSuggestions.length == 0) {
			more.remove();
		}
		return newSuggestions;
	}
};
})(jQuery);
//}}}
"//''Adding manpower to a late software project makes it later.''//"

[[The mythical man-month - essays on software engineering, 1975|http://ultra.pr.erau.edu/~jaffem/classes/se300/Supplemental%20materials/The_Mythical_Man-Month_Essays_on_Software_Engineering_Anniversary_Edition.pdf]]
[[Frederick P. Brooks|http://en.wikipedia.org/wiki/Fred_Brooks]]
page 25

----
/%
@@color:#c4d6ed; ^^
Description: Quote of Frederick P. Brooks Brook's Law
^^@@
%/
''You do not became an Agile Developer just by not doing things! You became an Agile Developer by (through study, experience and reasoning) being able to define and [[tailor|Tailoring]] processes and methods to achieve the goals with the minimum effort possible.''

Agility in software development was a good trend to clarify over engineering and too formal and rather useless practices that were being blindly imported from high maturity and criticality scenarios to other situations were they were little more than an useless overhead. Worst, as many of the practitioners did not knew how to perform those practices, they slowly degenerated in "pretend-to-be" activities that consumed resources without producing anything useful.

//''"A programmer who refuses to design is a person who refuses to think."''//
''Practices of an Agile Developer'' by Venkat Subramaniam and Andy Hunt, pag. 153 <<BibRef "Venkat 2006">>

Unfortunately, many times today, agility is used as an excuse for ignorance, immaturity and irresponsibility. Oddly, I became aware that some universities use agile methodologies to teach Software Engineering to people that does not know anything about Object Oriented Principles or software modelling or structured analysis, and that think they, alone by themselves, can "infer" all the Software Engineering knowledge ever produced just by knowing the syntax of a programming language and how to use Google. This will only produce, as we say in Portuguese, "meat for the cannons", low value programmers with very serious handicaps for evolving, but cheap and easy to replace...
Think of a would be painter that wants to start his learning by abstract art, it does not make much sense does it?

Beware of agility without solid knowledge and experience as it will be, most of the times, simplistic. Also start by considering that ''if you do not have an agile specification and an agile architecture you will, for sure, not have an agile development but just a sloppy one''.

This being said, agile methodologies are a great contribution to Software Engineering. To know more about them you may want to start with the [[Manifesto for Agile Software Development|http://agilemanifesto.org/]] and then probably head for [[Martin Fowler|http://martinfowler.com/intro.html]]'s [[Agile Software Development|http://martinfowler.com/agile.html]].

----
/%
@@color:#c4d6ed; ^^
Description: Agile Methodologies concept, discussion and references.
^^@@
%/
* [[tiddlyspace.com|http://tiddlyspace.com/]]

!![[TiddlySpace collaboration]] : some ideas and links about active collaboration and ideas exchange using TiddlySpace

!!Documentation
* [[Glossary|http://glossary.tiddlyspace.com/]] - terminology used by ~TiddlySpace 
* [[TiddlyWeb Documentation|http://tiddlyweb.peermore.com/wiki/]] - ~TiddlyWeb, the engine behind ~TiddlySpace
* [[MacroDocumentation|http://macros.tiddlyspace.com/]] - This space provides documentation for the core macros used in ~TiddlySpace.
** [[Core Macros]]@tiddlywiki - 
* [[formatting|http://formatting.tiddlyspace.com/]] - your quick reference for TiddlyWiki markup rules
* [[tiddlywiki|http://tiddlywiki.org/]] - This is the new TiddlySpace based community wiki for TiddlyWiki powered by the community.

!!Spaces
* [[Simplicity using TiddlySpace|http://simplicity.tiddlyspace.com/]] - an easy to use space by PMario.
* [[tiddlyspace|http://tiddlyspace.tiddlyspace.com]] - This is a ~TiddlySpace to talk about ~TiddlySpace, in particular to collect Stories for the development of ~TiddlySpace. Established ~TiddlySpace terms and concepts are defined in the [[Glossary|http://glossary.tiddlyspace.com/]] space.
* [[htmljs|http://htmljs.tiddlyspace.com]] - This is a space which allows you to pimp your HTML Serialization in ~TiddlySpace.
!!Verify
* [[http://tiddlyguv.org/CommentsPlugin.html#CommentsPlugin|http://tiddlyguv.org/CommentsPlugin.html#CommentsPlugin]]
* [[[tw] tiddlyspace comments? - msg#00594|http://osdir.com/ml/tiddlywiki/2010-10/msg00611.html]]

* [[TiddlyWeb Commander|http://commander.tiddlyspace.com/tiddlywebcommander#host:http://acarvalho.tiddlyspace.com]]

----
See also [[TiddlySpace Wish List|TiddlySpace WishList]]
----
|Quotes|h
|<<list filter [tag[Quote]]>>|
----
/%
@@color:#c4d6ed; ^^
Description: A collection of important quotes from important people
^^@@
%/
|Last 30 tiddlers created|Last 30 tiddlers modified|h
|<<ContentTimeline created 30>>|<<ContentTimeline modified 30>>|
----
@@color:#c4d6ed; ^^
Description: Shows the last updates in this wiki. 
^^@@
"//''For every complex problem, there is a solution that is simple, neat, and wrong.''//"
[[Henry Louis Mencken|http://en.wikipedia.org/wiki/H._L._Mencken]] (1880 - 1956)
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
Reuse by copy opposes to __reuse by reference__ and is one of the main obstacles to [[Systematic Reuse]] and [[Continuous Improvement]]. Reuse by reference applies to code reuse primarily but keep in mind that [[Systematic Reuse]] is not only, nor even primarily, code reuse.

Reuse by copy happens when, on reusing a module, you just copy it from its original repository and put the copy on the filesystem of the project that reuses it. On __reuse by reference__ you check out the reusable module to the filesystem of the reusing project but, on the [[CVS]] repository, the module is the same. Of course you shall relay your dependency on a [[CVS Tag]]. The benefit of doing so is evident : ''all enhancements and improvements may be easily shared among all projects that reuse the module'' along time. When you copy you hide from all other projects and [[Systematic Reuse]] is impaired.

In a very interesting post about [[5 Tips to Co-Create Reusable Components|http://artofsoftwarereuse.com/2013/02/17/5-tips-to-co-create-reusable-components/]] Vijay Narayanan states :
"//Share the source code of all your reusable components so every developer in the team can see under the hood how the component works and how it can be improved//"
----
See also : [[Promoting Reuse by Reference]]
----
@@color:#c4d6ed; ^^
Description: Reuse by Reference vs. Reuse by Copy  concept explanation.
^^@@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xl="http://www.w3.org/1999/xlink" version="1.1" viewBox="72 648 70 70" 
width="30" height="30">
<g stroke="none" stroke-opacity="1" stroke-dasharray="none" fill="none" fill-opacity="1">
	<g>
		<path d="M 77.59005 669.34003 C 71.532745 681.90424 73.714462 697.4441 84.135193 707.86475 
		C 97.315445 721.0451 118.684715 721.0451 131.8649 707.86475 
		C 145.04515 694.68457 145.04515 673.31537 131.8649 660.13513 
		C 121.4441 649.7141 105.90419 647.53253 93.339905 653.5899 L 102.047455 662.2976 
		C 109.58637 660.2373 117.987976 662.16803 123.90997 668.08997 
		C 132.69673 676.8767 132.69673 691.12317 123.90997 699.90985 
		C 115.12313 708.6966 100.87699 708.6966 92.09012 699.90985 
		C 86.168266 693.98804 84.23744 685.58643 86.297653 678.04755 Z M 72 648 L 72 668.25 L 78.75 661.49957 
		L 99.00019 681.7502 L 105.750175 675.00006 L 85.50013 654.75012 L 92.249985 648 Z" fill="black"
		class="glyph"/>
	</g>
</g>
</svg>
/***
|Name|GotoPlugin|
|Source|http://www.TiddlyTools.com/#GotoPlugin|
|Documentation|http://www.TiddlyTools.com/#GotoPluginInfo|
|Version|1.9.2|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|view any tiddler by entering it's title - displays list of possible matches|
''View a tiddler by typing its title and pressing //enter//.''  As you type, a list of possible matches is displayed.  You can scroll-and-click (or use arrows+enter) to select/view a tiddler, or press escape to close the listbox to resume typing.  When the listbox is not displayed, pressing //escape// clears the current input.
!!!Documentation
>see [[GotoPluginInfo]]
!!!Configuration
<<<
*Match titles only after {{twochar{<<option txtIncrementalSearchMin>>}}} or more characters are entered.<br>Use down-arrow to start matching with shorter input.  //Note: This option value is also set/used by [[SearchOptionsPlugin]]//.
*To set the maximum height of the listbox, you can create a tiddler tagged with <<tag systemConfig>>, containing:
//{{{
config.macros.gotoTiddler.listMaxSize=10;  // change this number
//}}}
<<<
!!!Revisions
<<<
2009.05.22 [1.9.2] use reverseLookup() for IncludePlugin
|please see [[GotoPluginInfo]] for additional revision details|
2006.05.05 [0.0.0] started
<<<
!!!Code
***/
//{{{
version.extensions.GotoPlugin= {major: 1, minor: 9, revision: 2, date: new Date(2009,5,22)};

// automatically tweak shadow SideBarOptions to add <<gotoTiddler>> macro above <<search>>
config.shadowTiddlers.SideBarOptions=config.shadowTiddlers.SideBarOptions.replace(/<<search>>/,"{{button{goto}}}\n<<gotoTiddler>><<search>>");

if (config.options.txtIncrementalSearchMin===undefined) config.options.txtIncrementalSearchMin=3;

config.macros.gotoTiddler= { 
	listMaxSize: 10,
	listHeading: 'Found %0 matching title%1...',
	searchItem: "Search for '%0'...",
	handler:
	function(place,macroName,params,wikifier,paramString,tiddler) {
		var quiet	=params.contains("quiet");
		var showlist	=params.contains("showlist");
		var search	=params.contains("search");
		params = paramString.parseParams("anon",null,true,false,false);
		var instyle	=getParam(params,"inputstyle","");
		var liststyle	=getParam(params,"liststyle","");
		var filter	=getParam(params,"filter","");
		var html=this.html;
		var keyevent=window.event?"onkeydown":"onkeypress"; // IE event fixup for ESC handling
		html=html.replace(/%keyevent%/g,keyevent);
		html=html.replace(/%search%/g,search);
		html=html.replace(/%quiet%/g,quiet);
		html=html.replace(/%showlist%/g,showlist);
		html=html.replace(/%display%/g,showlist?'block':'none');
		html=html.replace(/%position%/g,showlist?'static':'absolute');
		html=html.replace(/%instyle%/g,instyle);
		html=html.replace(/%liststyle%/g,liststyle);
		html=html.replace(/%filter%/g,filter);
		if (config.browser.isIE) html=this.IEtableFixup.format([html]);
		var span=createTiddlyElement(place,'span');
		span.innerHTML=html; var form=span.getElementsByTagName("form")[0];
		if (showlist) this.fillList(form.list,'',filter,search,0);
	},
	html:
	'<form onsubmit="return false" style="display:inline;margin:0;padding:0">\
		<input name=gotoTiddler type=text autocomplete="off" accesskey="G" style="%instyle%"\
			title="Enter title text... ENTER=goto, SHIFT-ENTER=search for text, DOWN=select from list"\
			onfocus="this.select(); this.setAttribute(\'accesskey\',\'G\');"\
			%keyevent%="return config.macros.gotoTiddler.inputEscKeyHandler(event,this,this.form.list,%search%,%showlist%);"\
			onkeyup="return config.macros.gotoTiddler.inputKeyHandler(event,this,%quiet%,%search%,%showlist%);">\
		<select name=list style="display:%display%;position:%position%;%liststyle%"\
			onchange="if (!this.selectedIndex) this.selectedIndex=1;"\
			onblur="this.style.display=%showlist%?\'block\':\'none\';"\
			%keyevent%="return config.macros.gotoTiddler.selectKeyHandler(event,this,this.form.gotoTiddler,%showlist%);"\
			onclick="return config.macros.gotoTiddler.processItem(this.value,this.form.gotoTiddler,this,%showlist%);">\
		</select><input name="filter" type="hidden" value="%filter%">\
	</form>',
	IEtableFixup:
	"<table style='width:100%;display:inline;padding:0;margin:0;border:0;'>\
		<tr style='padding:0;margin:0;border:0;'><td style='padding:0;margin:0;border:0;'>\
		%0</td></tr></table>",
	getItems:
	function(list,val,filter) {
		if (!list.cache || !list.cache.length || val.length<=config.options.txtIncrementalSearchMin) {
			// starting new search, fetch and cache list of tiddlers/shadows/tags
			list.cache=new Array();
			if (filter.length) {
				var fn=store.getMatchingTiddlers||store.getTaggedTiddlers;
				var tiddlers=store.sortTiddlers(fn.apply(store,[filter]),'title');
			} else 
				var tiddlers=store.reverseLookup('tags','excludeLists');
			for(var t=0; t<tiddlers.length; t++) list.cache.push(tiddlers[t].title);
			if (!filter.length) {
				for (var t in config.shadowTiddlers) list.cache.pushUnique(t);
				var tags=store.getTags();
				for(var t=0; t<tags.length; t++) list.cache.pushUnique(tags[t][0]);
			}
		}
		var found = [];
		var match=val.toLowerCase();
		for(var i=0; i<list.cache.length; i++)
			if (list.cache[i].toLowerCase().indexOf(match)!=-1) found.push(list.cache[i]);
		return found;
	},
	getItemSuffix:
	function(t) {
		if (store.tiddlerExists(t)) return "";  // tiddler
		if (store.isShadowTiddler(t)) return " (shadow)"; // shadow
		return " (tag)"; // tag 
	},
	fillList:
	function(list,val,filter,search,key) {
		if (list.style.display=="none") return; // not visible... do nothing!
		var indent='\xa0\xa0\xa0';
		var found = this.getItems(list,val,filter); // find matching items...
		found.sort(); // alpha by title
		while (list.length > 0) list.options[0]=null; // clear list
		var hdr=this.listHeading.format([found.length,found.length==1?"":"s"]);
		list.options[0]=new Option(hdr,"",false,false);
		for (var t=0; t<found.length; t++) list.options[list.length]=
			new Option(indent+found[t]+this.getItemSuffix(found[t]),found[t],false,false);
		if (search)
			list.options[list.length]=new Option(this.searchItem.format([val]),"*",false,false);
		list.size=(list.length<this.listMaxSize?list.length:this.listMaxSize); // resize list...
		list.selectedIndex=key==38?list.length-1:key==40?1:0;
	},
	keyProcessed:
	function(ev) { // utility function
		ev.cancelBubble=true; // IE4+
		try{event.keyCode=0;}catch(e){}; // IE5
		if (window.event) ev.returnValue=false; // IE6
		if (ev.preventDefault) ev.preventDefault(); // moz/opera/konqueror
		if (ev.stopPropagation) ev.stopPropagation(); // all
		return false;
	},
	inputEscKeyHandler:
	function(event,here,list,search,showlist) {
		if (event.keyCode==27) {
			if (showlist) { // clear input, reset list
				here.value=here.defaultValue;
				this.fillList(list,'',here.form.filter.value,search,0);
			}
			else if (list.style.display=="none") // clear input
				here.value=here.defaultValue;
			else list.style.display="none"; // hide list
			return this.keyProcessed(event);
		}
		return true; // key bubbles up
	},
	inputKeyHandler:
	function(event,here,quiet,search,showlist) {
		var key=event.keyCode;
		var list=here.form.list;
		var filter=here.form.filter;
		// non-printing chars bubble up, except for a few:
		if (key<48) switch(key) {
			// backspace=8, enter=13, space=32, up=38, down=40, delete=46
			case 8: case 13: case 32: case 38: case 40: case 46: break; default: return true;
		}
		// blank input... if down/enter... fall through (list all)... else, and hide or reset list
		if (!here.value.length && !(key==40 || key==13)) {
			if (showlist) this.fillList(here.form.list,'',here.form.filter.value,search,0);
			else list.style.display="none";
			return this.keyProcessed(event);
		}
		// hide list if quiet, or below input minimum (and not showlist)
		list.style.display=(!showlist&&(quiet||here.value.length<config.options.txtIncrementalSearchMin))?'none':'block';
		// non-blank input... enter=show/create tiddler, SHIFT-enter=search for text
		if (key==13 && here.value.length) return this.processItem(event.shiftKey?'*':here.value,here,list,showlist);
		// up or down key, or enter with blank input... shows and moves to list...
		if (key==38 || key==40 || key==13) { list.style.display="block"; list.focus(); }
		this.fillList(list,here.value,filter.value,search,key);
		return true; // key bubbles up
	},
	selectKeyHandler:
	function(event,list,editfield,showlist) {
		if (event.keyCode==27) // escape... hide list, move to edit field
			{ editfield.focus(); list.style.display=showlist?'block':'none'; return this.keyProcessed(event); }
		if (event.keyCode==13 && list.value.length) // enter... view selected item
			{ this.processItem(list.value,editfield,list,showlist); return this.keyProcessed(event); }
		return true; // key bubbles up
	},
	processItem:
	function(title,here,list,showlist) {
		if (!title.length) return;
		list.style.display=showlist?'block':'none';
		if (title=="*")	{ story.search(here.value); return false; } // do full-text search
		if (!showlist) here.value=title;
		story.displayTiddler(null,title); // show selected tiddler
		return false;
	}
}
//}}}
<<view image image width:12 height:12>><<view title text>>
!Introduction
After you performed [[RFP Analysis|RFP Analysis Guidelines]] you are ready to start building your Technical Proposal to use it as the basis for estimations and, as such, the basis for the Financial Proposal but also as a clear demonstration of capability able to persuade the Customer that you are the best technical choice to carry on his project.

{{tw_ttoc{}}}

!Technical Proposal Structure
The Technical Proposal is your contractual proposal to the Customer. It shall clearly close the scope of work and present your view of it to be validated by the Customer.
It is this view that determines effort estimation and cost proposed to the Customer and, as such, every effort shall be put on achieving a clear and closed scope to be used as a contractual reference.

The Technical Proposal may, and shall, refer the [[RFP]] if it is a formal one or may produce information that is supposed to came from [[RFP]] if it is an informal one.

Take notice that Proposal shall establish the structure and scope for Requirements gathering and, as such, it shall be as complete and detailed as possible.

At the Proposal closure the information items referred in [[RFP]] and Proposal shall be acquired no matter if from  [[RFP]] or built in the Proposal. This is a very important aspect of safe and realistic proposals.
!!Glossary
<<Image "FR" "" "Technical-Proposal-Structure.PNG" "https://dl.dropbox.com/" "s/1ao4mpykaidyynt/" "?dl=1" "Technical Proposal Structure">> Never underestimate the importance of communication. Remember that each knowledge area has its own vocabulary, your Customer's included, and that a common vocabulary is essential to communicate any ideas. To establish a Glossary that you keep, validate and enhance shall be one of your priorities. [[EA|Sparx Enterprise Architect]] provides a good mechanism to produce a glossary and, of course, you shall reuse it in other projects with the Customer or even on the domain. Start it on the first day.

!!Problem and Solution Statement
This is an introductory section that shall give an overview of the problem and provide a context for the following sections. It shall reuse (structuring, extending and enhancing) the correspondent section on the RFP.
*EA usage: 
**Packages as  typographical elements of a document. Illustrative diagrams may be used if necessary. 
*Internal section goals: 
**This section shall present an introduction to the problem and its context. It shall also present a broad scope definition for the proposal. This shall be Customer view as we understand it.
*External section goals: 
**This section shall be able to provide the Customer with the means to validate our conceptual understanding of his problem.

!!Solution Processes
This is the Proposal counterpart to RFP Business Processes section.
At this level we shall describe all business processes that the solution will support or contribute to. This is the system view of the business processes.
*EA usage: 
**The Solution Processes diagram is Activity and the most relevant elements are Partition, Activities and Decision.
**Primary Relationship is Control Flow to convey sequence. The partitions shall reflect the relevant actors be them Customer organizational units or existing or to be developed systems. For each activity the role of the solution shall be stated. Solution Processes shall be structured in packages and the package shall contain a contextual introduction to the diagram. The diagram itself shall contain a textual description of the process.
* [[Traceability]] : 
**Partitions shall trace to Roles.
*Internal section goals: 
**This section shall present an overview of the system/solution processes and a description of the activities proposed. This is a major scope definition item as any externally observable solution feature must be present here.
*External section goals: 
**Validate business view and understanding and solution coverage of business needs.
!!Roles
This section shall describe all Roles that are relevant for the solution.
This information may came from the RFP or be constructed by a joint effort between Tendering and Technical Proposal Team. If necessary and possible it shall also involve Customer.
*EA usage: 
**Diagram is Use Case. Role element is Actor. Actors may be related by Generalization/Specialization relationships. Actor description shall include a description of the role and solution interaction.
* [[Traceability]] : 
**Roles shall be traced to RFP Stakeholders.
*Internal section goals: 
**The Roles section provides a definitive list of Human interaction with the system. It may also represent other automated systems that play a role in the solution. This is an important information for instance to determine the different, Authorization based, interfaces the system must allow.
**This is also an important scope item as it provides a definitive list of foreseen interactions with the system.
!!Use Cases
This section shall describe all the Use Cases derived from Roles and Solution Processes interaction.
*EA usage: 
**The Use Cases diagram is Use Case and the elements are Actor (from Roles) and Use Case. Use Cases shall be structured in packages the top package shall state the structuring criteria. Each package shall state its scope with a short description. Each Use Case may be detailed by filling its Scenarios in Basic or Alternate paths. Actors relate with Use Cases through Use relationship. Use Cases relate with each other through Include and Extends relationships. The Use Case elements may be hierarchically numbered with, at least, two levels (xx.xxx). It is advisable to use factor 10 increments.
* [[Traceability]] : 
**Actors must be those in Roles. Use Cases may/shall be linked with Solution Processes' Activities as a way to detail them from an user interaction perspective.
*Internal section goals: 
**When possible register User interaction foreseen by the Customer or envisioned by the proposal team. Validate completeness and adequacy. 
**Help in defining proposal scope. The scope contribution is not definitive as Use Cases are used to detail User Interaction with the system when needed so its catalogue is not exhaustive, however if an Use Case exists it is a positive scope item that must be honoured.
*External section goals: 
**Allow Customer to validate adequacy of the perceived GUI needs.
See also : [[Use Case Diagram]]
!!Solution Integration and Deployment
*Description:
**This section shall describe the integration environment of the solution, namely, describing and specifying external interfaces and protocols used for our system integration with existing or foreseen external systems.
*EA usage:
**The Solution Integration diagram is Deployment and the elements are mainly Node, Execution Environment, Component and Interface.
**Components shall be reused from Technical Solution.
* [[Traceability]] : 
*Scope:
**The intended audience scope for the section is PUBLISHED.
*Internal section goals:
**This section is intended to define the integration needs of the solution by identifying all external systems and correspondent Interfaces and Protocols. This section shall also present a preliminary deployment environment specification for our system.
*External section goals:
**Validation of completeness of external systems list and identification of interfaces and protocols. 
*When in doubt:
** Build assumptions.
*Notes:
*References:
!!Proposed Features
Proposed [[Feature]]s are your response to customer's Requested Features. They will be the main content of your Technical Proposal and the main content of your customer analysis on the suitability and advantages of your proposed solution.
*Description:
**This section shall present the complete list of Proposed Features for the solution. These are our response to the Requested Features from Customer and constitute our proposed agreement terms and solution scope.
*EA usage:
**The Proposed Features diagram is Requirements and the element is Feature.
**The Proposed Feature elements have FT- prefix.
**The Proposed Feature elements are hierarchically numbered with, at least, two levels (xx.xxx). It is advisable to use factor 10 increments.
* [[Traceability]] : 
**Proposed Features shall trace (Abstraction) to Requested Features on RFP. Proposed Features shall be traced (Abstraction) from Software Requirements. Proposed Features may dependency trace to Issues and Assumptions and be associated to Ideas and Changes.
*Scope:
**The intended audience scope for the section is PUBLISHED.
*Internal section goals:
**This section shall contain the complete list of proposed Features and Assumptions in response to the RFP and, thus, be seen as the complete and primary scope definition for the Proposal.
*External section goals:
**This section shall allow Customer validation of completeness and adequacy of our proposal and serve as the complete agreement on project's scope.
*When in doubt:
**Any pending Issue at this stage shall be solved by an Assumption.
*Notes:
*References:
!!Technical Solution
On a Proposal the technical solution is, of course, preliminary. Nevertheless your Customer expects that you are able to convince him that you do have a solid technical solution and are able to execute it. He also wants, for sure, to access the compatibility and fitness of your proposed solution in his environment and evolution roadmap. Finally your Customer wants to be reassured that you understood the full scope and complexity of the problem and are taking that into account on your financial proposal and not just "tossing up a nice round number" over a simplistic view.
!!!Major Challenges
Identifying major technical challenges of the project is essential for estimation, know-how gathering and team assembling. Clearly stating them will also assure your Customer that you are a mature software developer that understood the problem and its solution and that your Proposal is solid, serious and proper for the task at hands. It is also a major asset when you have to "discuss the cost".
*Description:
**This section shall describe the major technical challenges rose by the project and propose approaches for each one.
*EA usage:
**This is a textual section.
**Correspondent Features, Components, etc. shall have their <<quote 'Difficulty attribute' 'EA Usage - Attribute Difficulty' >> set to High.
*Scope:
**The intended audience scope for the section is PUBLIC or PUBLISHED depending on the confidence of the analysis.
*Internal section goals:
**Internally this section must convey the assurance that all major technical challenges were considered. If a challenge has no immediate solution approach then Risks shall be created and Assumptions made.
**Technical challenges may also be rise from business challenges.
**This is an important factor in estimation accuracy. This is also important in defining know-how required and V&V potential main targets.
*External section goals:
**This section shall increase Customer confidence in a proper understanding and prioritisation of the solution challenges.
*When in doubt:
**Seek for Expert advise. Rise Risks and build Assumptions.
!!!Architectural Archetype
The <<quote 'Architectural Archetype' 'Application Archetype'>> is the spine of your solution's architecture. It is the first vision of it and will greatly determine all your other architectural choices, and, by the way, possibilities.
A known and well thought archetype will inspire confidence and provide a very good fitness [[validation|Validation]] element.
*Description:
**This section intends to convey the architectural, or, better, the meta-architectural archetype, in which the proposed technical solution will fit.
*EA usage:
**The Archetype diagram is CompositeStructure and the stack element is Part. You may use Boundary to separate tiers.
**The relationship is Connector from consumer to provider.
**This is a common Stacked Diagram as it is generally used in protocol illustration. Layers shall be vertically stacked inside tiers. Communication between tiers is important and also transversal concerns.
*Scope:
**The intended audience scope for the section is PUBLISHED.
*Internal section goals:
**The most important goal here is to establish an architectural basis, an archetype, from which solutions may be inferred in terms of commonly used patterns in the approach. 
**Non-conventional parts of the proposed solution must be explicitly detailed as such. **Example : the solution uses a proprietary Authentication schema. The "standard" solution parts need not to be much detailed and may be just referred.
**This diagram is invaluable in accessing reuse candidates.
*External section goals:
**It must allow the Customer to identify as known the architectural basis of our architecture. The Customer shall also validate that the proposed meta-architecture fits in his existent/envisioned environment.
**This top folder shall contain a brief justification of the choice as well as a demonstration that it fits in Customer's existing systems/architecture. If it is a new/isolated system then the justification shall be more elaborated in order to be perceived as proper for future development and expansion (maturity, long term support forecast, adopters importance, etc. are important factors to consider and to show to the Customer that they were considered).
*When in doubt:
**Produce clear assumptions regarding suitability of the archetype and its used patterns.
*References:
>Microsoft Application Architecture Guide (2nd Edition)
>[[Application Archetypes|http://msdn.microsoft.com/en-us/library/ee658107%28v=PandP.10%29.aspx]]
!!!Development Environment
*Description:
**This section shall state the technologies to be used in the proposed project.
**In most of the cases this section shall be a direct reuse of the standard list of environments. A standard environment comprises IDE, language, Database, Third-parties, Frameworks, Tools, etc.
*EA usage:
**For now this shall be a textual description of the environment.
*Scope:
**The intended audience scope for the section is PUBLISHED.
*Internal section goals:
**The most important goal here is to establish an architectural environment that directs know-how gathering, team selection and costs forecast. 
*External section goals:
**It must allow the Customer to identify as known the technological basis of proposed architecture. 
**This top folder shall contain a brief justification of the choice as well as a demonstration that it fits in Customer's existing technologies. If it is a new/isolated system then the justification shall be more elaborated in order to be perceived as proper for future development and expansion (maturity, long term support forecast, adopters importance, etc. are important factors to consider and to show to the Customer that they were considered).
*When in doubt:
**Produce clear assumptions regarding suitability of the Development Environment.
*References:
!!!Preliminary Component Model
*Description:
**This section shall provide a preliminary component model decomposition of the system that is primary oriented to support estimation and reuse analysis.
**Attention shall be centred on Major Challenges and the strategies envisioned to deal with them. Also the modularization shall reflect the architectural archetype chosen.
*EA usage:
**The Preliminary Component Model (PCM) diagram is Component and the PCM main elements are Component and Interface.
**Decomposition shall progress from overview model to more detailed ones. Detail shall be the one that is enough to produce an effort estimation within the risk level accepted for the Proposal and without taking unnecessary compromise with specific solution designs.
* [[Traceability]] : 
** Components shall Realize Software Requirements that, in this way, become their responsibilities. Components also Realize Interfaces and Aggregate Classes.
** Notice that this is a ''preliminary'' component model here at Proposal. It may be fully replaced by a Software Architecture Specification later.
*Scope:
**The intended audience scope for the section is PUBLISHED. Not all detail levels, however, may appear in final Proposal document as we must consider the level of Architectural compromise we want or are able to support at this phase.
*Internal section goals:
**Perform a first modular view of the system able to support estimation of effort, reuse analysis including third-parties, necessary know-how definition and challenge consideration demonstration and overcame strategy existence.
*External section goals:
**Perform a first modular view of the system that Customer's technical personal may validate.
**Generate confidence in our ability to deal with changes and achieve a good solution.
*When in doubt:
**Produce Assumptions. Identify Risks.
*Notes:
*References:
!!Assumptions
*Description:
**This section shall present the complete list of Assumption established for pending Issues, doubts or disambiguation.
*EA usage:
**The Assumption diagram is Custom and the element is Issue.
**The Assumption elements have AS- prefix.
**The Assumption elements are hierarchically numbered with, at least, two levels (xx.xxx). It is advisable to use factor 10 increments.
* [[Traceability]] : 
**Assumptions shall dependency trace from any element they are related to.
*Scope:
**The intended audience scope for the section is PUBLISHED.
*Internal section goals:
**This section shall establish a closed scope for proposal even when issues and doubts are still present.
*External section goals:
**This section shall allow Customer validation of our assumptions and serve as a complete closure on project's scope.
*When in doubt:
**This is mandatory.
*Notes:
*References:

----
Back to [[Business Analysis]]
----
<<TiddlerToC min-entries:1>>
/%
@@color:#c4d6ed; ^^
Description: Guidelines for Technical Proposal Production
^^@@
%/
/***
http://trac.tiddlywiki.org/ticket/637 - CLOSED: WON'T FIX
This tweak modifies the tooltip format that appears when you mouseover a link to a tiddler.  It adds an option to control the date format, as well as displaying the size of the tiddler (in bytes)

Tiddler link tooltip format:
{{stretch{<<option txtTiddlerLinkTootip>>}}}
^^where: %0=title, %1=username, %2=modification date, %3=size in bytes, %4=description slice, %5=first N characters of tiddler content^^
Tiddler link tooltip date format:
{{stretch{<<option txtTiddlerLinkTooltipDate>>}}}
Tiddler excerpt limit (chars):
{{stretch{<<option txtTiddlerLinkTooltipLimit>>}}}
***/

config.messages.tiddlerLinkTooltip='%4';
config.messages.tiddlerLinkTooltipDate='DDD, MMM DDth YYYY 0hh12:0mm AM';
config.messages.tiddlerLinkTooltipLimit=50;

config.options.txtTiddlerLinkTootip=
	config.options.txtTiddlerLinkTootip||config.messages.tiddlerLinkTooltip;
config.options.txtTiddlerLinkTooltipDate=
	config.options.txtTiddlerLinkTooltipDate||config.messages.tiddlerLinkTooltipDate;
config.options.txtTiddlerLinkTooltipLimit=
	config.options.txtTiddlerLinkTooltipLimit||config.messages.tiddlerLinkTooltipLimit;

Tiddler.prototype.getSubtitle = function() {
	var modifier = this.modifier;
	if(!modifier) modifier = config.messages.subtitleUnknown;
	var modified = this.modified;
	if(modified) modified = modified.formatString(config.options.txtTiddlerLinkTooltipDate);
	else modified = config.messages.subtitleUnknown;
	var descr=store.getTiddlerSlice(this.title,'Description')||'';
	var txt=this.text.substr(0,config.options.txtTiddlerLinkTooltipLimit);
	if (this.text.length>config.options.txtTiddlerLinkTooltipLimit) txt+="...";
	return config.options.txtTiddlerLinkTootip.format([this.title,modifier,modified,this.text.length,descr,txt]);
};
/***
Set default text for new tiddlers
***/
config.views.wikified.defaultText=store.getTiddlerText("DefaultTiddlerText");
config.views.editor.defaultText=store.getTiddlerText("DefaultTiddlerText"); 
[[Home|HomePage]] 
[[Software Development]]
[[Guidelines]]

[[Software Tools|SoftwareToolsPage]]
[[Modelling References]]
[[Programming Topics]]

[[Knowledge Management|KnowledgeManagement]]

[[Quotes|QuotesPage]]
[[Concepts|ConceptsPage]]
[[Bibliography|BibliographyPage]]
TagPolicy
----
[[Travel|TravelPage]]
----
__''[[Last Updates|LastUpdates]]''__
----
[[Administration|AdministrationPage]]
<<option chkEnableTabsBar>> Tabbed navigation
DisplayOptions
^^TiddlySpace^^
^^TiddlyWiki 
<<version>>^^
----
[img[http://guestscounter.com/count.php?c_style=2&id=1364293041" border=0 alt="counter widget"]]
----

<<TiddlyTagMindMap filter:[tag[Guideline]] vizType:rgraph id:Guideline nodeSize:5 nodeType:ellipse nodeHoverColor:'#ee00ff' nodeColor:"#ff0000" edgeColor:'#ccc' edgeWidth:2 width:750 height:480 template:NodeTemplate>>
----
/%
@@color:#c4d6ed; ^^
Description: TODO
^^@@
%/
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xl="http://www.w3.org/1999/xlink" version="1.1" viewBox="301 225 48 52"
width="30" height="30">
<g stroke="none" stroke-opacity="1" stroke-dasharray="none" fill="none" fill-opacity="1">
	<g>
		<path d="M 333.00003 234 L 306 258.75003 L 301.5 270 L 312.75 265.50003 L 339.75 240.74998 Z M 337.5 229.50002 
		L 335.24988 231.75008 L 341.99997 238.50003 L 344.24997 236.24995 Z M 342 225.00003 L 339.74988 227.25009 
		L 346.5 234.00005 L 348.75 231.75003 Z M 301.5 273.9719 C 301.5 273.9719 309.59888 277.99927 317.70013 273.97183 
		C 325.80066 269.94437 341.99997 276.65686 341.99997 276.65686 L 341.99997 273.97195 
		C 341.99997 273.97195 325.80014 267.2594 317.70013 271.28687 C 309.6 275.31451 301.5 271.28683 301.5 271.28683 Z" 
		fill="#101010" class="glyph"/>
	</g>
</g>
</svg>
/***
|''Name''|LoadMissingExternalTiddler|
|''Version''|0.1.0|
|''Author''|Jon Robson|
***/
//{{{
var _loadMissing = Story.prototype.loadMissingTiddler;
Story.prototype.loadMissingTiddler = function(title,fields,callback) {
	var matches = title.match(/([^\*]*) \*\(@([^\)]*)\)\*/);
	if(matches && matches.length > 0) {
		var sTitle = matches[1];
		var space = matches[2];		config.extensions.tiddlyspace.displayServerTiddler(story.getTiddler(title),
			sTitle, "bags/%0_public".format(space));
	} else {
	_loadMissing.apply(this, arguments)
	}
};
//}}}
/***
https://raw.github.com/tiddlyweb/chrjs/master/main.js
***/
//{{{
// TiddlyWeb adaptor
// v0.14.3

/*jslint vars: true, unparam: true, nomen: true, white: true */
/*global jQuery */

var tiddlyweb = (function($) {

"use strict";

var tw = {
	routes: {
		// host is the TiddlyWeb instance's URI (including server_prefix)
		// placeholders "_type" & "name" refer to the respective bag/recipe
		root     : "{host}/",
		bags     : "{host}/bags",
		bag      : "{host}/bags/{name}",
		recipes  : "{host}/recipes",
		recipe   : "{host}/recipes/{name}",
		tiddlers : "{host}/{_type}s/{name}/tiddlers",
		tiddler  : "{host}/{_type}s/{name}/tiddlers/{title}",
		revisions: "{host}/{_type}s/{name}/tiddlers/{title}/revisions",
		revision : "{host}/{_type}s/{name}/tiddlers/{title}/revisions/{revision}",
		search   : "{host}/search?q={query}"
	}
};

var convertTimestamp, supplant;

// host (optional) is the URI of the originating TiddlyWeb instance
tw.Resource = function(type, host) {
	if(arguments.length) { // initialization
		this._type = type;
		if(host !== false) {
			this.host = host !== undefined ? host.replace(/\/$/, "") : null;
		}
	}
};
$.extend(tw.Resource.prototype, {
	// retrieves resource from server
	// callback is passed resource, status, XHR (cf. jQuery.ajax success)
	// errback is passed XHR, error, exception, resource (cf. jQuery.ajax error)
	// filters is an optional filter string (e.g. "select=tag:foo;limit=5")
	get: function(callback, errback, filters) {
		var uri = this.route();
		if(filters) {
			var separator = uri.indexOf("?") === -1 ? "?" : ";";
			uri += separator + filters;
		}
		var self = this;
		return $.ajax({
			url: uri,
			type: "GET",
			dataType: "json",
			success: function(data, status, xhr) {
				var resource = self.parse(data);
				resource.etag = xhr.getResponseHeader("Etag");
				callback(resource, status, xhr);
			},
			error: function(xhr, error, exc) {
				errback(xhr, error, exc, self);
			}
		});
	},
	// sends resource to server
	// callback is passed data, status, XHR (cf. jQuery.ajax success)
	// errback is passed XHR, error, exception, resource (cf. jQuery.ajax error)
	put: function(callback, errback) {
		var self = this;
		var options = {
			url: this.route(),
			type: "PUT",
			contentType: "application/json",
			data: JSON.stringify(this.baseData()),
			success: function(data, status, xhr) {
				callback(self, status, xhr);
			},
			error: function(xhr, error, exc) {
				errback(xhr, error, exc, self);
			}
		};
		if(this.ajaxSetup) {
			this.ajaxSetup(options);
		}
		return $.ajax(options);
	},
	// deletes resource on server
	// callback is passed data, status, XHR (cf. jQuery.ajax success)
	// errback is passed XHR, error, exception, resource (cf. jQuery.ajax error)
	"delete": function(callback, errback) {
		var self = this;
		var options = {
			url: this.route(),
			type: "DELETE",
			success: function(data, status, xhr) {
				callback(self, status, xhr);
			},
			error: function(xhr, error, exc) {
				errback(xhr, error, exc, self);
			}
		};
		if(this.ajaxSetup) {
			this.ajaxSetup(options);
		}
		return $.ajax(options);
	},
	// returns an object carrying only the essential information of the resource
	baseData: function() {
		var data = {},
			self = this;
		$.each(this.data, function(i, item) {
			var value = self[item];
			if(value !== undefined) {
				data[item] = value;
			}
		});
		return data;
	},
	// returns corresponding instance from a raw object (if applicable)
	parse: function(data) {
		return data;
	},
	// list of accepted keys in serialization
	data: [],
	// returns resource's URI
	route: function() {
		return supplant(tw.routes[this._type], this);
	}
});

var Container = function(type, name, host) {
	if(arguments.length) { // initialization
		tw.Resource.apply(this, [type, host]);
		this.name = name;
		this.desc = "";
		this.policy = new tw.Policy({});
	}
};
Container.prototype = new tw.Resource();
$.extend(Container.prototype, {
	tiddlers: function() {
		return new tw.TiddlerCollection(this);
	},
	parse: function(data) {
		var type = tw._capitalize(this._type),
			container = new tw[type](this.name, this.host);
		data.policy = new tw.Policy(data.policy);
		return $.extend(container, data);
	},
	data: ["desc", "policy"]
});

// attribs is an object whose members are merged into the instance (e.g. query)
tw.Collection = function(type, host, attribs) {
	if(arguments.length) { // initialization
		tw.Resource.apply(this, [type, host]);
		$.extend(this, attribs);
	}
};
tw.Collection.prototype = new tw.Resource();

tw.TiddlerCollection = function(container, tiddler) {
	if(arguments.length) { // initialization
		tw.Collection.apply(this, [tiddler ? "revisions" : "tiddlers"]);
		this.container = container || null;
		this.tiddler = tiddler || null;
	}
};
tw.TiddlerCollection.prototype = new tw.Collection();
$.extend(tw.TiddlerCollection.prototype, {
	parse: function(data) {
		var container = this.container;
		return $.map(data, function(item, i) {
			var tiddler = new tw.Tiddler(item.title, container),
				bag = item.bag;
			tiddler = tw.Tiddler.prototype.parse.apply(tiddler, [item]);
			if(!tiddler.bag && bag) { // XXX: bag always present!?
				tiddler.bag = new tw.Bag(bag, container.host);
			}
			if(!tiddler.recipe && item.recipe) {
				tiddler.recipe = new tw.Recipe(item.recipe, container.host);
			}
			delete item.recipe;
			return $.extend(tiddler, item);
		});
	},
	route: function() {
		var params = this.container;
		if(this.tiddler) {
			var container = this.tiddler.bag || this.tiddler.recipe;
			params = {
				_type: container._type,
				host: container.host,
				name: container.name,
				title: this.tiddler.title
			};
		}
		return supplant(tw.routes[this._type], params);
	}
});

tw.Search = function(query, host) {
	tw.Collection.apply(this, ["search", host]);
	this.query = query;
};
tw.Search.prototype = new tw.Collection();
$.extend(tw.Search.prototype, {
	parse: function(data) {
		this.container = { // XXX: hacky
			_type: "bag",
			host: this.host
		};
		var tiddlers = tw.TiddlerCollection.prototype.parse.apply(this, arguments);
		delete this.container;
		return tiddlers;
	}
});

// title is the name of the tiddler
// container (optional) is an instance of either Bag or Recipe
// optionally accepts a single object representing tiddler attributes
tw.Tiddler = function(title, container) {
	tw.Resource.apply(this, ["tiddler", false]);
	this.title = title;
	this.bag = container && container._type === "bag" ? container : null;
	this.recipe = container && container._type === "recipe" ? container : null;
	var self = this;
	$.each(this.data, function(i, item) {
		self[item] = undefined; // exposes list of standard attributes for inspectability
	});
	if(title && title.title) { // title is an object of tiddler attributes
		$.extend(this, title);
	}
};
tw.Tiddler.prototype = new tw.Resource();
$.extend(tw.Tiddler.prototype, {
	revisions: function() {
		return new tw.TiddlerCollection(this.bag || this.recipe, this);
	},
	route: function() {
		var container = this.bag || this.recipe;
		var params = $.extend({}, this, {
			host: container ? container.host : null,
			_type: this.bag ? "bag" : (this.recipe ? "recipe" : null),
			name: container ? container.name : null
		});
		return supplant(tw.routes[this._type], params);
	},
	parse: function(data) {
		var tiddler = new tw.Tiddler(this.title),
			container = this.bag || this.recipe;
		if(data.bag) {
			tiddler.bag = new tw.Bag(data.bag, container.host);
			delete data.bag;
		}
		delete data.recipe;
		tiddler.created = data.created ? convertTimestamp(data.created) : new Date();
		delete data.created;
		tiddler.modified = data.modified ? convertTimestamp(data.modified) : new Date();
		delete data.modified;
		if(this.recipe) {
			tiddler.recipe = this.recipe;
		}
		return $.extend(tiddler, data);
	},
	data: ["created", "creator", "modifier", "modified", "tags", "type", "text",
			"fields"],
	ajaxSetup: function(options) {
		var self = this;
		if(this.etag && (options.type === "PUT" || options.type === "DELETE")) {
			options.beforeSend = function(xhr) {
				xhr.setRequestHeader("If-Match", self.etag);
			};
		}
		if(options.type === "PUT") {
			var callback = options.success;
			options.success = function(data, status, xhr) {
				var loc = xhr.getResponseHeader("Location"),
					etag = xhr.getResponseHeader("Etag");
				if(loc && etag) {
					self.etag = etag;
					if(!self.bag) {
						var bag = loc.split("/bags/").pop().split("/")[0];
						self.bag = new tw.Bag(bag, self.recipe.host);
					}
					callback(self, status, xhr);
				} else { // IE
					self.get(callback, options.error);
				}
			};
		}
	}
});

tw.Revision = function(id, tiddler) {
	var container = tiddler.bag || tiddler.recipe;
	tw.Tiddler.apply(this, [tiddler.title, container]);
	this._type = "revision";
	this.revision = id;
};
tw.Revision.prototype = new tw.Tiddler();
$.extend(tw.Revision.prototype, {
	revisions: false,
	data: false,
	put: false,
	"delete": false
});

tw.Bag = function(name, host) {
	Container.apply(this, ["bag", name, host]);
};
tw.Bag.prototype = new Container();

tw.Recipe = function(name, host) {
	Container.apply(this, ["recipe", name, host]);
	this.recipe = [];
};
tw.Recipe.prototype = new Container();
$.extend(tw.Recipe.prototype, {
	data: ["recipe"].concat(Container.prototype.data)
});

tw.Policy = function(constraints) { // TODO: validation?
	var self = this;
	$.each(this.constraints, function(i, item) {
		self[item] = constraints[item];
	});
};
tw.Policy.prototype.constraints = ["read", "write", "create", "delete",
	"manage", "accept", "owner"];

/*
 * utilities
 */

tw._capitalize = function(str) {
	return str.charAt(0).toUpperCase() + str.slice(1);
};

// convert YYYYMMDDhhmmss timestamp to Date instance
convertTimestamp = function(t) {
	if (t.match(/^\d{12,17}$/)) {
		return new Date(Date.UTC(
			parseInt(t.substr(0, 4), 10),
			parseInt(t.substr(4, 2), 10) - 1,
			parseInt(t.substr(6, 2), 10),
			parseInt(t.substr(8, 2), 10),
			parseInt(t.substr(10, 2), 10),
			parseInt(t.substr(12, 2) || "0", 10),
			parseInt(t.substr(14, 3) || "0", 10)
		));
	} else {
		return new Date(Date.parse(t));
	}
};

// adapted from Crockford (http://javascript.crockford.com/remedial.html)
supplant = function(str, obj) {
	return str.replace(/{([^{}]*)}/g, function (a, b) {
		var r = obj[b];
		r = typeof r === "string" || typeof r === "number" ? r : a;
		return $.inArray(b, ["host", "query"]) !== -1 ? r : encodeURIComponent(r); // XXX: special-casing
	});
};

return tw;

}(jQuery));
//}}}
Computer Aided Software Engineering
[[Wikipedia|http://en.wikipedia.org/wiki/Computer-aided_software_engineering]]
----
See also : [[CASE tools]]
----
@@color:#c4d6ed; ^^
Description: Computer Aided Software Engineering
^^@@
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AP8zZgAAAGYA//8zAADMMwD/mTMAAGYzAP8zMwAAADMAzP8AAADMAADMmQAAAGYAAMwzAAAAAADuzAAA3QAAALvMAACqAAAAiMwAAHcAAABVmQAARAAAACKZAAARAADuAJkA3QAAALsAmQCqAAAAiACZAHcAAABVAJkARAAAACIAZgARAADuAABm3QAAALsAAGaqAAAAiAAAZncAAABVAABmRAAAACIAAGYRAAAA7u7uM93d3QC7u7szqqqqAIiIiDN3d3cAVVVVM0RERAAiIiIzERERAAAAADMBAQEBAQEBAQEBpXl5eXl5eXl5eXmlAQEBAQEBAQEBAQEBAQEBAQEBgHl5eXl5eXl5eXl5eXl5gAEBAQEBAQEBAQEBAQEB/Xp5eXlVT04qKioqTk9VeXl5ev0BAQEBAQEBAQEBAaV5eXlPKioqKioqKioqKioqT3l5eaUBAQEBAQEBAQGAeXlVTioqKioqKioqKioqKioqTlV5eYABAQEBAQEBgHl5VSoqKioqKioqKioqKioqKioqKlV5eYABAQEBAaV5eVUqKioqKioqKioqKioqKioqKioqKlV5eaUBAQEBeXlVKioqKioqKioqKioqKioqKioqKioqKlV5eQEBAXl5eU4qKioqKioqKjExMTExMSoqKioqKioqTnl5eQEBeXlPKioqKioqKjEyMjIyMjIyMjEqKioqKioqT3l5AXp5eSoqKioqKioxMjIxBwcHBzEyMjEqKioqKioqeXl6eXlVKioqKioqMTIxBwcHBwcHBwcxMjEqKioqKipVeXl5eU8qKioqKioyMgcHBwcHBwcHBwcyMioqKioqKk95eXl5TioqKioqMTIxBwcHBwcHBwcHBzEyMSoqKioqTnl5eXkqKioqKioxMgcHBwcHBwcHBwcHBzIxKioqKioqeXl5eSoqKioqKjEyBwcHBwcHBwcHBwcHMjEqKioqKip5eXl5KioqKioqMTIHBwcHBwcHBwcHBwcyMSoqKioqKnl5eXkqKioqKioxMgcHBwcHBwcHBwcHBzIxKioqKioqeXl5eU4qKioqKjEyMQcHBwcHBwcHBwcxMjEqKioqKk55eXl5TyoqKioqKjIyBwcHBwcHBwcHBzIyKioqKioqT3l5eXlVKioqKioqMTIxBwcHBwcHBwcxMjEqKioqKipVeXl6eXkqKioqKioqMTIyMQcHBwcxMjIxKioqKioqKnl5egF5eU8qKioqKioqMTIyMjIyMjIyMSoqKioqKipPeXkBAXl5eU4qKioqKioqKjExMTExMSoqKioqKioqTnl5eQEBAXl5VSoqKioqKioqKioqKioqKioqKioqKipVeXkBAQEB+nl5VSoqKioqKioqKioqKioqKioqKioqVXl5+gEBAQEBenl5VSoqKioqKioqKioqKioqKioqKlV5eXoBAQEBAQEBeXl5VU4qKioqKioqKioqKioqKk5VeXl5AQEBAQEBAQEBenl5eU8qKioqKioqKioqKipPeXl5egEBAQEBAQEBAQEB+nl5eXlVT04qKioqTk9VeXl5efoBAQEBAQEBAQEBAQEBAXl5eXl5eXl5eXl5eXl5eXkBAQEBAQEBAQEBAQEBAQEBAQF6eXl5eXl5eXl5eXoBAQEBAQEBAQEB/+AH//+AAf/+AAB//AAAP/gAAB/wAAAP4AAAB8AAAAPAAAADgAAAAYAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAYAAAAHAAAADwAAAA+AAAAfwAAAP+AAAH/wAAD/+AAB//4AB///gB/8oAAAAIAAAAEAAAAABACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAEAAAACAAAAAwAAAAMAAAADAAAABG1bSA61m3JXuqB4mbuhd8m9o3jqvaF4+b2hePm9o3jqu6F3ybqgeJm1m3JXbVtIDgAAAAQAAAADAAAAAwAAAAMAAAACAAAAAQAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAACAAAAAwAAAAUAAAAGAAAACI98Wye0nXWavKF4876kev++pHr/vqR6/76kev++pHr/vqR6/76kev++pHr/vqR6/76kev+8oXjztJ11mo98WycAAAAIAAAABgAAAAUAAAADAAAAAgAAAAEAAAAAAAAAAAAAAAAAAAABAAAAAgAAAAQAAAAHAAAAChwcHBKulnGJvaN5+L6kev++pHr/y7GJ/9/Fnv/s1K7/9t25//rivv/64r7/9t25/+zUrv/fxZ7/y7GJ/76kev++pHr/vaN5+K6WcYkcHBwSAAAACgAAAAcAAAAEAAAAAgAAAAEAAAAAAAAAAAAAAAEAAAADAAAABwAAAAtuYkUst552z76kev++pHr+1LuS//Latf/85cD//OXA//zlwP/85cD//OXA//zlwP/85cD//OXA//zlwP/85cD/8tq1/9S7kv++pHr+vqR6/7eeds9uYkUsAAAACwAAAAcAAAADAAAAAQAAAAAAAAABAAAAAgAAAAQAAAAIi3hbNbqgd+a+pHr/xayD/+3Vr//85cD//OXA//zlwP/85cD//OXA//zlwP/85cD//OXA//zlwP/85cD//OXA//zlwP/85cD//OXA/+3Vr//FrIP/vqR6/7qgd+aJdVg0AAAACAAAAAQAAAACAAAAAQAAAAEAAAACAAAABIl8WSW8oXjlvqR6/8yyiv/54Lz//OXA//zlwP/85cD//OXA//zlwP/85cD//OXA//zlwP/85cD//OXA//zlwP/85cD//OXA//zlwP/85cD//OXA//ngvP/Msor/vqR6/7yheOWJfFklAAAABAAAAAIAAAABAAAAAAAAAAFfXz8Iu6F4zL6kev/Msor/+uK+//zlwP/85cD//OXA//zlwP/85cD//OXA//zlwP/85cD//OXA//zlwP/85cD//OXA//zlwP/85cD//OXA//zlwP/85cD//OXA//rivv/Msor/vqR6/7uheMxfXz8IAAAAAQAAAAAAAAAAAAAAAbqid4K+pHr/xayD//ngvP/85cD//OXA//zlwP/85cD//OXA//zlwP/85cD//OXA//zlwP/85cD//OXA//zlwP/85cD//OXA//zlwP/85cD//OXA//zlwP/85cD//OXA//fgvP/FrIP/vqR6/7qid4IAAAABAAAAAAAAAAC3l28gvaN5+L6kev7t1a///OXA//zlwP/85cD//OXA//zlwP/85cD//OXA/+/Twv/Qq8f/u5HK/7OGzP+zhsz/u5HK/9Crx//v08L//OXA//zlwP/85cD//OXA//zlwP/85cD//OXA/+3Vr/++pHr+vaN5+LeXbyAAAAAAAAAAALuheJa+pHr/1LuS//zlwP/85cD//OXA//zlwP/85cD//OXA//riwP/Pq8f/r4HM/6+Bzf+vgc3/r4HN/6+Bzf+vgc3/r4HN/6+BzP/Pq8f/+uLA//zlwP/85cD//OXA//zlwP/85cD//OXA/9S5kv++pHr/u6F4lgAAAACii3MLvKF4876kev/y2rX//OXA//zlwP/85cD//OXA//zlwP/64sD/w5vJ/6+Bzf+vg83/w5vc/9W06v/dwPD/3cDw/9W06v/Dm9z/r4PN/6+Bzf/Dm8n/+uLA//zlwP/85cD//OXA//zlwP/85cD/8tq1/76kev+8oXjzootzC72feFW+pHr/y7GJ//zlwP/85cD//OXA//zlwP/85cD//OXA/8+rx/+vgc3/tIfQ/9a16//hw/P/4cPz/+HD8//hw/P/4cPz/+HD8//Wtev/tIfQ/6+Bzf/Pq8f//OXA//zlwP/85cD//OXA//zlwP/85cD/y7GJ/76kev+9n3hVvaF4mL6kev/fxZ7//OXA//zlwP/85cD//OXA//zlwP/v08L/r4HM/6+Dzf/Wtev/4cPz/+HD8//hw/P/4cPz/+HD8//hw/P/4cPz/+HD8//Wtev/r4PN/6+BzP/v08L//OXA//zlwP/85cD//OXA//zlwP/fxZ7/vqR6/72heJi8oXfIvqR6/+zUrv/85cD//OXA//zlwP/85cD//OXA/9Crx/+vgc3/w5vc/+HD8//hw/P/4cPz/+HD8//hw/P/4cPz/+HD8//hw/P/4cPz/+HD8//Dm9z/r4HN/9Crx//85cD//OXA//zlwP/85cD//OXA/+zUrv++pHr/vKF3yL2jeOq+pHr/9t25//zlwP/85cD//OXA//zlwP/85cD/u5HK/6+Bzf/VtOr/4cPz/+HD8//hw/P/4cPz/+HD8//hw/P/4cPz/+HD8//hw/P/4cPz/9W06v+vgc3/u5HK//zlwP/85cD//OXA//zlwP/85cD/9t25/76kev+9o3jqvaF4+b6kev/64r7//OXA//zlwP/85cD//OXA//zlwP+zhsz/r4HN/93A8P/hw/P/4cPz/+HD8//hw/P/4cPz/+HD8//hw/P/4cPz/+HD8//hw/P/3cDw/6+Bzf+zhsz//OXA//zlwP/85cD//OXA//zlwP/64r7/vqR6/72hePm9oXj5vqR6//rivv/85cD//OXA//zlwP/85cD//OXA/7OGzP+vgc3/3cDw/+HD8//hw/P/4cPz/+HD8//hw/P/4cPz/+HD8//hw/P/4cPz/+HD8//dwPD/r4HN/7OGzP/85cD//OXA//zlwP/85cD//OXA//rivv++pHr/vaF4+b2jeOq+pHr/9t25//zlwP/85cD//OXA//zlwP/85cD/u5HK/6+Bzf/VtOr/4cPz/+HD8//hw/P/4cPz/+HD8//hw/P/4cPz/+HD8//hw/P/4cPz/9W06v+vgc3/u5HK//zlwP/85cD//OXA//zlwP/85cD/9t25/76kev+9o3jqvKF3yL6kev/s1K7//OXA//zlwP/85cD//OXA//zlwP/Qq8f/r4HN/8Ob3P/hw/P/4cPz/+HD8//hw/P/4cPz/+HD8//hw/P/4cPz/+HD8//hw/P/w5vc/6+Bzf/Qq8f//OXA//zlwP/85cD//OXA//zlwP/s1K7/vqR6/7yhd8i9oXiYvqR6/9/Fnv/85cD//OXA//zlwP/85cD//OXA/+/Twv+vgcz/r4PN/9a16//hw/P/4cPz/+HD8//hw/P/4cPz/+HD8//hw/P/4cPz/9a16/+vg83/r4HM/+/Twv/85cD//OXA//zlwP/85cD//OXA/9/Fnv++pHr/vaF4mL2feFW+pHr/y7GJ//zlwP/85cD//OXA//zlwP/85cD//OXA/8+rx/+vgc3/tIfQ/9a16//hw/P/4cPz/+HD8//hw/P/4cPz/+HD8//Wtev/tIfQ/6+Bzf/Pq8f//OXA//zlwP/85cD//OXA//zlwP/85cD/y7GJ/76kev+9n3hVootzC7yhePO+pHr/8tq1//zlwP/85cD//OXA//zlwP/85cD/+uLA/8Obyf+vgc3/r4PN/8Ob3P/VtOr/3cDw/93A8P/VtOr/w5vc/6+Dzf+vgc3/w5vJ//riwP/85cD//OXA//zlwP/85cD//OXA//Latf++pHr/vKF486KLcwsAAAAAu6N3l76kev/Uu5L//OXA//zlwP/85cD//OXA//zlwP/85cD/+uLA/8+rx/+vgcz/r4HN/6+Bzf+vgc3/r4HN/6+Bzf+vgc3/r4HM/8+rx//64sD//OXA//zlwP/85cD//OXA//zlwP/85cD/1LmS/76kev+7oXiWAAAAAAAAAAC3l28gvaN5+L6kev7t1a///OXA//zlwP/85cD//OXA//zlwP/85cD//OXA/+/Twv/Qq8f/u5HK/7OGzP+zhsz/u5HK/9Crx//v08L//OXA//zlwP/85cD//OXA//zlwP/85cD//OXA/+3Vr/++pHr+vaN5+LeXbyAAAAAAAAAAAAAAAAC6oneCvqR6/8Wsg//54Lz//OXA//zlwP/85cD//OXA//zlwP/85cD//OXA//zlwP/85cD//OXA//zlwP/85cD//OXA//zlwP/85cD//OXA//zlwP/85cD//OXA//zlwP/34Lz/xayD/76kev+6oneCAAAAAAAAAAAAAAAAAAAAAH9/VQa8oHjLvqR6/8yyiv/64r7//OXA//zlwP/85cD//OXA//zlwP/85cD//OXA//zlwP/85cD//OXA//zlwP/85cD//OXA//zlwP/85cD//OXA//zlwP/85cD/+uK+/8yyiv++pHr/vKB4y39/VQYAAAAAAAAAAAAAAAAAAAAAAAAAALKhbh67o3nkvqR6/8yyiv/54Lz//OXA//zlwP/85cD//OXA//zlwP/85cD//OXA//zlwP/85cD//OXA//zlwP/85cD//OXA//zlwP/85cD//OXA//ngvP/Msor/vqR6/7ujeeSyoW4eAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALqbdim7o3nkvqR6/8Wsg//t1a///OXA//zlwP/85cD//OXA//zlwP/85cD//OXA//zlwP/85cD//OXA//zlwP/85cD//OXA//zlwP/t1a//xayD/76kev+7o3nkupt2KQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALKhbh68oHjLvqR6/76kev7Uu5L/8tq1//zlwP/85cD//OXA//zlwP/85cD//OXA//zlwP/85cD//OXA//zlwP/y2rX/1LmS/76kev6+pHr/vKB4y7Khbh4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH9/VQa6oneCvaN5+L6kev++pHr/y7GJ/9/Fnv/s1K7/9t25//rivv/64r7/9t25/+zUrv/fxZ7/y7GJ/76kev++pHr/vaN5+Lqid4J/f1UGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC3l28gu6F4lryhePO+pHr/vqR6/76kev++pHr/vqR6/76kev++pHr/vqR6/76kev++pHr/vKF487uheJa3l28gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAootzC72feFW9oXiYvKF3yL2jeOq9oXj5vaF4+b2jeOq8oXfIvaF4mL2feFWii3MLAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP/gB///gAH//gAAf/wAAD/4AAAf8AAAD+AAAAfAAAADwAAAA4AAAAGAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAGAAAABwAAAA8AAAAPgAAAH8AAAD/gAAB/8AAA//gAAf/+AAf//4Af/
/***
|''Name''|BinaryUploadPlugin|
|''Version''|0.3.16|
|''Author''|Ben Gillies and Jon Robson|
|''Type''|plugin|
|''Source''|http://github.com/TiddlySpace/tiddlyspace/raw/master/src/plugins/BinaryUploadPlugin.js|
|''Description''|Upload a binary file to TiddlyWeb|
|''CoreVersion''|2.6.1|
|''Requires''|TiddlySpaceConfig TiddlyWebConfig|
!Usage
{{{
<<binaryUpload bag:<name> edit:tags edit:title tags:<default tags> title:<title> >>
}}}
* {{{bag:<name>}}}: optional; if left out, the file will be saved to the current workspace
* {{{edit:tags}}}: specifies that you want to tag the file being uploaded
* {{{edit:title}}}: specifies that you want to set the title to something other than the filename
* {{{tags:<default tags>}}}: specifies a default set of tags to apply to the file (requires {{{edit:tags}}} to be set)
* {{{title:<title>}}}: predefines the title of the binary tiddler
!Requires
TiddlyWeb
tiddlywebplugins.form
!Code
***/
//{{{
(function($) {

var tiddlyspace = config.extensions.tiddlyspace;

var macro = config.macros.binaryUpload = {
	locale: {
		titleDefaultValue: "Please enter a title...",
		tagsDefaultValue: "Please enter some tags...",
		titlePrefix: "title: ",
		tagsPrefix: "tags: ",
		loadSuccess: 'Tiddler %0 successfully uploaded',
		loadError: "An error occurred when uploading the tiddler %0",
		uploadInProgress: "Please wait while the file is uploaded...",
		membersOnly: "Only members can upload."
	},
	renderInputFields: function(container, options) {
		var locale = macro.locale;
		var editableFields = options.edit;
		var includeFields = {
			tags:  editableFields && editableFields.contains("tags") ? true : false,
			title: editableFields && editableFields.contains("title") ? true : false
		};
		var fields = ["title", "tags"];
		for(var i = 0; i < fields.length; i++) {
			var fieldName = fields[i];
			var userDefault = options[fieldName];
			var defaultValue = userDefault ? userDefault[0] : false;
			if(includeFields[fieldName] || defaultValue) {
				var localeDefault = locale["%0DefaultValue".format(fieldName)];
				var className = defaultValue ? "userInput" : "userInput notEdited";
				var inputEl;
				var val = defaultValue || localeDefault || "";
				var iContainer = $("<div />").addClass("binaryUpload%0".format(fieldName)).
					appendTo(container);
				if(defaultValue && !includeFields[fieldName]) {
					var label = locale["%0Prefix".format(fieldName)];
					$("<span />").text(label).appendTo(iContainer);
					$("<span />").addClass("disabledInput").text(val).appendTo(iContainer);
					inputEl = $("<input />").attr("type", "hidden");
				} else {
					inputEl = $("<input />").attr("type", "text");
				}
				inputEl.attr("name", fieldName).
					addClass("%0Edit".format(fieldName)).
					val(val).addClass(className).appendTo(iContainer);
			}
		}
	},
	getTiddlerName: function(fileName) {
		var fStart = fileName.lastIndexOf("\\");
		var fStart2 = fileName.lastIndexOf("/");
		fStart = fStart < fStart2 ? fStart2 : fStart;
		fileName = fileName.substr(fStart+1);
		return fileName;
	},
	errorHandler: function(fileName) {
		displayMessage("upload of file %0 failed".format(fileName));
	},
	uploadFile: function(place, baseURL, workspace, options) {
		var pleaseWait = $(".uploadProgress", place);
		var iframeName = options.target;
		var form = $("form", place);
		var existingVal = $("input[name=title]", form).val();
		var fileName = existingVal || $('input:file', form).val();
		if(!fileName) {
			return false; // the user hasn't selected a file yet
		}
		fileName = macro.getTiddlerName(fileName);
		$("input[name=title]", place).val(fileName);
		// we need to go somewhere afterwards to ensure the onload event triggers
		var redirectTo = "/%0/tiddlers.txt?select=title:%1".
			format(workspace, fileName);
		var token = tiddlyspace ? tiddlyspace.getCSRFToken() : "";
		var action = "%0?csrf_token=%1&redirect=%2"
			.format(baseURL, token, redirectTo);
		form[0].action = action; // dont use jquery to work with ie
		form[0].target = iframeName;
		// do not refactor following line... won't work in IE6 otherwise
		$(place).append($('<iframe name="' + iframeName + '" id="' + iframeName + '"/>').css('display','none'));
		macro.iFrameLoader(iframeName, function() {
			var content = document.getElementById(iframeName).contentWindow.document.documentElement;
			if($(content).text().indexOf(fileName) > -1) {
				options.callback(place, fileName, workspace, baseURL);
			} else {
				macro.errorHandler(fileName);
			}
			form.show(1000);
			pleaseWait.hide(1000);
		});
		form.hide(1000);
		pleaseWait.show(1000);
		return true;
	},
	createUploadForm: function(place, options) {
		var locale = macro.locale;
		if(readOnly) {
			$('<div class="annotation" />').text(locale.membersOnly).
				appendTo(place);
			return;
		}
		var bag = options.bag;
		options.callback = options.callback ? options.callback :
			function(place, fileName, workspace, baseurl) {
				macro.displayFile(place, fileName, workspace);
				displayMessage(locale.loadSuccess.format(fileName));
				$("input[type=text]", place).val("");
			};
		var defaults = config.defaultCustomFields;
		place = $("<div />").addClass("container").appendTo(place)[0];
		var workspace = bag ? "bags/%0".format(bag) : config.defaultCustomFields["server.workspace"];
		var baseURL = defaults["server.host"];
		baseURL += (baseURL[baseURL.length - 1] !== "/") ? "/" : "";
		baseURL = "%0%1/tiddlers".format(baseURL, workspace);
		//create the upload form, complete with invisible iframe
		var iframeName = "binaryUploadiframe%0".format(Math.random());
		// do not refactor following line of code to work in IE6.
		var form = $('<form action="%0" method="POST" enctype="multipart/form-data" />'.
					format(baseURL)).addClass("binaryUploadForm").
			appendTo(place)[0];
		macro.renderInputFields(form, options);
		$(form).
			append('<div class="binaryUploadFile"><input type="file" name="file" /></div>').
			append('<div class="binaryUploadSubmit"><input type="submit" value="Upload" disabled /></div>').
			submit(function(ev) {
				this.target = iframeName;
				options.target = iframeName;
				macro.uploadFile(place, baseURL, workspace, options);
			})
			.find('[type="file"]').bind('change', function() {
				$(form).find('[type="submit"]').prop('disabled', false);
			}).end();
		$('<div />').addClass("uploadProgress").text(locale.uploadInProgress).hide().appendTo(place);
		$("input[name=file]", place).change(function(ev) {
			var target = $(ev.target);
			var fileName = target.val();
			var title = $("input[type=text][name=title]", place);
			if(!title.val()) {
				title.val(fileName);
			}
		});
	},
	handler: function(place, macroName, params, wikifier, paramString, tiddler) {
		params = paramString.parseParams(null, null, true);
		macro.createUploadForm(place, params[0]);
	},
	iFrameLoader: function(iframeName, callback) {
		var iframe = document.getElementById(iframeName); //jQuery doesn't seem to want to do this!?
		var locale = macro.locale;
		$(".userInput").addClass("notEdited"); // reset editing
		var finishedLoading = function() {
			callback();
		};
		var iFrameLoadHandler = function() {
			finishedLoading.apply();
			return;
		};

		iframe.onload = iFrameLoadHandler;
		//IE
		completeReadyStateChanges = 0;
		iframe.onreadystatechange = function() {
			if (++(completeReadyStateChanges) == 3) {
				iFrameLoadHandler();
			}
		};
	},
	displayFile: function(place, title, workspace) {
		var adaptor = store.getTiddlers()[0].getAdaptor();
		var context = {
			workspace: workspace,
			host: config.defaultCustomFields['server.host']
		};
		adaptor.getTiddler(title, context, null, function(context) {
			if(context.status) {
				store.addTiddler(context.tiddler);
				story.displayTiddler(place, title);
				var image = config.macros.image;
				if(image && image.refreshImage) {
					image.refreshImage("/%0/tiddlers/%1".format(workspace, title));
					image.refreshImage(title);
					image.refreshImage("/%0".format(title));
					image.refreshImage("%0/%1/tiddlers/%2".format(config.extensions.tiddlyweb.host, workspace, title));
				}
			} else {
				displayMessage(macro.locale.loadError.format(title));
			}
		});
	}
};

if(tiddlyspace) {
	config.macros.binaryUploadPublic = {
		handler: function(place, macroName, params, wikifier, paramString, tiddler) {
			var options = paramString.parseParams(null, null, true)[0];
			var bag = tiddlyspace.getCurrentBag("public");
			options.bag = bag;
			macro.createUploadForm(place, options);
		}
	};
	config.messages.privacySetting = config.options.chkPrivateMode ?
		"private" : "public";
	config.macros.binaryUpload.defaultWorkspace = tiddlyspace.
		getCurrentWorkspace(config.messages.privacySetting);
}

})(jQuery);
//}}}
Integrated Development Environement
----
/%
@@color:#c4d6ed; ^^
Description: Integrated Development Environement
^^@@
%/
/*{{{*/

/* This was the original border around the tab section at top   */
/* 
#tiddlersBar {
	margin: 0.5em;
        border: 1px [[ColorPalette::TertiaryLight]] solid;
        background-color:[[ColorPalette::Background]];
}
*/

/* Undo the xxx to have an underline / border underneath TopMenu or the tab section
#tiddlersBar {
	margin: 0.5em;
           border-bottom: 1px [[ColorPalette::TertiaryLight]] solid;
           border-top:    1px [[ColorPalette::TertiaryLight]] solid;
        background-color:[[ColorPalette::Background]];
}
*/





/* line-height controls the second row of tabs at top. Not noticeable until after 21px;   */
#tiddlersBar .tab { 
     white-space: nowrap;  
     padding: .2em; 
     border: 1px [[ColorPalette::PrimaryDark]] solid;  
     line-height: 30px;
}


#tiddlersBar {padding : .5em}
.tabUnselected .tabButton, .tabSelected .tabButton {padding : 0 2px 0 2px; margin: 0 0 0 0px;}
.tiddler, .tabContents {border:0px [[ColorPalette::TertiaryLight]] solid;}
.tabUnselected { background-color:[[ColorPalette::TertiaryLight]];}
.tabSelected   { background-color:[[ColorPalette::PrimaryLight]];}

 #tiddlersBar .button 
{
    border:0; 
    padding-right: 5px;
    padding-left: 5px;
 
}

/*}}}*/
"//(...) a software requirement is a property which must be exhibited by software developed or adapted to solve a particular problem.//"
[[Guide to the Software Engineering Body of Knowledge (SWEBOK)|http://www.computer.org/portal/web/swebok/html/ch2#ch2-1.1]]

For a distinction against [[Feature]] see [[Software Requirement vs. Feature]]
----
See also : [[SMART Requirements]] [[Writing Good Requirements]]
----
@@color:#c4d6ed; ^^
Description: Software Requirement concept explanation and reference.
^^@@
<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="utf-8"/>
	<title>TiddlySpace Apps</title>
	<link rel="stylesheet" href="/bags/common/tiddlers/reset.css" />
	<link rel="stylesheet" href="/bags/common/tiddlers/appspage.css" />
	<!--[if lt IE 7 ]>
	<link rel="stylesheet" href="/bags/common/tiddlers/appspageie6.css" />
	<![endif]-->
</head>
<body>
	
	<div id="wrapper">
		<div id="TSbar"></div>
		<div id="main-content">
			<div id="space-details">
				<a href="/_space"><img class="siteicon"></a>
				<div id="title-subtitle">
					<h1 class="spaceaddress">
						<span class="spaceName"></span><span class="hostName"></span>
					</h1>
					<p class="tagline"><span class="subTitle"></span><a class="managespaces" href="/_space">manage space</a></p>
				</div>
			</div>
			<div id="holder">
				<div id="appswitcher-wrapper">
					<div id="appswitcher">
						<h2>Your Apps</h2>
						<ul id="app-list">
							<li class="htmlserialisation">
								<a href="/tiddlers.html?select=tag:!excludeLists;sort=-modified">
									<img src="/bags/common/tiddlers/browse_read_blue.png" alt="Icon for the HTML Serialisation" class="app-img" />
									BROWSE
								</a>
							</li>
							<li class="tiddlywiki">
								<a href="/tiddlers.wiki">
									<img src="/bags/common/tiddlers/tiddlywiki2_blue.png" alt="Icon for TiddlyWiki" class="app-img" />
									TIDDLYWIKI
								</a>
							</li>
						</ul>
						<div id="addapp">
							<button class="inactive">Add More!</button>
						</div>
					</div>
					<div id="app-desc">
						<ul>
							<li class="htmlserialisationdesc"><p>an easy to understand HTML representation of your content.</p></li>
							<li class="tiddlywikidesc"><p>use TiddlyWiki to create, edit and organise your content.</p></li>
						</ul>
					</div>
					<div style="clear: both;"></div>
				</div>
			</div>
		</div>
		<div id="footer"><!-- ie doesn't support footer tag -->
			<div id="footer-content">
				<div class="links">
					<a href="http://blog.tiddlyspace.com">blog</a>
					<a href="http://featured.tiddlyspace.com">featured</a>
					<a href="http://docs.tiddlyspace.com">documentation</a>
					<a href="https://github.com/TiddlySpace/tiddlyspace">source</a>
				</div>
				<p>TiddlySpace 2011, created by <a href="http://osmosoft.com">Osmosoft</a></p>
			</div>
		</div>
	</div>
	
	<script type="text/javascript" src="/bags/common/tiddlers/backstage.js"></script>
	<script type="text/javascript" src="/bags/common/tiddlers/jquery.js"></script>
	<script type="text/javascript" src="/bags/tiddlyspace/tiddlers/chrjs"></script>
	<script type="text/javascript" src="/bags/common/tiddlers/chrjs-store.js"></script>
	<script type="text/javascript" src="/bags/common/tiddlers/jquery-json.js"></script>
	<script type="text/javascript" src="/bags/common/tiddlers/appspage.js"></script>
</body>
</html>
[[Modularization]] is, probably, the most important choice you will make on structuring, specifying and implementing a solution. Its impacts, good or bad, will affect [[validation|Validation]] ability, reuse, maintainability, robustness, refactorability and all the other important aspects that define the overall quality of your solution.
It will also play a key role in the management ability of your project, planning, testing, delivery and other tasks are dependent on the quality of your modularization, progress reporting and evaluation, task assignment and know-how selection and almost any other development aspect will favourably or adversely be affected by it. 

The first, easiest and with more immediate return investment in modularization is to define, and closely enforce, a clear set of guidelines to be followed by the development team. These guidelines must encompass [[Namespace and Filesystem Guidelines]],  [[Namespace Coupling Guidelines]] and [[Namespace Code Placement Guidelines]].

!!Fundamental concepts
* ''Abstraction, Encapsulation and Information Hiding'' - The fundamental reference is [[Abstraction, Encapsulation, and Information Hiding|http://www.itmweb.com/essay550.htm]] By Edward V. Berard, The Object Agency <<BibRef Berard>>

----
See also [[Programming Links|ProgrammingLinksPage##OOP]]
----
@@Please do not modify this tiddler; it was created automatically upon space creation.@@
A software system that is not based on a platform maintained with [[Systematic Reuse]] and [[Continuous Improvement]] will decay over time and became legacy or obsolete software.

Also known as software entropy, software erosion or software decay.

Casuistic quick adaptation hacks are the most common cause of decay. And they add to each other up to an unmanageable, uncorrectable system.

[[Refactoring|Refactor]] is a way of dealing with the problem of software rot. [[Systematic Reuse]] also contributes to prevent it.
----
@@color:#c4d6ed; ^^
Description: Software Rot concept explanation and discussion.
^^@@
/***
|Name|SinglePageModePlugin|
|Source|http://www.TiddlyTools.com/#SinglePageModePlugin|
|Documentation|http://www.TiddlyTools.com/#SinglePageModePluginInfo|
|Version|2.9.7|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|Show tiddlers one at a time with automatic permalink, or always open tiddlers at top/bottom of page.|
This plugin allows you to configure TiddlyWiki to navigate more like a traditional multipage web site with only one tiddler displayed at a time.
!!!!!Documentation
>see [[SinglePageModePluginInfo]]
!!!!!Configuration
<<<
<<option chkSinglePageMode>> Display one tiddler at a time
><<option chkSinglePagePermalink>> Automatically permalink current tiddler
><<option chkSinglePageKeepFoldedTiddlers>> Don't close tiddlers that are folded
><<option chkSinglePageKeepEditedTiddlers>> Don't close tiddlers that are being edited
<<option chkTopOfPageMode>> Open tiddlers at the top of the page
<<option chkBottomOfPageMode>> Open tiddlers at the bottom of the page
<<option chkSinglePageAutoScroll>> Automatically scroll tiddler into view (if needed)

Notes:
* The "display one tiddler at a time" option can also be //temporarily// set/reset by including a 'paramifier' in the document URL: {{{#SPM:true}}} or {{{#SPM:false}}}.
* If more than one display mode is selected, 'one at a time' display takes precedence over both 'top' and 'bottom' settings, and if 'one at a time' setting is not used, 'top of page' takes precedence over 'bottom of page'.
* When using Apple's Safari browser, automatically setting the permalink causes an error and is disabled.
<<<
!!!!!Revisions
<<<
2010.11.30 2.9.7 use story.getTiddler()
2008.10.17 2.9.6 changed chkSinglePageAutoScroll default to false
| Please see [[SinglePageModePluginInfo]] for previous revision details |
2005.08.15 1.0.0 Initial Release.  Support for BACK/FORWARD buttons adapted from code developed by Clint Checketts.
<<<
!!!!!Code
***/
//{{{
version.extensions.SinglePageModePlugin= {major: 2, minor: 9, revision: 7, date: new Date(2010,11,30)};
//}}}
//{{{
config.paramifiers.SPM = { onstart: function(v) {
	config.options.chkSinglePageMode=eval(v);
	if (config.options.chkSinglePageMode && config.options.chkSinglePagePermalink && !config.browser.isSafari) {
		config.lastURL = window.location.hash;
		if (!config.SPMTimer) config.SPMTimer=window.setInterval(function() {checkLastURL();},1000);
	}
} };
//}}}
//{{{
if (config.options.chkSinglePageMode==undefined)
	config.options.chkSinglePageMode=false;
if (config.options.chkSinglePagePermalink==undefined)
	config.options.chkSinglePagePermalink=true;
if (config.options.chkSinglePageKeepFoldedTiddlers==undefined)
	config.options.chkSinglePageKeepFoldedTiddlers=false;
if (config.options.chkSinglePageKeepEditedTiddlers==undefined)
	config.options.chkSinglePageKeepEditedTiddlers=false;
if (config.options.chkTopOfPageMode==undefined)
	config.options.chkTopOfPageMode=false;
if (config.options.chkBottomOfPageMode==undefined)
	config.options.chkBottomOfPageMode=false;
if (config.options.chkSinglePageAutoScroll==undefined)
	config.options.chkSinglePageAutoScroll=false;
//}}}
//{{{
config.SPMTimer = 0;
config.lastURL = window.location.hash;
function checkLastURL()
{
	if (!config.options.chkSinglePageMode)
		{ window.clearInterval(config.SPMTimer); config.SPMTimer=0; return; }
	if (config.lastURL == window.location.hash) return; // no change in hash
	var tids=decodeURIComponent(window.location.hash.substr(1)).readBracketedList();
	if (tids.length==1) // permalink (single tiddler in URL)
		story.displayTiddler(null,tids[0]);
	else { // restore permaview or default view
		config.lastURL = window.location.hash;
		if (!tids.length) tids=store.getTiddlerText("DefaultTiddlers").readBracketedList();
		story.closeAllTiddlers();
		story.displayTiddlers(null,tids);
	}
}


if (Story.prototype.SPM_coreDisplayTiddler==undefined)
	Story.prototype.SPM_coreDisplayTiddler=Story.prototype.displayTiddler;
Story.prototype.displayTiddler = function(srcElement,tiddler,template,animate,slowly)
{
	var title=(tiddler instanceof Tiddler)?tiddler.title:tiddler;
	var tiddlerElem=story.getTiddler(title); // ==null unless tiddler is already displayed
	var opt=config.options;
	var single=opt.chkSinglePageMode && !startingUp;
	var top=opt.chkTopOfPageMode && !startingUp;
	var bottom=opt.chkBottomOfPageMode && !startingUp;
	if (single) {
		story.forEachTiddler(function(tid,elem) {
			// skip current tiddler and, optionally, tiddlers that are folded.
			if (	tid==title
				|| (opt.chkSinglePageKeepFoldedTiddlers && elem.getAttribute("folded")=="true"))
				return;
			// if a tiddler is being edited, ask before closing
			if (elem.getAttribute("dirty")=="true") {
				if (opt.chkSinglePageKeepEditedTiddlers) return;
				// if tiddler to be displayed is already shown, then leave active tiddler editor as is
				// (occurs when switching between view and edit modes)
				if (tiddlerElem) return;
				// otherwise, ask for permission
				var msg="'"+tid+"' is currently being edited.\n\n";
				msg+="Press OK to save and close this tiddler\nor press Cancel to leave it opened";
				if (!confirm(msg)) return; else story.saveTiddler(tid);
			}
			story.closeTiddler(tid);
		});
	}
	else if (top)
		arguments[0]=null;
	else if (bottom)
		arguments[0]="bottom";
	if (single && opt.chkSinglePagePermalink && !config.browser.isSafari) {
		window.location.hash = encodeURIComponent(String.encodeTiddlyLink(title));
		config.lastURL = window.location.hash;
		document.title = wikifyPlain("SiteTitle") + " - " + title;
		if (!config.SPMTimer) config.SPMTimer=window.setInterval(function() {checkLastURL();},1000);
	}
	if (tiddlerElem && tiddlerElem.getAttribute("dirty")=="true") { // editing... move tiddler without re-rendering
		var isTopTiddler=(tiddlerElem.previousSibling==null);
		if (!isTopTiddler && (single || top))
			tiddlerElem.parentNode.insertBefore(tiddlerElem,tiddlerElem.parentNode.firstChild);
		else if (bottom)
			tiddlerElem.parentNode.insertBefore(tiddlerElem,null);
		else this.SPM_coreDisplayTiddler.apply(this,arguments); // let CORE render tiddler
	} else
		this.SPM_coreDisplayTiddler.apply(this,arguments); // let CORE render tiddler
	var tiddlerElem=story.getTiddler(title);
	if (tiddlerElem&&opt.chkSinglePageAutoScroll) {
		// scroll to top of page or top of tiddler
		var isTopTiddler=(tiddlerElem.previousSibling==null);
		var yPos=isTopTiddler?0:ensureVisible(tiddlerElem);
		// if animating, defer scroll until after animation completes
		var delay=opt.chkAnimate?config.animDuration+10:0;
		setTimeout("window.scrollTo(0,"+yPos+")",delay); 
	}
}

if (Story.prototype.SPM_coreDisplayTiddlers==undefined)
	Story.prototype.SPM_coreDisplayTiddlers=Story.prototype.displayTiddlers;
Story.prototype.displayTiddlers = function() {
	// suspend single/top/bottom modes when showing multiple tiddlers
	var opt=config.options;
	var saveSPM=opt.chkSinglePageMode; opt.chkSinglePageMode=false;
	var saveTPM=opt.chkTopOfPageMode; opt.chkTopOfPageMode=false;
	var saveBPM=opt.chkBottomOfPageMode; opt.chkBottomOfPageMode=false;
	this.SPM_coreDisplayTiddlers.apply(this,arguments);
	opt.chkBottomOfPageMode=saveBPM;
	opt.chkTopOfPageMode=saveTPM;
	opt.chkSinglePageMode=saveSPM;
}
//}}}
/***
|Name|InlineJavascriptPluginInfo|
|Source|http://www.TiddlyTools.com/#InlineJavascriptPlugin|
|Documentation|http://www.TiddlyTools.com/#InlineJavascriptPluginInfo|
|Version|1.9.6|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|documentation|
|Description|Documentation for InlineJavascriptPlugin|
''Call directly into TW core utility routines, define new functions, calculate values, add dynamically-generated TiddlyWiki-formatted output'' into tiddler content, or perform any other programmatic actions each time the tiddler is rendered.
!!!!!Usage
<<<
This plugin adds wiki syntax for surrounding tiddler content with {{{<script>}}} and {{{</script>}}} markers, so that it can be recognized as embedded javascript code.  When a tiddler is rendered, the plugin automatically invokes any embedded scripts, which can be used to construct and return dynamically-generated output that is inserted into the tiddler content.
{{{
<script type="..." src="..." label="..." title="..." key="..." show>
	/* javascript code goes here... */
</script>
}}}
All parameters are //optional//.    When the ''show'' keyword is used, the plugin will also include the script source code in the output that it displays in the tiddler.  This is helpful when creating examples for documentation purposes (such as used in this tiddler!)

__''Deferred execution from an 'onClick' link''__
<script label="click here" title="mouseover tooltip text" key="X" show>
	/* javascript code goes here... */
	alert('you clicked on the link!');
</script>
By including a {{{label="..."}}} parameter in the initial {{{<script>}}} marker, the plugin will create a link to an 'onclick' script that will only be executed when that specific link is clicked, rather than running the script each time the tiddler is rendered.  You may also include a {{{title="..."}}} parameter to specify the 'tooltip' text that will appear whenever the mouse is moved over the onClick link text, and a {{{key="X"}}} parameter to specify an //access key// (which must be a //single// letter or numeric digit only).

__''Loading scripts from external source files''__
<script src="URL" show>
	/* optional javascript code goes here... */
</script>You can also load javascript directly from an external source URL, by including a src="..." parameter in the initial {{{<script>}}} marker (e.g., {{{<script src="demo.js"></script>}}}).  This is particularly useful when incorporating third-party javascript libraries for use in custom extensions and plugins.  The 'foreign' javascript code remains isolated in a separate file that can be easily replaced whenever an updated library file becomes available.

In addition to loading the javascript from the external file, you can also use this feature to invoke javascript code contained within the {{{<script>...</script>}}} markers.  This code is invoked //after// the external script file has been processed, and can make immediate use of the functions and/or global variables defined by the external script file.
>Note: To ensure that your javascript functions are always available when needed, you should load the libraries from a tiddler that is rendered as soon as your TiddlyWiki document is opened, such as MainMenu.  For example: put your {{{<script src="..."></script>}}} syntax into a separate 'library' tiddler (e.g., LoadScripts), and then add {{{<<tiddler LoadScripts>>}}} to MainMenu so that the library is loaded before any other tiddlers that rely upon the functions it defines. 
>
>Normally, loading external javascript in this way does not produce any direct output, and should not have any impact on the appearance of your MainMenu.  However, if your LoadScripts tiddler contains notes or other visible content, you can suppress this output by using 'inline CSS' in the MainMenu, like this: {{{@@display:none;<<tiddler LoadScripts>>@@}}}
<<<
!!!!!Creating dynamic tiddler content and accessing the ~TiddlyWiki DOM
<<<
An important difference between TiddlyWiki inline scripting and conventional embedded javascript techniques for web pages is the method used to produce output that is dynamically inserted into the document: in a typical web document, you use the {{{document.write()}}} (or {{{document.writeln()}}}) function to output text sequences (often containing HTML tags) that are then rendered when the entire document is first loaded into the browser window.

However, in a ~TiddlyWiki document, tiddlers (and other DOM elements) are created, deleted, and rendered "on-the-fly", so writing directly to the global 'document' object does not produce the results you want (i.e., replacing the embedded script within the tiddler content), and instead will //completely replace the entire ~TiddlyWiki document in your browser window (which is clearly not a good thing!)//.  In order to allow scripts to use {{{document.write()}}}, the plugin automatically converts and buffers all HTML output so it can be safely inserted into your tiddler content, immediately following the script.

''Note that {{{document.write()}}} can only be used to output "pure HTML" syntax.  To produce //wiki-formatted// output, your script should instead return a text value containing the desired wiki-syntax content'', which will then be automatically rendered immediately following the script.  If returning a text value is not sufficient for your needs, the plugin also provides an automatically-defined variable, 'place', that gives the script code ''direct access to the //containing DOM element//'' into which the tiddler output is being rendered.  You can use this variable to ''perform direct DOM manipulations'' that can, for example:
* generate wiki-formatted output using {{{wikify("...content...",place)}}}
* vary the script's actions based upon the DOM element in which it is embedded
* access 'tiddler-relative' DOM information using {{{story.findContainingTiddler(place)}}}
Note:
''When using an 'onclick' script, the 'place' element actually refers to the onclick //link text// itself, instead of the containing DOM element.''  This permits you to directly reference or modify the link text to reflect any 'stateful' conditions that might set by the script.  To refer to the containing DOM element from within an 'onclick' script, you can use "place.parentNode" instead.
<<<
!!!!!Instant "bookmarklets"
<<<
You can also use an 'onclick' link to define a "bookmarklet": a small piece of javascript that can be ''invoked directly from the browser without having to be defined within the current document.''  This allows you to create 'stand-alone' commands that can be applied to virtually ANY TiddlyWiki document... even remotely-hosted documents that have been written by others!!  To create a bookmarklet, simply define an 'onclick' script and then grab the resulting link text and drag-and-drop it onto your browser's toolbar (or right-click and use the 'bookmark this link' command to add it to the browser's menu).

Notes:
*When writing scripts intended for use as bookmarklets, due to the ~URI-encoding required by the browser, ''you cannot not use ANY double-quotes (") within the bookmarklet script code.''
*All comments embedded in the bookmarklet script must ''use the fully-delimited {{{/* ... */}}} comment syntax,'' rather than the shorter {{{//}}} comment syntax.
*Most importantly, because bookmarklets are invoked directly from the browser interface and are not embedded within the TiddlyWiki document, there is NO containing 'place' DOM element surrounding the script.  As a result, ''you cannot use a bookmarklet to generate dynamic output in your document,''  and using {{{document.write()}}} or returning wiki-syntax text or making reference to the 'place' DOM element will halt the script and report a "Reference Error" when that bookmarklet is invoked.  
Please see [[InstantBookmarklets]] for many examples of 'onclick' scripts that can also be used as bookmarklets.
<<<
!!!!!Special reserved function name
<<<
The plugin 'wraps' all inline javascript code inside a function, {{{_out()}}}, so that any return value you provide can be correctly handled by the plugin and inserted into the tiddler.  To avoid unpredictable results (and possibly fatal execution errors), this function should never be redefined or called from ''within'' your script code.
<<<
!!!!!$(...) 'shorthand' function
<<<
As described by Dustin Diaz [[here|http://www.dustindiaz.com/top-ten-javascript/]], the plugin defines a 'shorthand' function that allows you to write:
{{{
$(id)
}}}
in place of the normal standard javascript syntax:
{{{
document.getElementById(id)
}}}
This function is provided merely as a convenience for javascript coders that may be familiar with this abbreviation, in order to allow them to save a few bytes when writing their own inline script code.
<<<
!!!!!Examples
<<<
simple dynamic output:
><script show>
	document.write("The current date/time is: "+(new Date())+"<br>");
	return "link to current user: [["+config.options.txtUserName+"]]\n";
</script>
dynamic output using 'place' to get size information for current tiddler:
><script show>
	if (!window.story) window.story=window;
	var title=story.findContainingTiddler(place).getAttribute("tiddler");
	var size=store.getTiddlerText(title).length;
	return title+" is using "+size+" bytes";
</script>
dynamic output from an 'onclick' script, using {{{document.write()}}} and/or {{{return "..."}}}
><script label="click here" show>
	document.write("<br>The current date/time is: "+(new Date())+"<br>");
	return "link to current user: [["+config.options.txtUserName+"]]\n";
</script>
creating an 'onclick' button/link that accesses the link text AND the containing tiddler:
><script label="click here" title="clicking this link will show an 'alert' box" key="H" show>
	if (!window.story) window.story=window;
	var txt=place.firstChild.data;
	var tid=story.findContainingTiddler(place).getAttribute('tiddler');
	alert('Hello World!\nlinktext='+txt+'\ntiddler='+tid);
</script>
dynamically setting onclick link text based on stateful information:
>{{block{
{{{
<script label="click here">
	/* toggle "txtSomething" value */
	var on=(config.txtSomething=="ON");
	place.innerHTML=on?"enable":"disable";
	config.txtSomething=on?"OFF":"ON";
	return "\nThe current value is: "+config.txtSomething;
</script><script>
	/* initialize onclick link text based on current "txtSomething" value */
	var on=(config.txtSomething=="ON");
	place.lastChild.previousSibling.innerHTML=on?"disable":"enable";
</script>
}}}
<script label="click here">
	/* toggle "txtSomething" value */
	var on=(config.txtSomething=="ON");
	place.innerHTML=on?"enable":"disable";
	config.txtSomething=on?"OFF":"ON";
	return "\nThe current value is: "+config.txtSomething;
</script><script>
	/* initialize onclick link text based on current "txtSomething" value */
	var on=(config.txtSomething=="ON");
	place.lastChild.innerHTML=on?"enable":"disable";
</script>
}}}
loading a script from a source url:
>http://www.TiddlyTools.com/demo.js contains:
>>{{{function inlineJavascriptDemo() { alert('Hello from demo.js!!') } }}}
>>{{{displayMessage('InlineJavascriptPlugin: demo.js has been loaded');}}}
>note: When using this example on your local system, you will need to download the external script file from the above URL and install it into the same directory as your document.
>
><script src="demo.js" show>
	return "inlineJavascriptDemo() function has been defined"
</script>
><script label="click to invoke inlineJavascriptDemo()" key="D" show>
	inlineJavascriptDemo();
</script>
<<<
!!!!!Revisions
<<<
2010.12.15 1.9.6 allow (but ignore) type="..." syntax
2009.04.11 1.9.5 pass current tiddler object into wrapper code so it can be referenced from within 'onclick' scripts
2009.02.26 1.9.4 in $(), handle leading '#' on ID for compatibility with JQuery syntax
2008.06.11 1.9.3 added $(...) function as 'shorthand' for document.getElementById()
2008.03.03 1.9.2 corrected fallback declaration of wikifyPlainText() (fixes Safari "parse error")
2008.02.23 1.9.1 in onclick function, use string instead of array for 'bufferedHTML' (fixes IE errors)
2008.02.21 1.9.0 output from 'onclick' scripts (return value or document.write() calls) are now buffered and rendered into into a span following the script.  Also, added default 'return false' handling if no return value provided (prevents HREF from being triggered -- return TRUE to allow HREF to be processed).  Thanks to Xavier Verges for suggestion and preliminary code.
2008.02.14 1.8.1 added backward-compatibility for use of wikifyPlainText() in TW2.1.3 and earlier
2008.01.08 [*.*.*] plugin size reduction: documentation moved to ...Info tiddler
2007.12.28 1.8.0 added support for key="X" syntax to specify custom access key definitions
2007.12.15 1.7.0 autogenerate URI encoded HREF on links for onclick scripts.  Drag links to browser toolbar to create bookmarklets.  IMPORTANT NOTE: place is NOT defined when scripts are used as bookmarklets.  In addition, double-quotes will cause syntax errors.  Thanks to PaulReiber for debugging and brainstorming.
2007.11.26 1.6.2 when converting "document.write()" function calls in inline code, allow whitespace between "write" and "(" so that "document.write ( foobar )" is properly converted.
2007.11.16 1.6.1 when rendering "onclick scripts", pass label text through wikifyPlainText() to parse any embedded wiki-syntax to enable use of HTML entities or even TW macros to generate dynamic label text.
2007.02.19 1.6.0 added support for title="..." to specify mouseover tooltip when using an onclick (label="...") script
2006.10.16 1.5.2 add newline before closing '}' in 'function out_' wrapper.  Fixes error caused when last line of script is a comment.
2006.06.01 1.5.1 when calling wikify() on script return value, pass hightlightRegExp and tiddler params so macros that rely on these values can render properly
2006.04.19 1.5.0 added 'show' parameter to force display of javascript source code in tiddler output
2006.01.05 1.4.0 added support 'onclick' scripts.  When label="..." param is present, a button/link is created using the indicated label text, and the script is only executed when the button/link is clicked.  'place' value is set to match the clicked button/link element.
2005.12.13 1.3.1 when catching eval error in IE, e.description contains the error text, instead of e.toString().  Fixed error reporting so IE shows the correct response text.  Based on a suggestion by UdoBorkowski
2005.11.09 1.3.0 for 'inline' scripts (i.e., not scripts loaded with src="..."), automatically replace calls to 'document.write()' with 'place.innerHTML+=' so script output is directed into tiddler content.  Based on a suggestion by BradleyMeck
2005.11.08 1.2.0 handle loading of javascript from an external URL via src="..." syntax
2005.11.08 1.1.0 pass 'place' param into scripts to provide direct DOM access 
2005.11.08 1.0.0 initial release
<<<
/***
|Name|InlineJavascriptPlugin|
|Source|http://www.TiddlyTools.com/#InlineJavascriptPlugin|
|Documentation|http://www.TiddlyTools.com/#InlineJavascriptPluginInfo|
|Version|1.9.6|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|Insert Javascript executable code directly into your tiddler content.|
''Call directly into TW core utility routines, define new functions, calculate values, add dynamically-generated TiddlyWiki-formatted output'' into tiddler content, or perform any other programmatic actions each time the tiddler is rendered.
!!!!!Documentation
>see [[InlineJavascriptPluginInfo]]
!!!!!Revisions
<<<
2010.12.15 1.9.6 allow (but ignore) type="..." syntax
|please see [[InlineJavascriptPluginInfo]] for additional revision details|
2005.11.08 1.0.0 initial release
<<<
!!!!!Code
***/
//{{{
version.extensions.InlineJavascriptPlugin= {major: 1, minor: 9, revision: 6, date: new Date(2010,12,15)};

config.formatters.push( {
	name: "inlineJavascript",
	match: "\\<script",
	lookahead: "\\<script(?: type=\\\"[^\\\"]*\\\")?(?: src=\\\"([^\\\"]*)\\\")?(?: label=\\\"([^\\\"]*)\\\")?(?: title=\\\"([^\\\"]*)\\\")?(?: key=\\\"([^\\\"]*)\\\")?( show)?\\>((?:.|\\n)*?)\\</script\\>",
	handler: function(w) {
		var lookaheadRegExp = new RegExp(this.lookahead,"mg");
		lookaheadRegExp.lastIndex = w.matchStart;
		var lookaheadMatch = lookaheadRegExp.exec(w.source)
		if(lookaheadMatch && lookaheadMatch.index == w.matchStart) {
			var src=lookaheadMatch[1];
			var label=lookaheadMatch[2];
			var tip=lookaheadMatch[3];
			var key=lookaheadMatch[4];
			var show=lookaheadMatch[5];
			var code=lookaheadMatch[6];
			if (src) { // external script library
				var script = document.createElement("script"); script.src = src;
				document.body.appendChild(script); document.body.removeChild(script);
			}
			if (code) { // inline code
				if (show) // display source in tiddler
					wikify("{{{\n"+lookaheadMatch[0]+"\n}}}\n",w.output);
				if (label) { // create 'onclick' command link
					var link=createTiddlyElement(w.output,"a",null,"tiddlyLinkExisting",wikifyPlainText(label));
					var fixup=code.replace(/document.write\s*\(/gi,'place.bufferedHTML+=(');
					link.code="function _out(place,tiddler){"+fixup+"\n};_out(this,this.tiddler);"
					link.tiddler=w.tiddler;
					link.onclick=function(){
						this.bufferedHTML="";
						try{ var r=eval(this.code);
							if(this.bufferedHTML.length || (typeof(r)==="string")&&r.length)
								var s=this.parentNode.insertBefore(document.createElement("span"),this.nextSibling);
							if(this.bufferedHTML.length)
								s.innerHTML=this.bufferedHTML;
							if((typeof(r)==="string")&&r.length) {
								wikify(r,s,null,this.tiddler);
								return false;
							} else return r!==undefined?r:false;
						} catch(e){alert(e.description||e.toString());return false;}
					};
					link.setAttribute("title",tip||"");
					var URIcode='javascript:void(eval(decodeURIComponent(%22(function(){try{';
					URIcode+=encodeURIComponent(encodeURIComponent(code.replace(/\n/g,' ')));
					URIcode+='}catch(e){alert(e.description||e.toString())}})()%22)))';
					link.setAttribute("href",URIcode);
					link.style.cursor="pointer";
					if (key) link.accessKey=key.substr(0,1); // single character only
				}
				else { // run script immediately
					var fixup=code.replace(/document.write\s*\(/gi,'place.innerHTML+=(');
					var c="function _out(place,tiddler){"+fixup+"\n};_out(w.output,w.tiddler);";
					try	 { var out=eval(c); }
					catch(e) { out=e.description?e.description:e.toString(); }
					if (out && out.length) wikify(out,w.output,w.highlightRegExp,w.tiddler);
				}
			}
			w.nextMatch = lookaheadMatch.index + lookaheadMatch[0].length;
		}
	}
} )
//}}}

// // Backward-compatibility for TW2.1.x and earlier
//{{{
if (typeof(wikifyPlainText)=="undefined") window.wikifyPlainText=function(text,limit,tiddler) {
	if(limit > 0) text = text.substr(0,limit);
	var wikifier = new Wikifier(text,formatter,null,tiddler);
	return wikifier.wikifyPlain();
}
//}}}

// // GLOBAL FUNCTION: $(...) -- 'shorthand' convenience syntax for document.getElementById()
//{{{
if (typeof($)=='undefined') { function $(id) { return document.getElementById(id.replace(/^#/,'')); } }
//}}}
in reply to [[TiddlyWiki WishList]]@developers:

!Context menu in tiddler edit box
#Context menu in tiddler edit box with list of text templates to 
##insert in current caret position 
##surround selected text (with token substitution)
## The items of the menu came from a configuration tiddler like :
|Menu item|~Sub-Item|Command to insert|h
|Insert|||
|~|Image|{{{[img[XXXXXXX]]}}}|
|~|Quote|{{{<<quote 'Text to display' 'Tiddler name' [open]>>}}}|
|...|...|{{{...}}}|

*References
** [[RightContext v0.2.5|http://www.harelmalka.com/?p=60]] : A REAL JavaScript Context Menu – Supercharged and on Anabolic Steroids! 
** [[WikiBar|http://aiddlywiki.sourceforge.net/wikibar_demo_2.html]] - not working. To check. Seems to point in the right direction.
----
@@color:#c4d6ed; ^^
Description: A wish list for ~TiddlySpace plugins, macros and functionality. 
^^@@
/***
|''Name''|TiddlySpaceInitialization|
|''Version''|0.7.3|
|''Description''|Initializes new TiddlySpaces the first time they are created|
|''Status''|@@beta@@|
|''Source''|http://github.com/TiddlySpace/tiddlyspace/blob/master/src/plugins/TiddlySpaceInit.js|
|''CoreVersion''|2.6.1|
|''Requires''|TiddlySpaceConfig RandomColorPalettePlugin chrjs ImageMacroPlugin|
!TODO
* robust error notification and recovery
!MarkupPreHead
<!--{{{-->
<link href="/bags/%0_public/tiddlers.atom" rel="alternate"
	type="application/atom+xml" title="%0's public feed" />
<link rel="canonical" href="%1/" />
<!--}}}-->
!Code
***/
//{{{
(function($) {

var versionField = "tiddlyspaceinit_version";
var markupPreHead = store.getTiddlerText(tiddler.title + "##MarkupPreHead", "");
var tiddlyspace = config.extensions.tiddlyspace;
var currentSpace = tiddlyspace.currentSpace;
var tweb = config.extensions.tiddlyweb;

var plugin = config.extensions.TiddlySpaceInit = {
	version: "0.6",
	SiteTitle: "%0",
	SiteSubtitle: "a TiddlySpace",
	flagTitle: "%0SetupFlag",
	flagWarning: "Please do not modify this tiddler; it was created " +
		"automatically upon space creation.",

	dispatch: function(ev) {
		var title = plugin.flagTitle.format([currentSpace.name]);
		config.annotations[title] = plugin.flagWarning;
		if(currentSpace.type != "private") {
			return;
		}
		var tiddlers = [];
		var tid = store.getTiddler(title);
		if(tid) {
			curVersion = parseFloat(tid.fields[versionField]);
			reqVersion = parseFloat(plugin.version);
			if(curVersion < reqVersion) {
				plugin.update(curVersion, tid);
				tid.fields[versionField] = plugin.version;
				tid.incChangeCount();
				tid = store.saveTiddler(tid);
				tiddlers.push(tid);
			}
		} else { // first run
			tid = new Tiddler(title);
			tid.tags = ["excludeLists", "excludeSearch", "excludePublisher"];
			tid.fields = $.extend({}, config.defaultCustomFields);
			tid.fields[versionField] = plugin.version;
			tid.text = "@@%0@@".format([plugin.flagWarning]);
			tid = store.saveTiddler(tid);
			tiddlers = tiddlers.concat(plugin.firstRun(), tid);
		}
		autoSaveChanges(null, tiddlers);
	},
	update: function(curVersion, flagTiddler) {
		if(curVersion < 0.2) {
			this.createAvatar();
		}
		if(curVersion < 0.3) {
			flagTiddler.tags.pushUnique("excludePublisher"); // XXX: never persisted
		}
		if(curVersion < 0.5) { // v0.4 was faulty
			this.setupMarkupPreHead();
		}
		if(curVersion < 0.6) {
			this.purgeSystemSettings();
		}
	},
	pubTid: {
		tags: ["excludeLists", "excludeSearch"],
		fields: $.extend({}, config.defaultCustomFields, {
			"server.workspace": tiddlyspace.getCurrentWorkspace("public")
		})
	},
	makeTiddlerIfNot: function(tiddler) {
		if (!store.tiddlerExists(tiddler.title)) {
			$.extend(true, tiddler, plugin.pubTid);
			return [store.saveTiddler(tiddler)];
		} else {
			return [];
		}
	},
	firstRun: function() {
		var tiddlers = [];
		// generate Site*itle
		$.each(["SiteTitle", "SiteSubtitle"], function(i, item) {
			var tid = new Tiddler(item);
			tid.text = plugin[item].format([currentSpace.name]);
			tiddlers.push.apply(tiddlers,
				plugin.makeTiddlerIfNot(tid));
		});
		// generate public ColorPalette
		var tid = new Tiddler("ColorPalette");
		tid.text = config.macros.RandomColorPalette.generatePalette({
			saturation_pale: 0.67, saturation_light: 0.53,
			saturation_mid: 0.43, saturation_dark: 0.06,
			pale: 0.99, light: 0.85, mid: 0.5, dark: 0.31
		},
			false);
		tiddlers.push.apply(tiddlers, plugin.makeTiddlerIfNot(tid));
		this.createAvatar();
		this.setupMarkupPreHead();
		return tiddlers;
	},
	// remove _cookie slices (TiddlyWiki 2.6.2 beta 6 remnants)
	purgeSystemSettings: function() {
		var ss = store.getTiddler("SystemSettings");
		if(ss) {
			var lines = ss.text.split("\n");
			var persistentOptions = $.grep(lines, function(line, i) {
				return line.indexOf("_cookie:") == -1;
			});
			ss.text = persistentOptions.join("\n");
			ss = store.saveTiddler(ss);
			autoSaveChanges(null, [ss]);
		}
	},
	createAvatar: function() {
		var avatar = "SiteIcon";
		var host = tweb.host;
		var notify = function(xhr, error, exc) {
			displayMessage("ERROR: could not create avatar - " + // TODO: i18n
				"%0: %1".format([xhr.statusText, xhr.responseText]));
			// TODO: resolve!?
		};

		var pubBag = tiddlyspace.getCurrentBag("public");
		var tid = new tiddlyweb.Tiddler(avatar);
		tid.bag = new tiddlyweb.Bag(pubBag, host);

		var callback = function(data, status, xhr) {}; // avatar already exists; do nothing
		var errback = function(xhr, error, exc) {
			if(xhr.status != 404) {
				return;
			}
			// copy default avatar
			var _notify = function(tid, status, xhr) {
				displayMessage("created avatar"); // TODO: i18n
				var image = config.macros.image;
				if(image && image.refreshImage) {
					var uri = "/%0/tiddlers/SiteIcon".
						format(tiddlyspace.getCurrentWorkspace("public"));
					image.refreshImage(uri);
					image.refreshImage("SiteIcon");
				}
			};
			var _callback = function(tid, status, xhr) {
				tid.title = avatar;
				tid.bag.name = pubBag;
				delete tid.etag;
				tid.put(_notify, notify); // TODO: add to current session document (via adaptor?)
			};
			tweb.getUserInfo(function(user) {
				var avatarTitle = currentSpace.name == user.name ?
					"defaultUserIcon" : "defaultSiteIcon";
				var tid = new tiddlyweb.Tiddler(avatarTitle);
				tid.bag = new tiddlyweb.Bag("common", host);
				tid.get(_callback, notify);
			});
		};
		tid.get(callback, errback);
	},
	savePublicTiddlerText: function(title, text, pubWorkspace) {
		var tid = new Tiddler(title);
		tid.text = text;
		tid.tags = ["excludeLists"];
		tid.fields = $.extend({}, config.defaultCustomFields);
		tid.fields["server.workspace"] = pubWorkspace;
		tid.fields["server.page.revision"] = "false";
		tid = store.saveTiddler(tid);
		autoSaveChanges(null, [tid]);
	},
	setupMarkupPreHead: function() {
		var pubWorkspace = tiddlyspace.getCurrentWorkspace("public");
		var existing = store.getTiddler("MarkupPreHead");
		if(!existing || existing.fields["server.workspace"] != pubWorkspace) {
			var context = this;
			tweb.getStatus(function(status) {
				var text = markupPreHead.format(currentSpace.name,
					tiddlyspace.getHost(status.server_host, currentSpace.name));
				context.savePublicTiddlerText("MarkupPreHead", text,
					pubWorkspace);
			});
		}
		// also set up DefaultTiddlers
		var title = "DefaultTiddlers";
		existing = store.getTiddler(title) || new Tiddler(title);
		if(existing.fields["server.workspace"] != pubWorkspace) {
			var text = existing.text || store.getShadowTiddlerText(title);
			this.savePublicTiddlerText(title, text, pubWorkspace);
		}
	}
};

$(document).bind("startup", plugin.dispatch);

})(jQuery);
//}}}
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
Graphical User Interface
----
/%
@@color:#c4d6ed; ^^
Description: Graphical User Interface
^^@@
%/
This page is a personal collection of software tools I find particularly interesting or useful. 

!! <html><a name="InformationManagement" /></html> Information management
* [img[https://dl.dropbox.com/s/x5pa51wewk8ymr8/TiddlyWiki.png?dl=1]] [[TiddlyWiki|http://www.tiddlywiki.com/]] - a reusable non-linear personal web notebook. ~TiddlyWiki is written in HTML, CSS and ~JavaScript to run on any reasonably modern browser without needing any ~ServerSide logic. It allows anyone to create personal ~SelfContained hypertext documents that can be published to a ~WebServer, sent by email, stored in a ~DropBox or kept on a USB thumb drive to make a ~WikiOnAStick. Because it doesn't need to be installed and configured it makes a great ~GuerillaWiki.
* [img[http://frontpage.tiddlyspace.com/bags/frontpage_public/tiddlers/shinyspace.png]] [[TiddlySpace|http://tiddlyspace.com/]] - ~TiddlySpace builds on the tried and tested tiddler model introduced by ~TiddlyWiki by moving tiddlers to the web.
* [img(150px+,+)[http://freemind.sourceforge.net/wiki/images/thumb/c/c8/FreeMind-computer-knowledge-080.png/800px-FreeMind-computer-knowledge-080.png]] [[Freemind|http://freemind.sourceforge.net/wiki/index.php/Main_Page]] - ~FreeMind is a premier free mind-mapping software written in Java. 

!! <html><a name="Online" /></html> Online Services
* [img(38px+,+)[https://dl.dropbox.com/s/e8oenx53kn8z392/dropbox_48x48.ico?dl=1]] [[Dropbox|https://www.dropbox.com]] - Dropbox is a free service that lets you bring all your photos, docs, and videos anywhere. 

!! <html><a name="Security" /></html> Security
* [img[http://www.safer-networking.org/images/icons/spybotsd32.gif]] [[Spybot-S&D|http://www.safer-networking.org/en/index.html]] - the free, fully functioning privacy and anti-malware software brought to you for over 10 years by ~Safer-Networking!
* [img[http://www.truecrypt.org/images/logo38px.gif]] [[TrueCrypt|http://www.truecrypt.org/]] - Free open-source disk encryption software for Windows 7/Vista/XP, Mac OS X, and Linux.
* [img(38px+,+)[http://keepass.info/images/plockb75.gif]] [[KeePass Password Safe|http://keepass.info/]] - the free, open source, light-weight and easy-to-use password manager.

!! <html><a name="SystemUtilities" /></html> System utilities
* [img[http://www.steffengerlach.de/freeware/_scnthumb.gif]] [[Scanner|http://www.steffengerlach.de/freeware/]] - This tool uses a sunburst chart to display the usage of your hard disk or other media. The chart shows all major files and folders from all directory levels at once. 

----
Emergent reuse concept is proposed by Adam Sroka, in a [[very interesting thread|http://tech.groups.yahoo.com/group/extremeprogramming/message/149980]], as a way to avoid effort waste on making reusable modules that are never reused. He says :
"//This last part isn't exactly "design for reuse." It is more like "emergent reuse" which seems to be the one sort of reuse that is rarely wasteful.//"

In the same thread a participant called timander37 added an [[interesting point|http://tech.groups.yahoo.com/group/extremeprogramming/message/150005]] :
//We tell our business people "The first time you have to pay for it to be coded, the second time you have to pay for it to be reusable, the third time it's free"//.

Vijay Narayanan also seems to point in the same direction on his interesting article [[Build for Use, then Refactor to Reuse|http://artofsoftwarereuse.com/2010/07/11/build-for-use-then-refactor-to-reuse/]].

Emergent reuse is seen as an agile alternative to "design for reuse" where you do not make an investment upfront to produce reusable assets but, instead, when the reuse opportunity emerges, and only then, you do invest towards reusability through refactoring and generalization.
This is indeed a quite good approach to reuse in a "project centric" organization. In fact, design for reuse in these kind of environments involves the risk of investing in a reusable module that, by one reason or another, will never be reused again.
We do propose that, at least part of the reuse effort, be performed in a way similar to our proposed [[Opportunistic Productization]]. The obstacles to this approach are, mainly, in the Reusable Software Asset Discovery area, that is, how do you assure that reuse opportunities are not wasted due to ignorance and lack of access to reusable assets? 

On the other hand one must consider how to produce reusable assets that feed the emergent reuse and that is also not an easy task. Emergent reuse can not start from the scratch, it needs some systematic reuse planning and some infrastructural conditions and reuse methodologies to be put in place.

One important consideration is that Emergent Reuse is discussed against "Design for Reuse" it does not mean that it is not a way of performing [[Systematic Reuse]], on the contrary, it is one of the management strategies that may be used to perform it.

In [[Implementing Systematic Reuse]] we point out some guidelines that may be useful in this endeavour.

----
@@color:#c4d6ed; ^^
Description: Emergent reuse vs. design for reuse concept discussion
^^@@
!!Macros
|Type|Name|Code|Description|h
|Information|Version|{{{<<version>>}}}|Displays ~TiddlyWiki version|
|Information|Timeline|{{{<<timeline (created|modified) 5>>}}}|Displays last X tiddlers created or modified|

!!Guides
* [[TiddlyWiki Guides|http://tiddlywikiguides.org/index.php?title=TiddlyWiki_Guides]] - This is one of two collaborative documentation projects for TiddlyWiki. 

!!Creating macros
* BibRefMacro

!!Interesting plugins
*[[SlideShowPlugin|http://www.math.ist.utl.pt/~psoares/addons.html#SlideShowPlugin]] - 	Creates a slide show from any number of tiddlers.
*[[LinkifyPlugin|http://linkify.tiddlyspot.com/#LinkifyPlugin]] - Automatically turns text into links, optionally using aliases.

!!How To
!!! Formating images
* [[TWHelp|http://twhelp.tiddlyspot.com/#FormattingImages]]

----
See also [[TiddlyWiki Wish List|TiddlyWiki WishList]]
----
/%
@@color:#c4d6ed; ^^
Description: TiddlyWiki related issues. 
^^@@
%/
Performance doesn't seem to be a fashionable theme anymore. It is, however, one of the major Customer satisfaction problems we face in projects and it is, for sure, an essential step towards excelence.

Don't be naive, performance will not "just happen". You will have to design for it, experiment and take every opportunity to optimize.

__​To address performance you first have to be able to measure it!__

This is a small tool to allow for quick assessement of .Net code relative performance.

* [[ASPerfBench-1.0.02.13.zip|https://dl.dropbox.com/s/qcjdr1uw5rwr425/ASPerfBench-1.0.02.13.zip?dl=1]]

<<Image "" "456" "ASPerfBench01.png" "https://dl.dropbox.com/" "s/smrackn9v91f1ff/" "?dl=1" "">>

<<Image "" "456" "ASPerfBench02.png" "https://dl.dropbox.com/" "s/k1v2tilye8i5bh0/" "?dl=1" "">>
----
/***
|''Name:''|TiddlySpaceLinkPlugin|
|''Description:''|Formatter to reference other spaces from wikitext |
|''Author:''|PaulDowney (psd (at) osmosoft (dot) com) |
|''Source:''|http://github.com/TiddlySpace/tiddlyspace/raw/master/src/plugins/TiddlySpaceLinkPlugin.js|
|''Version:''|1.4.2|
|''License:''|[[BSD License|http://www.opensource.org/licenses/bsd-license.php]] |
|''Comments:''|Please make comments at http://groups.google.co.uk/group/TiddlyWikiDev |
|''~CoreVersion:''|2.4|
!!Documentation
This plugin provides wikitext formatters for referencing another [[space|Space]] on the same TiddlySpace server, as in the following examples:
<<<
  {{{@space}}} -- @space 
  {{{~@space}}} -- ~@space 
  {{{Tiddler@space}}} -- Tiddler@space
  {{{[[Tiddler Title]]@space}}} -- [[Tiddler Title]]@space 
  {{{[[Link text|Tiddler Title]]@space}}} -- [[Link text|Tiddler Title]]@space
<<<
Links to tiddlers with a title begining with an "@" remain as tiddlyLinks:
<<<
  {{{[[@tiddler]]}}} -- [[@tiddler]]
<<<
and these may be changed into a space link using {{{@@}}}:
<<<
  {{{[[@@space]]}}} -- [[@@space]]
  {{{[[Link to an another space|@@space]]}}} -- [[Link to another space|@@space]]
  {{{[[@space|@@space]]}}} -- [[@space|@@space]]
<<<
TiddlySpace includes the [[TiddlySpaceLinkPlugin]] which provides WikiText markup for linking to other spaces on the same server. For example @glossary is a link to the {{{glossary}}} space and [[Small Trusted Group]]@glossary a link to an individual tiddler in the @glossary space. Prefixing the link with a tilde escapes the link, for example {{{~@space}}}.
Email addresses, for example joe.bloggs@example.com and mary@had.a.little.lamb.org should be unaffected.
!!Features
The plugin provides external links decorated so that other plugins may be included to add features such as the ability to dynamically pull externally linked tiddlers into the current TiddlyWiki.
Wikitext linking to a space on another server, for example from a tiddler in a space on tiddlyspace.com to a tiddler or a space on example.com, isn't currently supported. 
!!Code
***/
//{{{
/*jslint onevar: false nomen: false plusplus: false */
/*global jQuery config createTiddlyText createExternalLink createTiddlyLink */

function createSpaceLink(place, spaceName, title, alt, isBag) {
	var link, a, currentSpaceName, label;
	try {
		if (spaceName === config.extensions.tiddlyspace.currentSpace.name) {
			title = title || spaceName;
			a = createTiddlyLink(place, title, false);
			jQuery(a).text(alt || title);
			return a;
		}
	} catch (ex1) {
		currentSpaceName = false;
	}

	a = jQuery("<a />").addClass('tiddlySpaceLink externalLink').appendTo(place)[0];
	if(title) {
		jQuery(a).attr('tiddler', title);
	}
	if(isBag) {
		jQuery(a).attr('bag', spaceName);
	} else {
		jQuery(a).attr('tiddlyspace', spaceName);
	}

	config.extensions.tiddlyweb.getStatus(function(status) {
		link = status.server_host.url;
		if (title) {
			label = alt || title;
			link = link + "/" + encodeURIComponent(title);
		} else {
			label = alt || spaceName;
		}
		// assumes a http URI without user:pass@ prefix
		if(!isBag) {
			link = link.replace("http://", "http://" + spaceName.toLowerCase() + ".");
		} else {
			link += "/bags/" + spaceName + "/tiddlers.wiki";
		}
		jQuery(a).attr("href", link).text(label);
	});
	return a;
}

(function ($) {

	config.textPrimitives.spaceName = "[a-zA-Z][a-zA-Z0-9-]*[a-zA-Z0-9]";
	config.textPrimitives.spaceNameStrict = "[a-z][a-z0-9-]*";
	config.textPrimitives.bareTiddlerLetter = config.textPrimitives.anyLetterStrict;

	config.formatters.splice(0, 0, {
		name: "spacenameLink",
		match: config.textPrimitives.unWikiLink + "?" + config.textPrimitives.bareTiddlerLetter + "*@" + config.textPrimitives.spaceName + "\\.?.?",
		lookaheadRegExp: new RegExp(config.textPrimitives.unWikiLink + "?(" + config.textPrimitives.bareTiddlerLetter + "*)@(" + config.textPrimitives.spaceName + ")", "mg"),
		handler: function (w) {
			if (w.matchText.substr(w.matchText.length - 2, 1) === '.' && w.matchText.substr(w.matchText.length - 1, 1).match(/[a-zA-Z]/)) {
				w.outputText(w.output, w.matchStart, w.nextMatch);
				return;
			}
			if (w.matchText.substr(0, 1) === config.textPrimitives.unWikiLink) {
				w.outputText(w.output, w.matchStart + 1, w.nextMatch);
				return;
			}
			this.lookaheadRegExp.lastIndex = w.matchStart;
			var lookaheadMatch = this.lookaheadRegExp.exec(w.source);
			if (lookaheadMatch && lookaheadMatch.index === w.matchStart) {
				createSpaceLink(w.output, lookaheadMatch[2], lookaheadMatch[1]);
				w.nextMatch = this.lookaheadRegExp.lastIndex;
			}
		}
	},
	{
		name: "tiddlySpaceLink",
		match: "\\[\\[[^\\|\\]]*\\|*@@" + config.textPrimitives.spaceName + "\\]",
		lookaheadRegExp: new RegExp("\\[\\[(.*?)(?:\\|@@(.*?))?\\]\\]", "mg"),
		handler: function (w) {
			this.lookaheadRegExp.lastIndex = w.matchStart;
			var lookaheadMatch = this.lookaheadRegExp.exec(w.source);
			if (lookaheadMatch && lookaheadMatch.index === w.matchStart) {
				var alt = lookaheadMatch[2] ? lookaheadMatch[1] : lookaheadMatch[1].replace(/^@@/, "");
				var space = lookaheadMatch[2] || alt;
				createSpaceLink(w.output, space, "", alt);
				w.nextMatch = this.lookaheadRegExp.lastIndex;
			}
		}
	},
	{
		name: "tiddlyLinkSpacenameLink",
		match: "\\[\\[[^\\[]*\\]\\]@",
		lookaheadRegExp: new RegExp("\\[\\[(.*?)(?:\\|(.*?))?\\]\\]@(" + config.textPrimitives.spaceName + ")", "mg"),
		handler: function (w) {
			this.lookaheadRegExp.lastIndex = w.matchStart;
			var lookaheadMatch = this.lookaheadRegExp.exec(w.source);
			if (lookaheadMatch && lookaheadMatch.index === w.matchStart) {
				var title = lookaheadMatch[2] || lookaheadMatch[1];
				var alt = lookaheadMatch[1] || lookaheadMatch[2];
				createSpaceLink(w.output, lookaheadMatch[3], title, alt);
				w.nextMatch = this.lookaheadRegExp.lastIndex;
			}
		}
	});

	// ensure space links don't appear as missing links
	config.textPrimitives.brackettedLink = "\\[\\[([^\\]][^@\\]][^\\]]*)\\]\\](?=[^@])";
	config.textPrimitives.titledBrackettedLink = "\\[\\[([^\\[\\]\\|]+)\\|([^\\[\\]\\|]+)\\]\\](?=[^@])";

	// reevaluate derrived expressions ..
	config.textPrimitives.tiddlerForcedLinkRegExp = new RegExp("(?:" + config.textPrimitives.titledBrackettedLink + ")|(?:" +
		config.textPrimitives.brackettedLink + ")|(?:" +
		config.textPrimitives.urlPattern + ")","mg");
	config.textPrimitives.tiddlerAnyLinkRegExp = new RegExp("("+ config.textPrimitives.wikiLink + ")|(?:" +
		config.textPrimitives.titledBrackettedLink + ")|(?:" +
		config.textPrimitives.brackettedLink + ")|(?:" +
		config.textPrimitives.urlPattern + ")","mg");

	// treat space links in titledBracketedLink as external links
	var missingTiddlySpaceLink = new RegExp("^@@" + config.textPrimitives.spaceName + "$", "");
	var isExternalLink = config.formatterHelpers.isExternalLink;
	config.formatterHelpers.isExternalLink = function(link) {
		return missingTiddlySpaceLink.test(link) || isExternalLink(link);
	};

}(jQuery));
//}}}
Tags are a very useful navigation and search mechanism in TiddlyWiki.
This space has several tags that group and categorize subjects.
When you open a tiddler its list of tags is in the upper right corner. You may click each tag to see a list of tiddlers tagged with it.

|Type|Tag|Description|h
|Generic|<<tag System>>|Support, configuration and functionality tiddlers for this space. You will only be interested in them if you want to know more about how TiddlyWiki and TiddlySpace work and how some functionality is made in this space.|
|~|<<tag Content>>|Main content of this site intended for visitors. All user content is tagged as such. Each subject in these tiddlers may, and most do, have other tags that further categorize its content|
|Subject|<<tag Acronym>>|Acronyms mainly from Software Engineering area|
|~|<<tag Concept>>|Software Engineering concepts with short descriptions and references.|
|~|<<tag Development>>|Software Development thoughts and tools.|
|~|<<tag EA>>|Sparx Enterprise Architect CASE tool usage guidelines and references.|
|~|<<tag Guideline>>|Software Engineering practical performance guidelines and detailed practical performance examples.|
|~|<<tag OOP>>|Software Engineering Object Oriented Programming or Principles|
|~|<<tag Quote>>|Software Engineering important citations from important people.|
|~|<<tag Reuse>>|Software Reuse concepts, guidelines and information|
|~|<<tag Requirements>>|Software Requirements concepts, guidelines and information|
|~|<<tag Tool>>|Software selected tools|
|System|<<tag systemConfig>>|Tags tiddlers that are treated as code providing additional functionality to TiddlyWiki|
|~|<<tag Reply>>|Tags tiddlers in this space that are replies to tiddlers in other spaces|
|~|<<tag excludeLists>>|Tags tiddlers that shall not appear in any list|

!Tagcloud
<<tagCloud>>

----
/%
@@color:#c4d6ed; ^^
Description: Tag policy used in this space
^^@@
%/
“//Continuous Integration is a software development practice where members of a team integrate their work frequently, usually each person integrates at least daily - leading to multiple integrations per day. Each integration is verified by an automated build (including test) to detect integration errors as quickly as possible.//”
[[Martin Fowler - Continuous Integration|http://martinfowler.com/articles/continuousIntegration.html]]

Continuous Integration is a major factor in team work and can prevent “snowball” integration errors and is also a major factor in preventing “broken” builds that affect everybody's work on a team. It is also used to integrate and automate other practices like [[Static Analysis]] or [[Unit Testing]].

Continuous Integration is one of the [[High Maturity Practices]] in [[Software Development]].
----
@@color:#c4d6ed; ^^
Description: Continuous Integration concept and references
^^@@
/***
|Name|SectionLinksPlugin|
|Source|http://www.TiddlyTools.com/#SectionLinksPlugin|
|Documentation|http://www.TiddlyTools.com/#SectionLinksPlugin|
|Version|1.4.2|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|allow tiddler sections in TiddlyLinks to be used as anchor points|
This plugin enhances tiddler links so that they can include section references that ''auto-scroll to the indicated section heading'' within a tiddler (i.e., similar to the 'anchor' behavior provided in HTML by {{{<a name="foo">}}} and {{{<a href="#foo">...</a>}}}).  The {{{<<tiddler>>}}} macro syntax has also be extended to allow section references without a tiddler name, so that transclusion of //hidden sections from the same tiddler// can be easily accomplished.  The plugin also adds a new macro, <<sectionTOC>> which can auto-generate and embed a 'Table of Contents' outline view into a tiddler to enable quick navigation to sections within that tiddler.
!!!Usage
<<<
!!!!~TiddlyLink syntax
You can link to a section of a tiddler by adding the "##sectionname" syntax to the tiddlername:
{{{
[[SomeTiddler##SomeSection]]
}}}
When clicked, the tiddler is displayed and the specified section heading is automatically scrolled into view. If the tiddler title is omitted or the 'here' keyword is used, e.g.,
{{{
[[##SomeSection]] or [[here##SomeSection]]>>
}}}
then the current containing tiddler is implied by default.
!!!!HTML anchor syntax
You can use HTML syntax to create a scrollable 'anchor' location within a tiddler without use of the standard TW section heading syntax:
{{{
<html><a name="sectionname" /></html>
}}}
You can then link to that section using the enhanced TiddlyLink syntax as above.
!!!!{{{<<tiddler>>}}} macro 
The {{{<<tiddler>>}}} syntax has been extended so that when the tiddler title is omitted or the 'here' keyword is used, e.g.,
{{{
<<tiddler ##SomeSection>> or <<tiddler here##SomeSection>>
}}}
then the current containing tiddler is implied by default.
!!!!"""<<sectionTOC>>""" macro
This macro generates a 'Table of Contents' outline-style bullet list with links to all sections within the current tiddler.  Simply place the following macro at the //end of the tiddler content// (i.e., following all section headings).  Important note: //''The {{{<<sectionTOC>>}}} macro must occur at the end of the tiddler in order to locate the rendered section headings that precede it.''//
{{{
<<sectionTOC>> or <<sectionTOC className>>
}}}
To position the macro's //output// within the tiddler, you must create a special 'target element' that uses a specific classname (default='sectionTOC'), like this:
{{{
{{sectionTOC{}}}
}}}
When the {{{<<sectionTOC>>}}} macro is rendered, it will find the matching 'sectionTOC'-classed element and writes it's output there.  You can also add the macro and/or target elements directly to the [[ViewTemplate]] definition, so that every tiddler can automatically display the table of contents:
{{{
<span class='sectionTOC'></span> <!-- target element -->
...
<span macro='sectionTOC'></span> <!-- must be at end of tiddler -->
}}}
<<<
!!!Configuration
<<<
You can change the {{{<<SectionTOC>>}}} output link format by adding the following statement to a tiddler tagged with <<tag systemConfig>>
{{{
config.macros.sectionTOC.linkFormat='[[%0|##%0]]';
}}}
The default value (shown above) produces a link to each section within the tiddler, using "%0" to insert the section name into the link.  You can add extra formatting to generate additional output to suit your purposes.  For example, if you have EditSectionPlugin installed, you could include a link that invokes that plugin's popup editor directly from each item in the TOC display, like this:
{{{
config.macros.sectionTOC.linkFormat='[[%0|##%0]] <<editSection [[##%0]] [[(edit)]]>>';
}}}
<<<
!!!Examples
<<<
links to sections defined by ''TW heading syntax'' (e.g, {{{!!!sectionname}}}):{{indent{
[[SectionLinksPlugin##onClickTiddlerLink]]
[[##onClickTiddlerLink]] //(current tiddler implied)//}}}
links to anchors defined by ''HTML syntax'' (e.g., {{{<html><a href="anchorname"></html>}}}):{{indent{
[[SectionLinksPlugin##sampleanchorlink]]
[[##sampleanchorlink]] //(current tiddler implied)//}}}
<<<
!!!Revisions
<<<
2011.12.21 1.4.2 refactor sectionTOCformat to permit customization
2011.02.08 1.4.1 in isExternalLink() hijack, strip section references before testing for external link
2010.08.09 1.4.0 in scrollToSection(), added support for using HTML <a name="..."> anchor elements
2009.08.21 1.3.4 added handling to ignore leading/trailing whitespace in section references
2009.08.21 1.3.3 in createTiddlyLink(), add tiddlyLinkNonExistingSection class if matching section is not found
2009.08.14 1.3.2 in createTiddlyLink(), don't override core value for ~TiddlyLink attribute
2009.08.02 1.3.1 in sectionTOC.handler(), trim leading/trailing whitespace from generated section links
2009.08.01 1.3.0 in scrollToSection(), apply 3-tier section matching (exact, startsWith, contains)
2009.07.06 1.2.2 fixed displayTiddler() hijack
2009.07.03 1.2.1 in {{{<<sectionTOC>>}}}, suppress output if target is not found
2009.06.02 1.2.0 added support for 'here' keyword in {{{[[here##section]]}}} links and {{{<<tiddler here##section>>}}} macro
2009.04.09 1.1.1 in sectionTOC macro, make target visible when TOC is rendered.
2009.01.18 1.1.0 added {{{<<sectionTOC>>}}} macro to generate numbered-bullet links to sections of current tiddler
2009.01.06 1.0.0 converted to stand-alone plugin
2008.10.14 0.0.0 initial release (as [[CoreTweaks]] #784 - http://trac.tiddlywiki.org/ticket/784)
<<<
!!!Code
***/
//{{{
version.extensions.SectionLinksPlugin= {major: 1, minor: 4, revision: 2, date: new Date(2011,12,21)};

Story.prototype.scrollToSection = function(title,section) {
	if (!title||!section) return; var t=this.getTiddler(title); if (!t) return null;
	var elems=t.getElementsByTagName('*');
	var heads=[]; var anchors=[];
	for (var i=0; i<elems.length; i++)
		if (['H1','H2','H3','H4','H5'].contains(elems[i].nodeName)) heads.push(elems[i]);
	for (var i=0; i<elems.length; i++)
		if (elems[i].nodeName=='A' && (elems[i].getAttribute('name')||'').length) anchors.push(elems[i]);
	var found=null;
	for (var i=0; i<heads.length; i++)
		if (getPlainText(heads[i]).trim()==section) { found=heads[i]; break; }
	if (!found) for (var i=0; i<heads.length; i++)
		if (getPlainText(heads[i]).trim().startsWith(section)) { found=heads[i]; break; }
	if (!found) for (var i=0; i<heads.length; i++)
		if (getPlainText(heads[i]).trim().indexOf(section)!=-1) { found=heads[i]; break; }
	if (!found) for (var i=0; i<anchors.length; i++)
		if (anchors[i].getAttribute('name')==section) { found=anchors[i]; break; }
	if (!found) for (var i=0; i<anchors.length; i++)
		if (anchors[i].getAttribute('name').startsWith(section)) { found=anchors[i]; break; }
	if (!found) for (var i=0; i<anchors.length; i++)
		if (anchors[i].getAttribute('name').indexOf(section)!=-1) { found=anchors[i]; break; }
	if (found) {
		// if section heading is collapsed, click to expand it - see [[FoldHeadingsPlugin]]
		if (hasClass(found,'foldable') && found.nextSibling.style.display=='none') found.onclick();
		// scroll *after* tiddler animation
		var delay=config.options.chkAnimate?config.animDuration+100:0;
		setTimeout('window.scrollTo('+findPosX(found)+','+findPosY(found)+')',delay);
		return found;
	}
}
//}}}
/***
!!!!core hijacks
***/
/***
!!!!!createTiddlyLink
***/
//{{{
// [[tiddlername##section]] and [[##section]]
if (!window.createTiddlyLink_section)
	window.createTiddlyLink_section=window.createTiddlyLink;
window.createTiddlyLink=function(place,title) {
	var t=story.findContainingTiddler(place); var tid=t?t.getAttribute('tiddler'):'';
	var parts=title.split(config.textPrimitives.sectionSeparator);
	var title=parts[0]; var section=parts[1]; if (section) section=section.trim();
	if (!title.length || title.toLowerCase()=='here') title=tid;  // default=current tiddler
	arguments[1]=title;
	var btn=createTiddlyLink_section.apply(this,arguments);
	if (section) {
		btn.setAttribute('section',section);
		if (store.getTiddlerText(title+config.textPrimitives.sectionSeparator+section)===null)
			addClass(btn,'tiddlyLinkNonExistingSection');
	}
	return btn;
}
//}}}
/***
!!!!!onClickTiddlerLink
***/
//{{{
if (!window.onClickTiddlerLink_section)
	window.onClickTiddlerLink_section=window.onClickTiddlerLink;
window.onClickTiddlerLink=function(ev) {
	var e=ev||window.event;	var target=resolveTarget(e); var title=null;
	while (target!=null && title==null) {
		title=target.getAttribute('tiddlyLink');
		section=target.getAttribute('section');
		target=target.parentNode;
	} 
	var t=story.findContainingTiddler(target); var tid=t?t.getAttribute('tiddler'):'';
	if (title!=tid||!section) // avoid excess scrolling for intra-tiddler links
		onClickTiddlerLink_section.apply(this,arguments);
	story.scrollToSection(title,section);
	return false;
}
//}}}
/***
!!!!! displayTiddler
***/
//{{{
if (!Story.prototype.displayTiddler_section)
	Story.prototype.displayTiddler_section=Story.prototype.displayTiddler;
Story.prototype.displayTiddler = function(srcElement,tiddler)
{
	var title=(tiddler instanceof Tiddler)?tiddler.title:tiddler;
	var parts=title.split(config.textPrimitives.sectionSeparator);
	var title=parts[0]; var section=parts[1]; if (section) section=section.trim();
	if (!title.length || title.toLowerCase()=='here') {
		var t=story.findContainingTiddler(place);
		title=t?t.getAttribute('tiddler'):'';
	}
	arguments[1]=title;  // default=current tiddler
	this.displayTiddler_section.apply(this,arguments);
	story.scrollToSection(title,section);
}
//}}}
/***
<html><a name="sampleanchorlink" /></html>This is a sample ''anchor link'': {{{<html><a name="sampleanchorlink" /></html>}}}
!!!!!isExternalLink
***/
//{{{
if (!config.formatterHelpers.isExternalLink_section)
	config.formatterHelpers.isExternalLink_section=config.formatterHelpers.isExternalLink;
config.formatterHelpers.isExternalLink=function(link) {  // remove section references before testing
	var l=link.split(config.textPrimitives.sectionSeparator)[0];
	return config.formatterHelpers.isExternalLink_section(l);
}
//}}}
/***
!!!!!tiddler.handler
***/
//{{{
if (!config.macros.tiddler.handler_section)
	config.macros.tiddler.handler_section=config.macros.tiddler.handler;
config.macros.tiddler.handler=function(place,macroName,params,wikifier,paramString,tiddler)
{
	if (!params[0]) return;
	var sep=config.textPrimitives.sectionSeparator;
	var parts=params[0].split(sep); var tid=parts[0]; var sec=parts[1]; if (sec) sec=sec.trim();
	if ((tid.toLowerCase()=='here'||!tid.length) && sec) { // fixup for 'here##section' and '##section'
		var here=story.findContainingTiddler(place)
		var tid=here?here.getAttribute('tiddler'):tiddler?tiddler.title:'';
		arguments[2][0]=tid+sep+sec;
		arguments[4]=paramString.replace(new RegExp('(here)?'+sep+sec),tid+sep+sec);
	}
	config.macros.tiddler.handler_section.apply(this,arguments);
}
//}}}
/***
!!!!sectionTOC macro
***/
//{{{
config.macros.sectionTOC = {
	targetClass: 'sectionTOC',
	linkFormat: '[[%0|##%0]]',
	handler: function(place,macroName,params,wikifier,paramString,tiddler) {
		var out=[];
		var targetClass=params[0]||this.targetClass;
		var t=story.findContainingTiddler(place); if (!t) return;
		var elems=t.getElementsByTagName('*');
		var level=5; // topmost heading level
		for (var i=0; i<elems.length; i++) {
			var txt=getPlainText(elems[i]).trim();
			var link=this.linkFormat.format([txt]);
			switch(elems[i].nodeName) {
				case 'H1': out.push('#'+link);		level=1; break;
				case 'H2': out.push('##'+link);		level=level<2?level:2; break;
				case 'H3': out.push('###'+link);	level=level<3?level:3; break;
				case 'H4': out.push('####'+link);	level=level<4?level:4; break;
				case 'H5': out.push('#####'+link);	level=level<5?level:5; break;
				default: if (hasClass(elems[i],targetClass)) var target=elems[i];
			}
		}
		// trim excess bullet levels
		if (level>1) for (var i=0; i<out.length; i++) out[i]=out[i].substr(level-1);
		// show numbered list
		if (out.length && target) {
			if (target.style.display=='none') target.style.display='block';
			wikify(out.join('\n'),target);
		}
	}
}
//}}}
/***
!!!Invoke macro
{{{
<<sectionTOC>>
}}}
***/
// //<<sectionTOC>>
----
/%
@@color:#c4d6ed; ^^
Description: TODO
^^@@
%/
This is a list of various tips and tricks that may be useful when using [[EA|Sparx Enterprise Architect]].

{{tw_ttoc{}}}

!Connectors
!! Connecting to element's internal features
You can target a connector to an element's attribute or operation instead of the element as a whole. <<Image "FR" "300" "EATT_ConnIntFeat.PNG" "https://dl.dropbox.com/" "s/xlekxxy3e6rrghj/" "?dl=1" "Connecting to internal features.">>
# In a diagram
## Create a connector between two elements
## Invoke contextual menu on the connector
## Select "Link to Element Feature"
### Choose the type of Feature
### Choose the Feature
!! Highlight Connectors from/to Element
You can highlight the connectors targeting and originating from an Element
# In a diagram
## Select an Element
## Press 'L'
### Green connectors are outgoing
### Red connectors are incoming
!Import & Export
!! Creating elements by dragging text onto a diagram
You can create an element just by dragging some text from a document onto an EA diagram. The text is parsed to split title and content of the element.
!Shortcuts
!! Auto generate timestamp
You can generate the current date & time in the text of an Element's note
# In the notes textbox
## Press F5
----
<<TiddlerToC min-entries:1>>
/%
@@color:#c4d6ed; ^^
Description: Tips & tricks for EA usage
^^@@
%/
SMART stands for :
* ''Specific'' : A requirement must say exactly what is required.
* ''Measurable'' : In the context of Requirements Engineering, by measurable we mean is it possible, once the system has been constructed, to verify that this requirement has been met.
* ''Attainable'' : By an attainable requirement we mean it is possible physically for the system to exhibit that requirement under the given conditions.
* ''Realizable'' : in the context of software requirements, by realisable we mean is it possible to achieve this requirement given what is known about the constraints under which the system and the project must be developed. 
* ''Traceable'' : Requirements [[Traceability]] is the ability to trace (forwards and backwards) a requirement from its conception through its specification to its subsequent design, implementation and test.

These are characteristics a Software Requirement shall present to be considered as such. The concept was proposed by <<BibRef "Mannion,Keepence 1995">>.

----
See also : [[Software Requirement]] [[Writing Good Requirements]]
----
@@color:#c4d6ed; ^^
Description: SMART Requirements concept explanation and reference.
^^@@
//"The [[meta-architecture|http://www.bredemeyer.com/ArchitectingProcess/MetaArchitecture.htm]] collects together decisions relating to your architecture strategy. It sets direction for your architecture effort, with high-level decisions that will shape the architecture and guide the architects. These include architecture principles, statements of philosophy, metaphors and organizing concepts that will guide system decomposition and design of architectural mechanisms."//

Meta-architecture is a concept of [[VAP - Visual Architecting Process|http://www.bredemeyer.com/ArchitectingProcess/VisualArchitectingProcess.htm]] by Ruth Malan and Dana Bredemeyer.

Meta architecture harmonization and sharing is a key aspect of [[Implementing Systematic Reuse]] and it is also a main target and indicator of the Methodological stage in the Reuse Maturity Model. Meta-architectural matching is a primary indicator of reusability when accessing a potential reusable asset.
----
See also: [[Namespace and Filesystem Guidelines]] [[Namespace Coupling Guidelines]]
----
/%
@@color:#c4d6ed; ^^
Description: Meta-architecture concept explanation and references.
^^@@
%/
Software Requirements Specification
----
@@color:#c4d6ed; ^^
Description: Software Requirements Specification
^^@@
|~ViewToolbar|+editTiddler cloneTiddler closeOthers closeTiddler > fields refreshTiddler changeToPublic changeToPrivate syncing permalink references jump previousTiddler < |
|~EditToolbar|+saveTiddler saveDraft -cancelTiddler deleteTiddler|
|~RevisionToolbar|> fields revert|
----
@@color:#c4d6ed; ^^
Description: following http://confusedofcalcutta.tiddlyspace.com
^^@@
!Database programming

!!Keys
Record identification and ID generation and strategy is a major choice when designing a database.
!!!GUID
Global Unique Identifiers present some very attractive advantages to database keys but they have some drawbacks also.
Following are some worth reading articles on the subject :
|Author|Date|Title|Resume|h
|Jeremy Todd|2013|[[GUIDs as fast primary keys under multiple databases|http://www.codeproject.com/Articles/388157/GUIDs-as-fast-primary-keys-under-multiple-database]]|This article outlines an approach for using GUID values as primary keys/clustered indexes that avoids most of the normal disadvantages, adapting the COMB model for sequential GUIDs developed by Jimmy Nilsson in his article The Cost of GUIDs as Primary Keys.  While that basic model has been used by a variety of libraries and frameworks (including NHibernate), most implementations seem to be specific to Microsoft SQL Server.  This article attempts to adapt the approach into a flexible system that's can be used with other common database systems such as Oracle, PostgreSQL, and MySQL, and also addresses some of the eccentricities of the .NET Framework in particular.|
|Jimmy Nilsson|2002|[[The Cost of GUIDs as Primary Keys|http://www.informit.com/articles/article.aspx?p=25862]]|In this article, Jimmy Nilsson presents the pros and cons of using globally unique identifiers (GUIDs) as the datatype for primary keys in SQL Server 2000. In doing so, he shows you test results that hint of performance characteristics and introduces you to a special type of GUID that he invented, called COMBs, that solves what otherwise might give you a big throughput problem.|
|||||

----
@@color:#c4d6ed; ^^
Description: Database programming main page.
^^@@
iVBORw0KGgoAAAANSUhEUgAAACwAAAArCAYAAAADgWq5AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAN1wAADdcBQiibeAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAk5SURBVFiF1ZlrbBzVFYC/O7Mz+16/vc47tmM7sZOQB5QGAkqiqhE0VKAqrSgJjfiRqpX4UyFaqCLLotDSIrVCoghKSyqSliYgSgpNVSC4SWlSIIoJBGPjPByIE9sbr1/7mp2d2x9jz67j9dp50Krn1+zcO+d+99xzzzn3rpBS8v8kyv8a4HLFdbUKHtzZWqWr1g1SUeqRsh5ENWCCHBEwIpEREIdMQz/4+H03j1zteOJKXKJl9/5QSrq/IRD3AOuZ2UqZCPEelvyLnhFPN29bN3jZA3OZwC07Wz2Gy/oRiAcB76XtLpeKz+tDCDDNDKZpYqQN8gwxBDxpKdovf/rttdEvBPjhXW9/XcCvgOrxd7qmURWuIFxZQcDvR9e1Sd+ZpslAdJCB6CCRgSixWPxS8O2Pblm/55oBf3PvXrUuVf5rYPv4u1AwQG3NQirKShFCzHQsAPojF+k63c3wcNadpeDJi7HQA89sX52+KuAf7D3s9aZSfwJ5B4CmuairqWbunNlcJuck6e3r50R7J2nTHCMRhzO6edvPNn9l6IqAW559zWf4A28i5RqAgN/HqhXL8Ho8V0eaI4lkkrYPP3asLaHV7Y5sbN682Zjqmyl3t+H3PTUOW1pSzI3Xr7ymsABej4cbV6+gorwMAAHrUqnynQKmXL+8wD/e/fZ9SLENoLgoxOoVy3G5rjpk5wdQFK5b1khxUQgAAXc/tPvAD6fqP8klHtrVukhBHge8uq6x5kur8bjdXwhsrqTTaY68f4x4PAEQN4VoePyedZ9f2m+ShRXkDsZi7PKmJZcHKyVKdATX2V6UodHLAtY0jaVLGsZ/+lQpf56v3wQL7/j9gVpLFR2AGq6sYMWyxhkN5jrbi378JEpkCJE2s/y6i0xFCcaqejJVpTPSdfyjds739tlwyJt/smXDvyaMlftDquIhQAWorV4wrXKRNnEfPoHWcTZ/u2HiOtePqydCYmkJxopGFE8xBfYU9XU19PVHyFgWFuL7wARgx8J22pVRwDMT64q0ie/Ph1AG7aVXXCrBcAmeoA/N68aIJ0kOxxmMnKO34g2S3nP2dy4//tpteObcPqXuHCvH9Hissnn7Jic9OhY2NHkzEg9AVbiiICyA+912B9ZXEqSqcQEuj+60+0qDGJkROgJPk7QGnPfSjDHa8RTC5cMdXpdX96yqynFgv+H33wn8YbzN2XRCsmH8ubS4uCCs2hNB+/gMAN4iP3NX1k2AHZeuwX0O7OxZfpY1laFp9pCxT3+DzCTy6i8vK82GUSlvy21zgKUQ64Epi5hc0T86DYBQFMKNC/O6ZCx9gc9HDwFQUe7lyzeEqastYnmTnSQsY5BE90t59QshCPh942D1eYGFlNWAE8ALidpvV4T+8hC6L3/Y64i+jJQWAMuashFi/rwgRSF7NRKfvYKVupj3e59vrHoV1OYFllAEoE1jXRFLIuIpADxBX94+A8lO+uMfADBvboDiouykhIClY1aWmRTxU7vy6vD7HN1lLTtbHR9VAL777FGNsWShqWpBYGUkW89qvny1haQjuhcAVRE0LSklOpii7XiEtuMRTp4eIlzhJVxpWzB54Q3M0TOTtOS6ZVLPOEukAJR5Bh0/UF2Fga0iv/OcjiUntZ+PvcdwqhuA2poifF4Xf3/rM1au3cPKtXu4/wHbr5c2ltklqpTET/5ukp6MmXGePUIdngA8OmSMAhZAMjVlZQeA9LqR/jHrjMQmTkaafBp9BQBdV2mos1cyGMxaKxi0/bcopLNgXhAA4+JR0gNtE3Q5dTLQMxJ0amQF4Mn7b0shOAtceoTJK5lwCQCxyDDJ4Wz/7uG3SJj2JlpcX+yEsGAgG/JCwexz4+JSVNUOMbGu35J7+EunncNHIvckkhuHOwFi8emBjesWgSKQUnLh4zPIjEXainFqaD8Afr9GzcJstAkGtLzPHo9KXa29CuboKVK9B5y26KBj1E9zx86JErIdIB5PYOYsRz7JlBfZ0IARS9L97id09L2CadmTXbqkFEXJBudADmQoNDHB1C8qwu22903s1AtIy8Aw0oyMOu72Vl5gRbIPsK3W118QGCC1qp5M2N68sXQfPYl/AlBa4mHObP+EvrlWzXUJAJdLobHBdjEr2U/ys1e5GM05+Qv5Rl5g16lDrUAPwPkLfdMCoyjEN63BWFVPtOzfSDE5STjAOZC58OOycEHI2Zjx7j30X+gebzIMyzyYF7i5udmS8CLAQHSQkZEZFOCKQmyRJOY/CcCcWX7KSifHZp/X5bjIpRaGsWSyZCyZmHG0i/vsBsmuX2z96oRQNOHEoUr1OSAD0N7ZNT0wEOt6boxd0NQ4dZEe8NsWzA1xuTKrykdFuR0uy2nDSzSjWPKxS/tNAH5k663twDNg79ILvYV9OdX/DumhdgCqF4QcqHyyYnk5DXXFVFZMuuFyZNnYhAUW89l/7pHvbDhZEBhAdxs7kAwAfNLZRSI5OZsBIE3iXTsB0DSFJQ2FS9J/7L+Ttne+xfUrK6fsU1zsZt7cAAAB8fn8l3ZtvGla4ObNGwekkA8ApAyDo20fkk5PDnOJc38lk+gBoKGuGF2fOqWPxtIsvfFFwrXP8+rrpwtOrCknJCpCeWJaYIDHtmx4XiCeADvzHTv+EWZObpeWQfy0fQjweV3U1hQVhHjnyHlOtA8wPGLw4suF94bP62JRVt+al/94+x3TAgM8umXdgyBfAtufD7971Ikc5uAJZNq+XlrcUIKqFL5ou/Wm2dxy0yzmzPZz39bFBfuCvWJO4snI9bltU17nSJAtprLVcEkv8LV4IsGR94/RsKiGSjW7Gf2+6W+EvF4XB/9217T9xkXTFHRNIZnKIATzZgQM0LxtXVLAHQ/vbn0YKVssy1LbO7s45xbUoQAWxz6IUL0whK5fu79L+vsTJFO2C4qxomxcZnyhveOFAxssIZ4H5gNUi9cp5cQ1g5xCzohM+vq77n3TOUfN2CyPbN1wQHdH6oSU3wPOdsuN9Mi1pAl8EaASOCIVuSkXFq70T5m9e3UjVXEvyDsF1q06Q0Fh1/+FJK2SOuiRA69VqUda3SIyRYAHN+7Iprv3RfK1XRFwrrS0trpSZzM3IJRbBLISIYJIAgipC5QzlrA6sUSn5cm0TXe7PhO5auD/tvwHQhyDgtGxXlsAAAAASUVORK5CYII=
|SiteIcon SiteTitle SiteSubtitle||||StyleSheet|
|MainMenu|SiteUrl||PageTemplate|StyleSheetColors|
|~|DefaultTiddlers||EditTemplate|StyleSheetLayout|
|~|~||ViewTemplate|StyleSheetPrint|
|~|~|OptionsPanel|||
|~|~|AdvancedOptions|||
|~|~|SideBarTabs|||
|~|~|SideBarOptions|||
|~|~|~|||

* GettingStarted
* [[TiddlySpace Documentation|http://docs.tiddlyspace.com/]]

----
!Installed plugins
* TagCloudPlugin : present a 'cloud' of tags (or links) using proportional font display
* ImageSizePlugin : adds support for resizing images
* SectionLinksPlugin : allow tiddler sections in TiddlyLinks to be used as anchor points
* FullScreenPlugin : Toggle between viewing tiddlers fullscreen and normally. Very handy for when you need more viewing space.
* HoverMenuPlugin : Provides a hovering menu on the edge of the screen for commonly used commands, that scrolls with the page. Configured at HoverMenu .
* InlineJavascriptPlugin : Insert Javascript executable code directly into your tiddler content. With more information at InlineJavascriptPluginInfo .
* GotoPlugin : view any tiddler by entering it's title - displays list of possible matches.
* GATrackerPlugin : Google Analytics tracker
* TiddlerToCPlugin : Tiddler Table of Contents generator
* BreadcrumbsPlugin : list/jump to tiddlers viewed during this session plus "back" button/macro. With more information at BreadcrumbsPluginInfo
* QuotePlugin : Create a direct link to a tiddler using a normal button and a button that expands the specified tiddler inside the current tiddler.
* TiddlersBarPluginMP : A bar to switch between tiddlers through tabs (like browser tabs bar).
** StyleSheetTiddlersBar
** DisplayOptions
* SinglePageModePlugin - Show tiddlers one at a time with automatic permalink, or always open tiddlers at top/bottom of page.
** SinglePageModePluginInfo
* [[E.A.S.E]] - this framework allows you to easily create commands that work on the current tiddler text selection in edit mode.
** [[easyFormat]] - the format command format selection according to your choice.
** [[easyInsert]] - insert text template at caret position.
* [[TiddlyTagMindMap2Plugin]] - Create mind-maps from tags
** [[jit-yc]]
** [[MapNodeTemplate]]
** [[MindMapContent]]

!Installed Macros
* BibRefMacro - A TiddlyWiki Macro to create links to anchors in a bibliography tiddler.
* ImageMacro - A TiddlyWiki Macro to create configurable links to images.
* ContentTimelineMacro - A TiddlyWiki Macro to show timelines (modified, created) for tiddlers tagged 'Content'

!Installed Tweaks
* CoreTweaks - generic tweaks
** DefaultTiddlerText - Configure default new tiddler text
* HTML serialization - produces bag, receip
** HtmlJavascript - Call external javascript code on serializing

!!~TiddlyWiki tools
* [[TiddlyVault|http://tiddlyvault.tiddlyspot.com/]] - An index of ~TiddlyWiki extensions
* [[Tiddly Tools|http://www.tiddlytools.com]] 
* [[abegoExtensions|http://tiddlywiki.abego-software.de]] - UdoBorkowski's Extensions for TiddlyWiki

* [[Martin's wiki|http://www.martinswiki.com/]] - Martin Budden's plugins and extensions for TiddlyWiki 
----
@@color:#c4d6ed; ^^
Description: Administration functionality for this wiki. 
^^@@



/***
|Name|GATrackerPlugin|
|Description|Google Analytics tracker|
|Author|Julien Coloos|
|Version|1.2.0|
|Date|2011-05-18|
|Status|stable|
|Source|http://julien.coloos.free.fr/TiddlyWiki-dev/#GATrackerPlugin|
|License|[img[CC BY-SA 3.0|http://i.creativecommons.org/l/by-sa/3.0/80x15.png][http://creativecommons.org/licenses/by-sa/3.0/]]|
|CoreVersion|2.6.2|
|Documentation|http://julien.coloos.free.fr/TiddlyWiki-dev/#GATrackerPlugin|

!Description
This plugin enables Google Analytics tracking inside TiddlyWiki.

The version used is the asynchronous one ({{{ga.js}}}).
The plugin comes with its own configuration, which is stored persistently inside the (hidden) [[SystemSettings]] tiddler.
The configuration has to be set before being effective: it can be done in the plugin tiddler (see below) if TiddlyWiki is not in read-only mode. Tracking works if an account ID has been set, tracking has been enabled, and TiddlyWiki access is non-local.

Tracking can be reported as either:
* page views
** pages are named {{{/#Tiddler name}}}
* events
** Category: {{{Tiddlers}}}
** Action: {{{Open}}}, {{{Refresh}}}, {{{Edit}}}, {{{Search}}}, {{{Close}}} or {{{CloseAll}}}
** Label
*** for {{{CloseAll}}} action: excluded tiddler
*** for {{{Search}}} action: searched text
*** otherwise, tiddler name on which action is performed
** Value: for the {{{CloseAll}}} action, the number of closed tiddlers
** Note: Google Analytics script limits the number of events (1 every 5 seconds, with a burst limit of 10)
Tracking can be globally disabled, or enabled per action on each tiddler:
* //Open//: when tiddler was not yet displayed
** Note: default tiddlers do not trigger this action when accessing TiddlyWiki
* //Refresh//: when tiddler was already displayed
** Note: this action is automatically triggered after editing a tiddler
* //Edit//: when editing (or viewing in read-only mode) the tiddler
* //Close//: when tiddler was displayed
** this action is never tracked in //pages views// tracking
** the //CloseAll// action is triggered by the TiddyWiki links //close all// and //close others// if at least one tiddler was closed; individual tiddlers closed are not tracked as //Close// actions
* //Search//: when searching in tiddlers
** this action is never tracked in //pages views// tracking
** {{{CloseAll}}} and {{{Open}}} actions are not taken into account while search is performed: TiddlyWiki automically closes opened tiddlers before searching and opens tiddler that match the searched text


!Configuration
<<GATrackerConfig>>


!Revision History
!!v1.2.0 (2011-05-18)
Enhancements:
* do not trigger {{{CloseAll}}} and {{{Open}}} actions when search is performed
* added the {{{Search}}} action

!!v1.1.0 (2011-05-17)
Enhancements:
* do not trigger {{{Open}}} action when displaying default tiddlers
* added the {{{CloseAll}}} action

!!v1.0.0 (2011-05-14)
Initial release.


!Code
***/
//{{{
/* Google Analytics queue object. Needs to be global. */
var _gaq = _gaq || [];

if (!config.extensions.GATracker) {(function($) {

version.extensions.GATrackerPlugin = {major: 1, minor: 2, revision: 0, date: new Date(2011, 5, 18)};

/* Prepare overridden TiddlyWiki displaying */
var trackOptions = {};
var displayDefault = 0, closingAll = 0, searching = 0;
var pl = config.extensions.GATracker = {
getOption: function(optKey) {
	return (config.optionsSource && (config.optionsSource[optKey] == "setting")) ? config.options[optKey] : null;
},
setOption: function(optKey, value) {
	config.options[optKey] = value;
	config.optionsSource[optKey] = "setting";
	saveOption(optKey);
},
loadOptions: function() {
	var gaTrack = (pl.getOption("txt_GATracker_track") || "1,0,1,1,1,0,0").split(",");
	trackOptions = {
		id: pl.getOption("txt_GATracker_id"),
		enabled: parseInt(gaTrack[0] || "1"),
		type: parseInt(gaTrack[1] || "0"),
		events: {
			open: parseInt(gaTrack[2] || "1"),
			refresh: parseInt(gaTrack[3]) || "1",
			edit: parseInt(gaTrack[4] || "1"),
			close: parseInt(gaTrack[5] || "0"),
			search: parseInt(gaTrack[6] || "0")
		}
	};
	if (trackOptions.id && !trackOptions.id.length) {
		trackOptions.id = null;
	}
},
saveOptions: function() {
	var opts = trackOptions.enabled && "1" || "0";
	opts += "," + trackOptions.type;
	for (var ev in trackOptions.events) {
		opts += "," + (trackOptions.events[ev] && "1" || "0");
	}
	pl.setOption("txt_GATracker_id", trackOptions.id || "");
	pl.setOption("txt_GATracker_track", opts);
},
track: function() {
	_gaq.push.apply(_gaq, arguments);
},
trackAndDisplayDefaultTiddlers: function() {
	displayDefault = 1;
	try { pl.displayDefaultTiddlers.apply(this, arguments) } catch(e){};
	displayDefault = 0;
},
trackAndDisplayTiddler: function(srcElement, tiddler, template, animate, unused, customFields, toggle, animationSrc) {
	if (!displayDefault) {
		var trackEvent, title = (tiddler instanceof Tiddler) ? tiddler.title : tiddler;
		if (story.getTiddler(title)) {
			/* Tiddler is already displayed */
			if (toggle === true) {
				/* Closing tiddler: tracked in separate function */
			}
			else if (template === DEFAULT_EDIT_TEMPLATE) {
				if (trackOptions.events.edit) trackEvent = "Edit";
			}
			else if (trackOptions.events.refresh) trackEvent = "Refresh";
		}
		else if (trackOptions.events.open && !searching) trackEvent = "Open";

		if (trackEvent) pl.track(trackOptions.type ? ["_trackPageview", "/#" + title] : ["_trackEvent", "Tiddlers", trackEvent, title]);
	}
	pl.displayTiddler.apply(this, arguments);
},
trackAndCloseTiddler: function(title, animate, unused) {
	if (closingAll) closingAll++;
	else pl.track(["_trackEvent", "Tiddlers", "Close", title]);
	pl.closeTiddler.apply(this, arguments);
},
trackAndCloseAllTiddlers: function(excluded) {
	closingAll = 1;
	try { pl.closeAllTiddlers.apply(this, arguments) } catch(e){};
	if ((closingAll > 1) && !searching) pl.track(["_trackEvent", "Tiddlers", "CloseAll", excluded, closingAll - 1]);
	closingAll = 0;
},
trackAndSearch: function(text, useCaseSensitive, useRegExp) {
	if (!trackOptions.type && trackOptions.events.search) pl.track(["_trackEvent", "Tiddlers", "Search", text]);
	searching = 1;
	try { pl.search.apply(this, arguments) } catch(e){};
	searching = 0;
}
};

pl.loadOptions();

/* Only track in non-local mode */
var local = "file:" == document.location.protocol;
if (!local && trackOptions.id && trackOptions.enabled) {
	/* Insert script tag to load GA */
	$("head").eq(0).prepend($("<script/>").attr({type: "text/javascript", async: "true", src: ("https:" == document.location.protocol ? "https://ssl" : "http://www") + ".google-analytics.com/ga.js"}));

	/* Override TiddlyWiki display */
	pl.displayTiddler = story.displayTiddler;
	story.displayTiddler = pl.trackAndDisplayTiddler;
	pl.displayDefaultTiddlers = story.displayDefaultTiddlers;
	story.displayDefaultTiddlers = pl.trackAndDisplayDefaultTiddlers;
	if (!trackOptions.type && trackOptions.events.close) {
		pl.closeTiddler = story.closeTiddler;
		story.closeTiddler = pl.trackAndCloseTiddler;
		pl.closeAllTiddlers = story.closeAllTiddlers;
		story.closeAllTiddlers = pl.trackAndCloseAllTiddlers;
	}
	pl.search = story.search;
	story.search = pl.trackAndSearch;

	/* Initialize tracking */
	pl.track(["_setAccount", trackOptions.id], ["_trackPageview"]);
}

config.macros.GATrackerConfig = {
handler: function(place, macroName, params, wikifier, paramString, tiddler) {
	$(createTiddlyElement(place, "div")).html("Tracking status: <span style='color:" + (trackOptions.id && trackOptions.enabled ? "green'>enabled" : "red'>disabled") + "</span> and <span style='color:" + (local ? "red'>" : "green'>non-") + "local</span>");
	if (readOnly) {
		$(createTiddlyElement(place, "div")).html("Configuration is not available in read-only mode");
		return;
	}
	var formNode = $(createTiddlyElement(place, "div")).html("<div>Google Analytics plugin configuration:</div><table><tr><td>Account ID:</td><td><input id='ga_id' type='text'/></td></tr><tr><td>Tracking:</td><td><input id='ga_enabled' type='checkbox'/>Enabled<br/><br/>How: <select id='ga_track'><option value='0'>Events</option><option value='1'>Pages</option></select><br/><br/>What:<br/><input id='ga_track_open' type='checkbox'/>Open<br/><input id='ga_track_refresh' type='checkbox'/>Refresh<br/><input id='ga_track_edit' type='checkbox'/>Edit<br/><input id='ga_track_close' type='checkbox'/>Close<br/><input id='ga_track_search' type='checkbox'/>Search<br/></td></tr></table><input id='ga_action_submit' type='submit' value='Apply'/>");
	$("#ga_id", formNode).val(trackOptions.id);
	$("#ga_enabled", formNode)[0].checked = trackOptions.enabled;
	$("#ga_track option", formNode).eq(trackOptions.type)[0].selected = true;
	for (var ev in trackOptions.events) {
		$("#ga_track_" + ev, formNode)[0].checked = trackOptions.events[ev];
	}
	$("#ga_action_submit", formNode).click(function() {
		trackOptions.id = $("#ga_id", formNode).val();
		if (!trackOptions.id.length) trackOptions.id = null;
		trackOptions.enabled = $("#ga_enabled", formNode)[0].checked;
		trackOptions.type = parseInt($("#ga_track", formNode).val());
		for (var ev in trackOptions.events) {
			trackOptions.events[ev] = $("#ga_track_" + ev, formNode)[0].checked;
		}
		pl.saveOptions();

		var nodeDisplay = story.findContainingTiddler(place);
		var tiddlerDisplay;
		if (nodeDisplay) tiddlerDisplay = store.getTiddler(nodeDisplay.getAttribute("tiddler"));
		story.refreshTiddler(tiddlerDisplay ? tiddlerDisplay.title : tiddler.title, null, true);
	});
}
};

})(jQuery);}
//}}}
/***
|Name|TiddlerToCPlugin|
|Description|Tiddler Table of Contents generator|
|Author|Julien Coloos|
|Version|1.1.0|
|Date|2011-06-12|
|Status|stable|
|Source|http://julien.coloos.free.fr/TiddlyWiki-dev/#TiddlerToCPlugin|
|License|[img[CC BY-SA 3.0|http://i.creativecommons.org/l/by-sa/3.0/80x15.png][http://creativecommons.org/licenses/by-sa/3.0/]]|
|CoreVersion|2.6|
|Documentation|http://julien.coloos.free.fr/TiddlyWiki-dev/#TiddlerToCPlugin|

{{tw_ttoc{}}}
!Description
This plugin adds the {{{TiddlerToC}}} macro to generate a ~ToC inside a tiddler.
The generated ~ToC entries list the visible headings found in the tidder, each entry being preceded by a number representing its level and index (e.g.: //1.2.1//). Those numbers link to the corresponding heading.
Found headings are also altered to display a link back to the ~ToC.

The ~ToC does not reference tiddlers embedded using the {{{tiddler}}}, {{{slider}}} or {{{tabs}}} macro.

The ~ToC is either generated at a given target, or at the beginning of the place it was dropped in. If there are less headings than a given minimum (default being 2), the ~ToC is not displayed.
The ~ToC title can be clicked to hide/display the ~ToC content.


!Notes
The {{{TiddlerToC}}} macro searches for the HTML headings ({{{h1}}} to {{{h6}}} tags) in the place where it is inserted. Each heading is then converted to a ~ToC entry, preserving inner text format.
The macro thus has to be inserted at the end of the tiddler: content has been generated and the ~ToC can be populated.


!Usage
The {{{TiddlerToC}}} macro is intended to be inserted at the end of a tiddler.

By default the ~ToC is generated at the beginning of the place the macro was inserted in.
However a target can be used: if the place contains an element which class is {{{tw_ttoc}}}, this element will be replaced by the ~ToC.
Such an element can be generated by dropping one of the following inside the tiddler:
* using a ~TiddlyWiki macro
{{{
{{tw_ttoc{}}}
}}}
* inserting an explicit HTML tag; the advantage here is that attributes can be specified
{{{
<html><div class="tw_ttoc" min-entries="3"/></html>
}}}


The macro and/or target element can also be used in [[ViewTemplate]] to be applied to all tiddlers:
{{{
...
<!-- Wikified tiddler content -->
<div class='viewer' macro='view text wikified'>
	<!-- Insert ToC right before tiddler content -->
	<div class='tw_ttoc'></div>
</div>
<!-- ToC generator, to use at the end of the tiddler -->
<div macro='TiddlerToC min-entries:3'></div>
}}}

!!Parameters
The following parameters are available:
* {{{min-entries}}} (optional)
** minimum number of entries needed to display the ~ToC
** can be specified as macro parameter, and can be overridden in the target tag (needs explicit HTML tag; see before)
** default value is {{{2}}}

!!Examples
Without target:
{{{
Tiddler content.
...

<<TiddlerToC min-entries:3>>
}}}

With a target:
{{{
Beginning of the tiddler.
...

Where to generate the ToC:
{{tw_ttoc{}}}
Or, with a minimum number of entries specified:
<html><div class="tw_ttoc" min-entries="3"/></html>

Tiddler continues ...

<<TiddlerToC min-entries:3>>
}}}


!Styling
~ToC content uses some classes which style can be overriden using CSS. Those classes are:
* {{{tw_ttoc}}}: ~ToC
* {{{tw_ttoc_title}}}: title ({{{Table of Contents}}})
* {{{tw_ttoc_level}}}: sub-level entry indentation
* {{{tw_ttoc_entry}}}: entry
* {{{tw_ttoc_id}}}: entry number
* {{{tw_ttoc_top}}}: heading link back to the ~ToC

Default style can be found in the code below, and can be overridden in the [[StyleSheet]] tiddler.


!Revision History
!!v1.1.0 (2011-06-12)
Changes:
* by default, ~ToC is now displayed only if it contains more than one entry

Enhancements:
* added a macro parameter to give the minimum number of entries needed to display the ~ToC
** the parameter can be overridden in the ~ToC target

Fixes:
* do not list headings that are not //displayed//

!!v1.0.1 (2011-05-29)
Changes:
* if there is none, adds a {{{br}}} tag after the ~ToC

!!v1.0.0 (2011-05-28)
Initial release.


!Code
***/
//{{{
if (!config.macros.TiddlerToC) {(function($) {

version.extensions.TiddlerToCPlugin = {major: 1, minor: 1, revision: 0, date: new Date(2011, 6, 12)};

var hTag = /^h([1-6])$/i;

setStylesheet(".tw_ttoc {background-color: #F8F8F8; padding: 10px; border: 1px #CCCCCC solid;} .tw_ttoc_title {text-align:center; font-weight: bold; margin: 5px 0px 20px 0px;} .tw_ttoc_level {padding-left: 20px;} .tw_ttoc_id {margin-right: 6px;} .tw_ttoc_top {float: right; font-size: 0.5em;}", "TiddlerToCPlugin");

function cloneNodeWithEvents(node) {
	var clone = node.cloneNode(true);
	var n1 = [node].concat(Array.prototype.slice.call(node.getElementsByTagName('*')));
	var n2 = [clone].concat(Array.prototype.slice.call(clone.getElementsByTagName('*')));

	for (var i=0 ; i<n1.length ; i++) {
		for (var j in n1[i]) {
			if (j.substr(0,2) != "on") continue;
			n2[i][j] = n1[i][j];
		}
	}

	return clone;
}

var pl = config.macros.TiddlerToC = {
handler: function(place, macroName, params, wikifier, paramString, tiddler) {
	var namedParams = paramString.parseParams(null, null, true), paramMinEntries = getParam(namedParams, "min-entries"), minEntries = paramMinEntries ? parseInt(paramMinEntries) : 2;

	if ($(place).hasClass("viewer") || $(place).parents(".viewer").size()) pl.generate(place, minEntries);
	else {
		/* the macro is not used inside a tiddler content but probably in a template */
		var t = story.findContainingTiddler(place);
		if (!t) return;
		pl.generate(t, minEntries);
	}
},
getElements: function(place) {
	var els = $();

	$(place).children().each(function(i, n) {
		/* exclude embedded tiddlers */
		if ($(n).attr("tiddler") || $(n).hasClass("sliderPanel") || $(n).hasClass("tabsetWrapper")) return;
		/* include headings and ToC target */
		if (hTag.test(n.tagName) || $(n).is(".tw_ttoc")) els = els.add(n);
		/* recurse */
		els = els.add(pl.getElements(n));
	});

	return els;
},
generate: function(place, minEntries) {
	var els = pl.getElements(place);

	/* get ToC target, or insert it as first element */
	var toc = els.filter(".tw_ttoc");
	if (toc.size()) {
		if (toc.size() > 1) {
			/* More than one target; happens when using ViewTemplate while
			 * tiddler already contains a ToC target. In any case, it is best
			 * to keep the last one and remove others.
			 */
			toc.not(toc.last()).remove();
			toc = toc.last();
		}
		/* check the ToC was not already generated */
		if (toc[0].toc && toc[0].toc.generated) return;
		/* check if the minimum number of entries is overridden */
		if (toc.attr("min-entries")) minEntries = parseInt(toc.attr("min-entries"));
		/* rebuild target tag */
		toc = toc.empty().wrapInner("<div class='tw_ttoc'/>").children("div").unwrap();
	}
	else toc = $("<div class='tw_ttoc'/>").prependTo(place);

	var hLevelCurrent = 0, hLevel;
	var tocInner = $("<div/>"), listCurrent = tocInner[0], listId = "1";
	toc.hide().append($("<div class='tw_ttoc_title'><a href='javascript:;'>Table of Contents</a></div>"), tocInner);
	$(".tw_ttoc_title a", toc).click(function() {
		if (tocInner.is(":visible")) tocInner.hide("fast");
		else tocInner.show("fast");
	});

	var headings = $();
	els.each(function(i, c) {
		/* check we got a visible heading */
		var match = hTag.exec(c.tagName);
		if (!match || !$(c).is(":visible")) return;
		hLevel = parseInt(match[1]);

		/* check the heading level */
		if (!hLevelCurrent) hLevelCurrent = hLevel;
		if (hLevel < hLevelCurrent) {
			/* have to go up */
			while ((hLevel <= --hLevelCurrent) && listCurrent.parentNode) {
				listCurrent = listCurrent.parentNode.parentNode;
				ids = listId.split(".");
				ids.pop();
				listId = ids.join(".");
			}
		}
		else if (hLevel > hLevelCurrent) {
			/* have to go down */
			while (hLevel >= ++hLevelCurrent) {
				$(listCurrent.lastChild).append(listCurrent = $("<div class='tw_ttoc_level'/>")[0]);
				ids = listId.split(".");
				ids.push(1);
				listId = ids.join(".");
			}
		}
		/* determine this heading index */
		ids = listId.split(".");
		ids[ids.length-1] = $(listCurrent).children("div.tw_ttoc_entry").size() + 1;
		listId = ids.join(".");

		/* clone the heading content to insert it in the ToC */
		$(cloneNodeWithEvents(c)).wrapInner("<div class='tw_ttoc_entry'/>").children("div").unwrap().prepend($("<a class='tw_ttoc_id' href='javascript:;'/>").html(listId).click({target: c}, function(ev){window.scrollTo(0,findPosY(ev.data.target))})).appendTo(listCurrent);

		headings = headings.add(c);

		hLevelCurrent = hLevel;
	});
	toc[0].toc = {generated: true};

	if (headings.size() >= minEntries) {
		/* display ToC */
		/* Note: jQuery 'next' does not take into account text nodes */
		var sibling = toc.show()[0].nextSibling;
		if (sibling && (sibling.nodeName != "BR")) toc.after("<br/>");

		/* insert a 'ToC' link in the headings */
		headings.append($("<span class='tw_ttoc_top'><a href='javascript:;' title='Go to Table of Contents'>[ToC]</a></span>")).find(".tw_ttoc_top a").click(function() {window.scrollTo(0,findPosY(toc[0]))});
	}
}
};

})(jQuery);}
//}}}
/***
<<TiddlerToC>>
***/
Software development thoughts and more...
Traceability is the ability to trace (forwards and backwards) a modelling element from its conception through its specification to its subsequent design, implementation and test.
<<Image "FR" "413" "Traceability-Concretisation.png" "https://dl.dropbox.com/" "s/5dmf76e8aankguz/" "?dl=1" "Traceability and Concretisation">>
As a process, software development progresses through phases and, in each phase, a different level of information concretisation (and range) is achieved.
The diagram illustrates the main elements of each phase, their relationships and the concretisation traceability from Inception to Construction.
Pay attention that several other diagrams and elements may and shall be used, to detail and improve specification, like business models, use cases, state diagrams, etc. These auxiliary diagrams and elements, however, are not considered in our main traceability proposal.
For now we shall understand that traceability refers to the ability of locating related elements up in abstraction direction or down in concretisation direction or even horizontally as happens with test cases and tables.

As such a ''Requested [[Feature]]'' shall be traced (Abstraction) from one or more dependant ''Proposed Features''. A ''Requested Feature'' shall also be dependant from one or more ''Stakeholders'' (Customer person affected or/and with decision power over the feature).
''[[Requirements|Software Requirement]]'' shall trace (Abstraction) to features and shall also be associated with their correspondent ''Test Cases''. The architectural ''Components'' shall ''realize'' the requirements that, in that way, correspond to their responsibilities.
Composition of the ''Components'' shall be established by aggregation of the correspondent ''Classes'' that, in turn, shall trace their dependency from database ''Tables'' and establish their realizations of ''Interfaces''.

Notice that, although ''Interfaces'' and ''Tables'' appear at Construction level they may, and shall, be specified as soon as possible.

Traceability also implies unequivocal and ''unambiguous identification'' of each item. As Classes are naturally identified by namespace and name and Components and Tables are, usually, only identified by name, this means that you should number your Features, Requirements, Issues, Assumptions, Test Cases, and anything whose name is not unique in the system, in an unequivocal way. We strongly suggest to use hierarchical numbering with gaps and type prefixes. See [[Writing Good Requirements]] for more information on this.

<<Image "FL" "630" "ModelNavigability.png" "https://dl.dropbox.com/" "s/ycu8jb2frb5f3oz/" "?dl=1" "Model Navigability">>
When using a [[CASE]] tool like [[EA|Sparx Enterprise Architect]], traceability relationships are also a condition for ''model navigability''. This is essential if you want a minimum of productivity and efficiency in tool usage.

Proper relationships give us model navigability with simple follow link action. 
As you surely understand, the ability to locate information in a set as large as Software Specifications tend to be is crucial and can not be underestimated.



''Model Navigability'' is essential to :
* cope with information volume
* assess change impact and context
* assure coverage
* protect scope
----
''See also :''
* Additional recommended relationships in Requirements Diagrams : [[EA Usage - Requirements Diagram]]
----
!!Other references on the topic
* Rémy Fannader,  on [[Traceability|http://caminao.wordpress.com/system-engineering/project-management/traceability/]]
* Serge Thorn, on [[Redefining traceability in Enterprise Architecture and implementing the concept with TOGAF 9.1 and/or ArchiMate 2.0|http://sergethorn.blogspot.fr/2013/05/redefining-traceability-in-enterprise.html]]
----
@@color:#c4d6ed; ^^
Description: traceability concept explanation and usage guideline.
^^@@
----
@@color:#c4d6ed; ^^
Description: following http://ricardoperes.tiddlyspace.com
^^@@
/***
|''Name''|TiddlySpaceRevisionView|
|''Description''|Show tiddler revisions in a stack of cards view|
|''Author''|BenGillies|
|''Version''|0.2.0|
|''Status''|beta|
|''Source''|http://github.com/TiddlySpace/tiddlyspace|
|''CodeRepository''|http://github.com/TiddlySpace/tiddlyspace|
|''License''|[[BSD|http://www.opensource.org/licenses/bsd-license.php]]|
|''CoreVersion''|2.6.0|
|''Requires''|TiddlyWebAdaptor|
!Usage
The viewRevisions macro can be attached to any element, which should be passed
in as a parameter.

For example:

&lt;&lt;viewRevisions page:10 link:"<<view modified date>>"&gt;&gt;

would show the revisions "stack of cards" view, 10 at a time, when the modified
date is clicked.
!Code
***/
//{{{
(function($) {

var me = config.macros.viewRevisions = {
	revisionTemplate: "RevisionTemplate",
	revSuffix: " [rev. #%0]", // text to append to each tiddler title
	defaultPageSize: 5, // default number of revisions to show
	defaultLinkText: "View Revisions", // when there's nothing else to use
	offsetTop: 30, // in px
	offsetLeft: 10, // in px
	shiftDownDelay: 50, // in ms
	visibleSlideAmount: 20, // amount of revisions to show on left hand edge after sliding
	zIndex: 100, // default z-index
	handler: function(place, macroName, params, wikifier, paramString, tiddler) {
		params = paramString.parseParams(null, null, true)[0];
		var tiddlerElem = story.findContainingTiddler(place);

		var revButton;
		var pageSize = parseInt(params.page[0], 10) || me.defaultPageSize;
		var linkObj = params.link ? params.link[0] || me.defaultLinkText : false;
		if(linkObj) {
			revButton = $('<span class="button openRevisions" />')
				.appendTo(place);
			wikify(linkObj, revButton[0], null, tiddler);
		} else {
			revButton = place;
		}

		$(revButton).click(function() {
			if (!$(tiddlerElem).hasClass("revisions")) {
				me.showRevisions(tiddlerElem, tiddler, pageSize);
			} else {
				me.closeRevisions(tiddlerElem);
			}
		});
	},

	// initialisation for revision view
	showRevisions: function(tiddlerElem, tiddler, pageSize) {
		var context = {
			host: tiddler.fields["server.host"],
			workspace: tiddler.fields["server.workspace"]
		};
		$(tiddlerElem).addClass("revisions").attr("revName", tiddler.title);
		// ensure toolbar commands deactivate RevisionsView
		$("a", ".toolbar", tiddlerElem).each(function(index, btn) {
			var _onclick = btn.onclick;
			btn.onclick = function(e) {
				me.closeRevisions(tiddlerElem);
				_onclick.apply(this, arguments);
			};
		});
		// ensure default action deactivates RevisionsView
		var _ondblclick = tiddlerElem.ondblclick;
		tiddlerElem.ondblclick = function(e) {
			me.closeRevisions(tiddlerElem);
			_ondblclick.apply(this, arguments);
		};
		var type = tiddler.fields["server.type"];
		var adaptor = new config.adaptors[type]();
		var userParams = {
			tiddlerElem: tiddlerElem,
			pageSize: pageSize,
			title: tiddler.title
		};
		me.createCloak(tiddlerElem);
		adaptor.getTiddlerRevisionList(tiddler.title, null, context, userParams,
				function(context, userParams) {
					// strip the current revision
					context.revisions.shift();
					me.expandStack(context, userParams);
				});
	},

	// fetch the actual revision and put it in the tiddler div
	showRevision: function(place, revision, callback) {
		var context = {
			host: revision.fields["server.host"],
			workspace: revision.fields["server.workspace"]
		};
		var userParams = {
			revElem: place
		};
		var type = revision.fields["server.type"];
		var adaptor = new config.adaptors[type]();
		var revNo = revision.fields["server.page.revision"];
		adaptor.getTiddlerRevision(revision.title, revNo, context, userParams,
			function(context, userParams) {
				var tiddler = context.tiddler;
				tiddler.title += me.revSuffix
					.format([$(place).attr("revision")]);
				tiddler.fields.doNotSave = true;
				if (store.getTiddler(tiddler.title)) {
					store.deleteTiddler(tiddler.title);
				}
				store.addTiddler(tiddler);

				//now, populate the existing div
				var revElem = userParams.revElem;
				$(revElem).attr("id", story.tiddlerId(tiddler.title));
				$(revElem).attr("refresh", "tiddler");
				var getTemplate = function() {
					var themeName = config.options.txtTheme;
					if (themeName) {
						return store.getTiddlerSlice(themeName,
							me.revisionTemplate) || me.revisionTemplate ||
							"ViewTemplate";
					} else {
						return (store.getTiddler(me.revisionTemplate)) ?
							me.revisionTemplate : "ViewTemplate";
					}
				};
				var template = getTemplate();
				story.refreshTiddler(tiddler.title, template, true);
				callback(tiddler);
			});
	},

	createCloak: function(promoteElem) {
		var el = $(promoteElem);
		// cache styles for resetting later
		el.data({
			top: el.css("top"),
			left: el.css("left"),
			zIndex: el.css("z-index")
		});

		$('<div class="revisionCloak" />').css("z-index", me.zIndex)
			.click(function() {
				me.closeRevisions(promoteElem);
			})
			.appendTo(document.body);

		el.css("z-index", me.zIndex + 1);
	},

	// clean up, removing all evidence of revision view
	closeRevisions: function(promoteElem) {
		var el = $(promoteElem);
		// revert the original tiddler back to its previous state
		el.removeAttr("revName").removeClass("revisions").css({
			top: el.data("top"),
			left: el.data("left"),
			zIndex: el.data("zIndex")
		});

		// remove any revisions still in the store
		var revisions = $(".revisions");
		revisions.each(function(index, revision) {
			var revAttributes = revision.attributes;
			if ((revAttributes.revname) &&
					(revAttributes.revision)) {
				var revName = revAttributes.revname.value;
				var revNo = revAttributes.revision.value;
				var title = revName + me.revSuffix.format([revNo]);

				if (store.getTiddler(title)) {
					store.deleteTiddler(title);
				}
			}
		});

		// delete the previous revisions
		revisions.remove();

		// remove the cloak
		$(".revisionCloak").remove();
	},

	// calback from getting list of revisions
	expandStack: function(context, userParams) {
		var pageSize = userParams.pageSize;

		var from = userParams.from || 0;
		var tiddlerElem = userParams.tiddlerElem;

		userParams.defaultHeight = $(tiddlerElem).height();
		userParams.defaultWidth = $(tiddlerElem).width();
		if (from < context.revisions.length) {
			me.displayNextRevision(tiddlerElem, userParams, context, from,
				from + pageSize - 1);
		}
	},

	// place the next div above and behind the previous one
	displayNextRevision: function(tiddlerElem, userParams, context, from, to) {
		var revision = context.revisions[from];
		var callback = function() {
			var revText = revBtn.getRevisionText(tiddlerElem, revision);
			tiddlerElem = me.createRevisionObject(tiddlerElem, context,
				userParams, revText);
			$(tiddlerElem)
				.attr("revision", (context.revisions.length - from));
			if ((from < to) && ((from + 1) < context.revisions.length)){
				me.displayNextRevision(tiddlerElem, userParams, context,
					from + 1, to);
			} else if ((context.revisions.length - 1) > to) {
				me.showMoreButton(tiddlerElem, context, userParams, to + 1);
			}
		};
		me.shiftVisibleDown(userParams.title, callback);
	},

	createRevisionObject: function(tiddlerElem, context, userParams, text) {
		var newPosition = me.calculatePosition(tiddlerElem, context);
		return $('<div class="revisions tiddler" />')
			.css({
				position: "absolute",
				top: newPosition.top,
				left: newPosition.left,
				"z-index": me.zIndex + 1,
				height: userParams.defaultHeight,
				width: userParams.defaultWidth
			})
			.attr("revName", userParams.title)
			.append(text)
			.insertBefore(tiddlerElem);
	},

	// move the already present revisions down by 1 to fit the next one in
	shiftVisibleDown: function(title, callback) {
		var revisions = $("[revName='%0'].revisions".format([title]));
		var revisionCount = revisions.length;

		$(revisions).animate({top: "+=" + me.offsetTop},
				me.shiftDownDelay, function() {
					revisionCount -= 1;
					if ((callback) && (!revisionCount)) {
						callback();
					}
				});
	},

	// where we put the new revision
	calculatePosition: function(elem, context) {
		var offset = $(elem).offset();
		var currentPosition = $(elem).position();
		var newPosition = {
			top: currentPosition.top - me.offsetTop
		};
		if ((context.restrictLeft) ||
				((offset.left - me.offsetLeft) <
				$("#contentWrapper").offset().left)) {
			newPosition.left = $(elem).position().left;
			context.restrictLeft = true;
		} else {
			newPosition.left = currentPosition.left - me.offsetLeft;
		}
		return newPosition;
	},

	// equivalent of displayNextRevision, but for the more button
	showMoreButton: function(tiddlerElem, context, userParams, moreIndex) {
		userParams.from = moreIndex + 1;
		me.shiftVisibleDown(userParams.title, function() {
			var btn = me.createRevisionObject(tiddlerElem, context, userParams,
				"");

			var more = createTiddlyButton(btn[0], "more...", "show more revisions",
				function() {
					if ($(".viewRevision").length) {
						return;
					}
					userParams.tiddlerElem = btn[0];
					$(btn).text("")
						.append(revBtn
							.getRevisionText(btn[0], context.revisions[moreIndex]))
						.attr("revision", context.revisions.length - moreIndex);
					me.expandStack(context, userParams);
				});
			$(more).css("float", "right");
		});
	},

	stripRevFromTitle: function(revisionTitle) {
		return revisionTitle.split(/ ?\[rev\. #[0-9]+\]$/)[0];
	},

	onClickRevision: function(revElem, revision, callback) {
		// don't do anything if we are still loading
		if ($(".revisions").hasClass("loading")) {
			return null;
		}

		var origTitle = me.stripRevFromTitle(revision.title);
		if ($(revElem).hasClass("viewRevision")) {
			$(".revisions").addClass("loading");
			me.slideIn(revElem, revision, origTitle, function() {
				store.deleteTiddler(revision.title);
				revision.title = origTitle;
				$(revElem).text("").append(revBtn.getRevisionText(revElem,
						revision))
					.removeAttr("tags").removeAttr("tiddler")
					.removeAttr("refresh").removeAttr("template")
					.removeAttr("id");
				$(".revisions").removeClass("loading");
				if (callback) {
					callback();
				}
			});
			$(revElem).removeAttr("prevPos").removeClass("viewRevision");
		} else {
			var viewRevision = function() {
				var prevPos = $(revElem).position().left;
				$(revElem).addClass("viewRevision").attr("prevPos", prevPos);
				$(".revisions").addClass("loading");
				me.showRevision(revElem, revision, function(rev) {
					me.slideOut(revElem, rev, origTitle, function() {
						$(".revisions").removeClass("loading");
					});
				});
			};
			// make sure another revision isn't already out
			if ($(".viewRevision").length) {
				var newRevElem = $(".viewRevision")[0];
				var newRevision = store.getTiddler($(newRevElem)
					.attr("tiddler"));
				me.onClickRevision(newRevElem, newRevision, viewRevision);
			} else {
				viewRevision();
			}
		}
	},

	slideOut: function(revElem, revision, title, callback) {
		var leftMostPos = $("[revName='%0'].revisions".format([title]))
			.offset().left;
		var width = $(revElem).width();
		var originalLeftPos = $(story.getTiddler(title))
			.position().left;

		var slideAmount = leftMostPos + width - me.visibleSlideAmount;
		$("[revName='%0'].revisions:not(.viewRevision)".format([title]))
			.animate({left: "-=" + slideAmount}, 1000);
		$(revElem)
			.attr("baseHeight", $(revElem).css("height"))
			.css("height", "auto")
			.animate({left: originalLeftPos}, 1000, callback);
	},

	slideIn: function(revElem, revision, title, callback) {
		var slideAmount = $(revElem).offset().left -
			$(story.getTiddler(title)).offset().left;
		var origRevPos = $(revElem).attr("prevPos");

		$("[revName='%0'].revisions:not(.viewRevision)".format([title]))
			.animate({left: "+=" + slideAmount}, 1000);
		$(revElem).animate({left: origRevPos}, 1000, function() {
			$(revElem)
				.css("height", $(revElem).attr("baseHeight"))
				.removeAttr("baseHeight");
			callback();
		});
	}
};

var revBtn;
config.macros.slideRevision = revBtn = {
	btnText: "created by %0 at %1 on %2",
	handler: function(place, macroName, params, wikifier, paramString, tiddler) {
		var btn = revBtn.getRevisionText(place, tiddler);
		$(place).append(btn);
	},

	getRevisionText: function(place, revision) {
		var text = revBtn.btnText.format([revision.modifier,
			revision.modified.formatString("0hh:0mm"),
			revision.modified.formatString("0DD MMM YYYY")]);
		var btn = $('<a href="javascript:;" class="button revButton" />')
			.text(text)
			.click(function() {
				var revElem = story.findContainingTiddler(this);
				me.onClickRevision(revElem, revision);
			});
		return btn;
	}
};

})(jQuery);
//}}}
In our scope Static Analysis refers to Static ''Code'' Analysis. it is static because it is a code quality analysis done without running the code. In this sense a code inspection may be considered a form of static analysis. Modern tools for automated static analysis that detect known problematic patterns or rule violations are common nowadays and provide a very good quality return with little effort and investment.

Static Analysis targets are ''defects'', that is, code patterns that are known to cause problems or ''violations'', that is, occurrences that violate an existent coding rule or guideline (naming conventions for instance).

Static Analysis is one of the [[High Maturity Practices]] in [[Software Development]].

For a guideline on enterprise wide implementation of static analysis see : [[Implementing Static Analysis]]

!!Static Analysis References
* Tools
** [[List of tools for static code analysis|http://en.wikipedia.org/wiki/List_of_tools_for_static_code_analysis]] From Wikipedia, the free encyclopedia.
* Implementing
** [[Deploying Static Analysis|http://www.drdobbs.com/testing/deploying-static-analysis/240003801?pgno=1]] by Flash Sheridan, 2012 - Static analysis is a cheap and easy way to find bugs, but it offers important challenges that tend to be more political than technical.
** [[How to Spring Clean Your Static Analysis: 10 Tips|http://www.codeproject.com/Articles/589448/How-to-Spring-Clean-Your-Static-Analysis-10-Tips]] by c_a_dunlop, 2013 - A [[Code Project|http://www.codeproject.com]] article with some interesting tips.
----
@@color:#c4d6ed; ^^
Description: Static Analysis concept, discussion and references.
^^@@
/* -------------------------- */
/* Mind Map */
/* -------------------------- */
.mindMap {
height: 300px;
margin: 16px 448px 0px 72px;
}
/* -------------------------- */
/* Image padding */
/* -------------------------- */
.viewer img { padding:0em 0.5em 0em 0.5em; }
/* -------------------------- */
/* -------------------------- */
/* Image formatting for float */
/* -------------------------- */
.imgfloatleft{float:left;} 
.imgfloatright{float:right;padding:5px} 
.imgfloatcenter{float:center;} 
/* -------------------------- */

/* -------------------------- */
/* Site titles */
/* -------------------------- */
.siteTitle { 
 font-family: script;
 font-size: 3.0em;
 font-weight: bold;
}

.siteSubtitle { 
 font-family: script;
 font-size: 1.5em;
 font-weight: bold;
 padding-left: 1.0em;
}
/* -------------------------- */

/* -------------------------- */
/* Tiddler options*/
/* -------------------------- */
.tiddler .subtitle { display:none; } 
/* -------------------------- */

/* -------------------------- */
/* Font selection */
/* -------------------------- */
body {
 font-family: "Lucida Sans Unicode", freesans, clean, sans-serif;
 font-size: 1.0em;
}
/* -------------------------- */
/***
|Name|ImageMacro|
|Created by|Andre' de Carvalho|
|Location|http://acarvalho.tiddlyspace.com/#ImageMacro|
|Version|1.1.0|
|Date|2013 05 10|
|Type|Macro|
|Description|A TiddlyWiki Macro to create configurable links to images.|

/%
Version history :
1.1.0 2013 05 10 : handling null parameters
%/

!!Example
<<Image "FL" "200" "Coupling-root-level.png" "https://dl.dropbox.com/" "s/vfki4dkx343k4ut/" "?dl=1" "Root level allowed dependencies.">>
{{{
<<Image "FL" "200" "Coupling-root-level.png" "https://dl.dropbox.com/" "s/vfki4dkx343k4ut/" "?dl=1" "Root level allowed dependencies.">>
}}}




or

<<Image "FR" "200" "Coupling-root-level.png" "https://dl.dropbox.com/" "s/vfki4dkx343k4ut/" "?dl=1" "Root level allowed dependencies.">>
{{{
<<Image "FR" "200" "Coupling-root-level.png" "https://dl.dropbox.com/" "s/vfki4dkx343k4ut/" "?dl=1" "Root level allowed dependencies.">>
}}}

or

<<Image "" "" "Coupling-root-level.png" "https://dl.dropbox.com/" "s/vfki4dkx343k4ut/" "?dl=1" "Root level allowed dependencies.">>
{{{
<<Image "" "" "Coupling-root-level.png" "https://dl.dropbox.com/" "s/vfki4dkx343k4ut/" "?dl=1" "Root level allowed dependencies.">>
}}}

!!Installation
Import (or copy/paste) this tiddler into your document and tag it with "systemConfig".  For using size you need [[ImageSizePlugin|	http://www.TiddlyTools.com/#ImageSizePlugin]].

!!Code
***/
//{{{
version.extensions.Image= {major: 1, minor: 1 , revision: 0, date: new Date(2013,5,10)};
//Created by André de Carvalho
//}}}
//{{{
config.macros.Image = {};
config.macros.Image.handler= function(place,macroName,params) {
  /* Type : FL = float left, FR = float right, "" = no float */
   var type=params[0];
  /* Size : number = pixels (requires ImageSizePlugin), "" = no size */
   var size=params[1];
  /* Name : the name of the image file */
   var name=params[2];
  /* Name : the path of the image file (include end backslash) */
   var path = params[3];
  /* Prefix : optional prefix to be inserted between Path and FileName */
   var prefix = params[4];
  /* Postfix : optional postfix to be appended after FileName */
   var postfix = params[5];
  /* Caption : optional caption */
   var caption = params[6];

  var ini = "";
  var end = "";

  if (caption)
  {
    caption = "<br>@@padding:0.8em;@@@@color:#00f;^^"+caption+"^^@@";
  }
  else
  {
    caption = "";
  }

  switch(type)
  {
    case "FR":
      ini = "{{imgfloatright{[img";
      end = "]]"+caption+"}}}";
      break;
    case "FL":
      ini = "{{imgfloatleft{[img";
      end = "]]"+caption+"}}}";
      break;
    default:
      ini="[img";
      end = "]]";
  }

  if (size)
    ini = ini + "("+size+"px+,+)";

   ini = ini+"[";
   if (path)
     ini = ini+ path;
   if (prefix)
     ini = ini+ prefix;
   if (name)
     ini = ini+ name;
   if (postfix)
     ini = ini+ postfix;

   wikify(ini+end, place)
};
//}}}
 
|Concepts|Acronyms|h
|<<list filter [tag[Concept]]>>|<<list filter [tag[Acronym]]>>|
----
@@color:#c4d6ed; ^^
Description: A glossary of concepts and acronyms. 
^^@@
!EA
<<TiddlyTagMindMap filter:[tag[EA]] vizType:rgraph id:ttmm2 nodeSize:7 nodeType:ellipse nodeHoverColor:'#ee00ff' nodeColor:"#ff0000" edgeColor:'#ccc' edgeWidth:2 centerOn:EA width:750 height:480 template:MapNodeTemplate>>

!Concept
<<TiddlyTagMindMap filter:[tag[Concept]] vizType:rgraph id:ttmm1 nodeSize:10 nodeType:ellipse nodeHoverColor:'#ee00ff' nodeColor:"#ff0000" edgeColor:'#ccc' edgeWidth:2 centerOn:Concept width:750 height:480 template:MapNodeTemplate>>

!Requirements
<<TiddlyTagMindMap filter:[tag[Requirements]] centerOn:Requirements width:750 height:480 vizType:hypertree>>

!Guideline
<<TiddlyTagMindMap filter:[tag[Guideline]] vizType:rgraph id:ttmm3 nodeSize:10 nodeType:ellipse nodeHoverColor:'#ee00ff' nodeColor:"#ff0000" edgeColor:'#ccc' edgeWidth:2 centerOn:Guideline width:750 height:480 template:MapNodeTemplate>>

----
/%
@@color:#c4d6ed; ^^
Description: Mind Map for Content tag
^^@@
%/
----
@@color:#c4d6ed; ^^
Description: following http://augcampos.tiddlyspace.com/ ^^@@
[img[shiplogoC.gif]] André de Carvalho
Modularization is, probably, the most important choice you will make on structuring, specifying and implementing a solution. Its impacts, good or bad, will affect [[validation|Validation]] ability, reuse, maintainability, robustness, [[refactorability|Refactor]] and all the other important aspects that define the overall quality of your solution.
If I had to choose just one quality for a software project I would not doubt : good modularization. Everything else is meaningless without it. The sheer size of any software project is not humanely manageable without proper modularization.

!What is modularization
"The effectiveness of a "modularization" is dependent upon the criteria used in dividing the system into modules." <<BibRef "Parnas 1972">>
Modularization is a division of complexity, based on criteria, that produces a structure.

!The many contexts of modularization
!!Modularization at Analysis
The first thing to do when facing a 'big problem' is to split it in several 'smaller problems'. This is common sense from many centuries now,
!!Modularization at Specification
Conceptualisation of a solution is the first step to be able to cope with complexity and to work in a team with the communication needs it involves. A good concept is worth a thousand words...
!!Modularization at Construction
Filesystem and namespace rules play an essential role in preventing obstacles to and promoting many of the most important software qualities. A well structured filesystem and namespace is essential for maintainability, coupling control, cohesion, refactorability, testability and many other qualities. Be sure to establish a set of comprehensive and well reasoned [[Namespace and Filesystem Guidelines]]

----
See also : [[Application Archetype]] [[Coupling]] [[Cohesion]]
@@color:#c4d6ed; ^^
Description: Modularization concept explanation.
^^@@
//''"In preparing for battle, I have always found that plans are useless but planning is indispensable."''//
[[Dwight David Eisenhower (14 October 1890 – 28 March 1969)|http://en.wikiquote.org/wiki/Dwight_D._Eisenhower]]
!Introduction
The Request for Proposal Analysis occurs when you have to respond to a Customer's request for providing a Proposal (technical, financial and schedule) for a, possible, project he is willing to perform. This is the first stage you must perform : study and analysis of the problem and its scope.

{{tw_ttoc{}}}

!RFP Analysis Structure
The Request for Proposal Analysis is intended to provide a study infrastructure and step that will allow you to fully understand the Customer's request and needs. If done with method and proper tools, it will also produce a known, coherent and normalized [[traceability|Traceability]] basis for further work.
At the same time you study the [[RFP]] you shall <<quote 'copy' 'EA Tips & Tricks##Creating elements by dragging text onto a diagram'>> its information to the referred structure, changing as little as you can. The structure will act as a roadmap for analysis and as a completeness check list.
Do not think it is a waste of time, restructuring and normalizing the information is one of the best known ways of converting it into knowledge, and more, ''shareable persistent knowledge''. 
!!Problem Statement
This is an introductory section that shall give an overview of the problem and give a broad overview of the Customer envisioned solution.
This shall also provide a context for the following sections.
EA usage : Packages as  typographical elements of a document. Illustrative diagrams may be used if necessary. This shall, when possible, be an import of the Customer provided information.
<<Image "FR" "" "RFP-Analysis-Structure.PNG" "https://dl.dropbox.com/" "s/dwefsm068yfz2w0/" "?dl=1" "RFP Analysis Structure">>

//This is the Business Requirements Level. The business requirement is written from the Sponsor's point-of-view. It defines the objective of the project (goal) and the measurable business benefits for doing the project. The following sentence format is used to represent the business requirement and helps to increase consistency across project definitions:
"The purpose of the [project name] is to [project goal -- that is, what is the team expected to implement or deliver] so that [measurable business benefit(s) -- the sponsor's goal]." //
<<BibRef "BABOK 2008">> Chapter 4 : Enterprise Analysis

!!Goals
The Goals section shall describe the Customer goals for the project.
It shall also provide a list of success criteria in Customer's perspective.
This section shall present the business goals the project is supposed to support. This information shall be used to take decisions and to evaluate project's success.

You may, and probably shall, partition the project goals in sub-packages as specific as possible. Remember the goals are the factors to consider in trade-offs and are also success criteria so, the more specific they are the better.

Goals list is a main alignment tool between you and your Customer. Goals identification and description are also a main validation item that provides a very readable and understandable topic for your stakeholders.

"//According to our experience, the goal-agent-scenario triangle proved to be really effective. In particular, we repeatedly observed that a well-structured goal model provides an ideal communication interface between business managers and software engineers. Decision makers looked at goal models carefully, paying special attention to alternative goal refinements, operationalizations and responsibility assignments; they did not care too much about UML object models; annotated goal diagrams were found to be more helpful for focussed brainstorming, validation, negotiation, and decision making than fairly vague use case diagrams.//"
A. van Lamsweerde 
[[Goal-Oriented Requirements Engineering: A Roundtrip from Research to Practice |http://www.info.ucl.ac.be/Research/Publication/2004/avl-RE04-Keynote.pdf]]
Proceedings of RE’04, 12th IEEE Joint International Requirements Engineering Conference, Kyoto, Sept. 2004, 4-8 (Invited Keynote Paper) 


!!Stakeholders
Stakeholders are the persons affected by the project results and that can sponsor, contribute or take decisions over its definition.
<<Image "FR" "250" "RFP-Stakeholders.png" "https://dl.dropbox.com/" "s/25108r91fth99ra/" "?dl=1" "RFP Stakeholders">>
Define Stakeholders list.
Stakeholder attributes :
*Identification
*Contact details
*Affected interests
*Project's impact : real / perceived
*Decision ability
EA usage : ''Use Case'' diagram. ''Actor'' element (for groups detail contact person(s)). Fill details (Stakeholder attributes) in each element.
[[Traceability]] : Stakeholders may/shall be traced from Requested Features as authors or decision makers.
Stakeholders are not Roles. Not all Stakeholders will correspond to a role in the solution but all roles in the Proposed Solution must have a correspondent Stakeholder.
<<BibRef "BABOK 2008">> Chapter 2 : Business Analysis Planning and Monitoring : 2.3 and 2.9 

!!Business Processes
<<Image "FR" "250" "RFP-Business-Process.png" "https://dl.dropbox.com/" "s/go4tkspievr9bqc/" "?dl=1" "RFP Business Processes">>
This section shall describe all business processes, as the Customer see or perform them, that the solution will interact with.
This information may came from Customer's documented business processes or be constructed by a joint effort between Tendering and Technical Proposal Team. If necessary and possible it shall also involve Customer.
EA usage : The Business Processes diagram is ''Activity'' and the most relevant elements are ''Partition'', ''Activities'' and ''Decision''.
Primary Relationship is ''Control Flow'' to convey sequence.
The partitions shall reflect the relevant actors be them Customer organizational units or existing or to be developed systems. For each activity the expected role of the solution shall be stated.
Business Processes shall be structured in packages and the package shall contain a contextual introduction to the diagram. The diagram itself shall contain a textual description of the process.

!!System Context
The following sections are intended to provide a full description of the surrounding environment for the solution.
This is a major scope control information and shall prevent most of the integration problems. It is also very useful in defining our system's responsibilities versus Customer's systems responsibilities and, as such, very important for Proposal. 
!!!Data Flow Diagram
<<Image "FR" "250" "DFD%280%29.png" "https://dl.dropbox.com/" "s/9xa5jbcjemrd9j9/" "?dl=1" "DFD(0) or Context Diagram">>
Next to specification errors, integration "surprises" are a major cause of project problems or even failure. Determining a clear exploration context with very specific integration needs is, therefore, a major concern in Software Development. Also an underspecified context is a major scope risk. You know the scenario when tenths of MS Access databases start popping in requirements phase, don't you? 
On analysing the [[RFP]] you shall identify each and every reference to external systems and record it in your [[DFD|Data Flow Diagram]].

A [[Data Flow Diagram]] is your first and best ally in this matter.


!!!Integration Environment
The Integration Environment shall describe the intended hardware, network and software platform were the system is supposed to be deployed.
It is the deployment or infrastructure view of the Context Diagram.
<<Image "FR" "250" "Integration%20Environment%20-%20Overview.png" "https://dl.dropbox.com/" "s/zbvwh0uix7o3i8y/" "?dl=1" "Integration Environment - Overview">>
There are two views for this information: 
*informal - targeted to non technical audiences is simpler and only focuses in nodes and connections, 
*formal - for more technical audiences addresses execution environments.

The integration environment is an important piece to align customer infrastructure needs and also to assure good and specified integration of the solution. This may save you a lot of trouble and waiting time when deploying for acceptance.

*Description:
**This shall describe Customer's infrastructure and the integration environment for the requested solution.
**It shall present the existent deployment hardware environment and the software components with which the solution interacts.
**This must clearly state all integration requirements such as Authentication Schema, mandatory frameworks/technologies, etc.
<<Image "FR" "250" "Integration%20Environment.png" "https://dl.dropbox.com/" "s/6c58fgjn7omzmfi/" "?dl=1" "Integration Environment">>
*EA usage:
**The Integration Environment diagrams are Deployment diagram. The elements are Nodes for machines, Execution Environments for operating systems and platforms, Components for programs, existent or to be developed. The components to be developed shall be represented at the deployment package or system level and they may be placed here or at Technical Proposal.Technical Solution.Preliminary Component Model being this the preferred placement.
**Relationships are Association and they may be named for protocol and have source and target roles specified.
**Two diagrams shall be produced : the Overview with only the Nodes and their relationships and using friendly icons and the Detailed diagram using all referred elements.
*Traceability
**Traceability shall be maintained upwards by Association with correspondent Data Flow Externals.
*Scope:
**This is a PUBLIC section that is not directly present in deliverables.
*Internal section goals:
**This section shall present a technological introduction to the problem and its context. It shall also present a broad technological scope definition for the proposal. This shall be a Customer view. 
**This is the (Customer) declared integration environment, it will be the basis for the corresponding section on Proposal.
**All systems (hardware, devices, software, interfaces) that are relevant to the problem/solution shall be listed and described with as much detail as possible. Relationships between them shall be described and protocols identified.
*External section goals:
**None.
*When in doubt:
**This is a mandatory input. You may state "NO INTEGRATION" if you, as an architect, are lucky enough to have such a project, in this case this is a very probable candidate to productization and reuse.
*Notes:
**This section is reused (probably with modifications/enhancements) on [[Proposal|Technical Proposal Production Guidelines]].
**This is a clear candidate for reuse and continuous improvement when we have more than one project with the Customer. It shall be continuously refined along all the project.
*References:
!!!External Interfaces
*Description:
**This shall list and describe Customer's systems interfaces that our system will depend upon.
**The interfaces shall be described (operations and parameters) to the possible extent. This may/shall be refined on Specification phase.
**This must clearly state all interfaces that our system will depend upon.
*EA usage:
**The External Interfaces diagram is Class Diagram and the elements are Interface.
*Traceability
**External Interfaces shall be exposed on Integration Environment Components.
*Scope:
**This is a PUBLIC section that is not directly present in deliverables.
*Internal section goals:
**This section shall, up to the possible extent, present a full list of interfaces that our system will use on Customer's existing systems. 
*External section goals:
**Validate completeness.
*When in doubt:
**This is a mandatory input. You may state "NO INTEGRATION" if you, as an architect, are lucky enough to have such a project, in this case this is a very probable candidate to productization and reuse.
*Notes:
**This section is reused (probably with modifications/enhancements) on [[Proposal|Technical Proposal Production Guidelines]].
**This is a clear candidate for reuse and continuous improvement when we have more than one project with the Customer. It shall be continuously refined along all the project.
*References:
!!Organization Standards
Every organization has some standards it follows. They may be more or less formal, written or just practised,  but they are always, at least, guidelines and expectation referentials.
When this information is transmitted to you, in any form, you can not afford to ignore or lose it under the penalty of disregarding something that is obviously important for your Customer.
In our context this section shall list, reference and, at least, summary describe all Customer pertinent information. Imagine a reference architecture, a naming convention, a glossary, an external standard the Customer is certified under, etc.
This information is essential and is an important business continuity mark when you have more than one project with the same Customer. It shall be reused and enhanced in each new project with the same Customer.

!!Requested Features
The first consideration is how to express the problem and the business needs. ''User Requirements'' concept is the first thing to came to mind. We propose, however, that a different concept be used in the Inception phase, that concept is ''Feature'' in the form of ''Requested Feature'' and ''Proposed Feature''. The detailed discussion on this approach is in [[Software Requirement vs. Feature]].

The Requested Features shall have a content as close to the Customer's original expression as possible. You want to capture all of the RFP information in the model in order to not have to go back to [[RFP]] after analysis is concluded. For this you shall respect Customer's statements and make clear what was said by him and what you add yourself. Remember that Requested Features are your primary [[traceability|Traceability]] origins and scope items.

Decompose Customer statements into as many features as they contain and create one feature for each. You want requested Features to be as specific as possible.
Customer : "//The system shall optimize data entry effort and enrich it with more information than we have today.//"
''~RFT-10.010 - Optimize data entry effort''
The system shall optimize data entry effort (...).
''~RFT-10.020 - Enrich data with more information''
The system shall (...) enrich [data entry] with more information than we have today.

!!Issues
If you are analysing you'll have doubts and identify omissions, record them or lose them, is that simple.

----
Back to [[Business Analysis]]
----
<<TiddlerToC min-entries:1>>
/%
@@color:#c4d6ed; ^^
Description: Guidelines for RFP analysis
^^@@
%/
----
@@color:#c4d6ed; ^^
Description: following pmario at http://pmario.tiddlyspace.com/
^^@@
Data Flow Diagrams (DFD) were proposed as __the essential view__ in the historical ''Structured Analysis and System Specification'' by Tom ~DeMarco, Yourdon Press, New York, 1978. 
In his enlightened words "//(...) ''I conclude that it is a natural characteristic of the tool: When a Data Flow Diagram is wrong, it is glaringly, demonstrably, indefensibly wrong. This seems to me to be an enormous advantage of using Data Flow Diagrams.''//" chapter 3.2

Although he corrected his statement to "//Dataflow is one of the essential views, not the only one//" in //Structured Analysis, Tom ~DeMarco, sd&m Conference 2001, Software Pioneers//, we strongly agree that ''DFD view is essential'' for the analysis of software solutions specially as a __''[[validation|Validation]] and [[scope|Scope]] definition tool''__ on the inception stages. No wonder DFD(0) are also known as ''System Context Diagram'', this name alone should give you the idea of its importance.

<<Image "FR" "250" "DFD%280%29.png" "https://dl.dropbox.com/" "s/9xa5jbcjemrd9j9/" "?dl=1" "DFD(0) or Context Diagram">>
//"Another useful model in system design is the context diagram, which represents all external entities that may interact with a system, either directly or indirectly. (...) Such a diagram pictures the system at the center, with no details of its interior structure, surrounded by all its interacting systems, environments, and activities. The objective of a system context diagram is to focus attention on external factors and events that should be considered in developing a complete set of system requirements and constraints."//
<<BibRef "Kossiakoff 2011">> pg. 266

No software specification is complete without, at least, one Context Diagram describing the system data flows to and from all external entities. Not doing so is to risk to face a lot of Access databases and obscure legacy systems that nobody heard about before, popping like mushrooms after a rainy day, on the Requirements Specification phase and, of course, they must be integrated in the new system.

<<Image "FR" "350" "DFD%281%29.png" "https://dl.dropbox.com/" "s/wgm8wh10cihcn37/" "?dl=1" "DFD level 1">>
DFDs may be detailed in further levels to describe the inner flows of the system and they are very useful to help define modularization.





!!Additional references
* Just Enough Structured Analysis, Edward Yourdon - [[Wiki version|http://yourdon.com/strucanalysis/wiki/index.php/Chapter_9]]

TODO: add example, describe usage
----
See also : [[Use Case Diagram]]
----
@@color:#c4d6ed; ^^
Description: DFD concept, usage and references
^^@@
"//In software engineering, a design pattern is a general reusable solution to a commonly occurring problem within a given context in software design. A design pattern is not a finished design that can be transformed directly into source or machine code. It is a description or template for how to solve a problem that can be used in many different situations. Patterns are formalized best practices that the programmer must implement themselves in the application.[1] Object-oriented design patterns typically show relationships and interactions between classes or objects, without specifying the final application classes or objects that are involved.//"
Pasted from <http://en.wikipedia.org/wiki/Software_design_pattern> 

One of the best resources for pattern related information is [[The Hillside Group|http://hillside.net/]] site.

----
/%
@@color:#c4d6ed; ^^
Description: Software Design Patterns concept and references
^^@@
%/
Features are a "relaxed" form of Requirements, namely they are not required to be, necessarily, [[SMART|SMART Requirements]]. We propose them as a preferred form to express requirements in [[RFP]] and [[Technical Proposal|Technical Proposal Production Guidelines]] at Inception phases.
<<Image "FR" "250" "Requirements-Elements.png" "https://dl.dropbox.com/" "s/o4ewv8nlr4vfb7w/" "?dl=1" "Feature element in EA.">>
Feature is an extended element in [[Sparx Enterprise Architect]] [[CASE]] tool Requirements diagram.
Features are split in ''Requested Features'', the ones that originate at Customer and describe the needs in the Customer perspective and ''Proposed Features'', the ones that constitute the software developer response at Proposal. The first ones use ''RFT'' prefix, the later ''FT''. 

Quoting The Standish Group, The CHAOS Report, 1994, Scott ~McEwen in his very interesting article [[Requirements: An introduction|http://www.ibm.com/developerworks/rational/library/4166.html]] defines: "//''A feature is a service that the system provides to fulfill one or more stakeholder needs.''//"

For a distinction against [[Software Requirement]] see [[Software Requirement vs. Feature]]
----
@@color:#c4d6ed; ^^
Description: Feature concept and references.
^^@@
/***
|''Name''|ServerSideSavingPlugin|
|''Description''|server-side saving|
|''Author''|FND|
|''Version''|0.6.5|
|''Status''|stable|
|''Source''|http://svn.tiddlywiki.org/Trunk/association/plugins/ServerSideSavingPlugin.js|
|''License''|[[BSD|http://www.opensource.org/licenses/bsd-license.php]]|
|''CoreVersion''|2.5.3|
|''Keywords''|serverSide|
!Notes
This plugin relies on a dedicated adaptor to be present.
The specific nature of this plugin depends on the respective server.
!Revision History
!!v0.1 (2008-11-24)
* initial release
!!v0.2 (2008-12-01)
* added support for local saving
!!v0.3 (2008-12-03)
* added Save to Web macro for manual synchronization
!!v0.4 (2009-01-15)
* removed ServerConfig dependency by detecting server type from the respective tiddlers
!!v0.5 (2009-08-25)
* raised CoreVersion to 2.5.3 to take advantage of core fixes
!!v0.6 (2010-04-21)
* added notification about cross-domain restrictions to ImportTiddlers
!To Do
* conflict detection/resolution
* rename to ServerLinkPlugin?
* document deletion/renaming convention
!Code
***/
//{{{
(function($) {

readOnly = false; //# enable editing over HTTP

var plugin = config.extensions.ServerSideSavingPlugin = {};

plugin.locale = {
	saved: "%0 saved successfully",
	saveError: "Error saving %0: %1",
	saveConflict: "Error saving %0: edit conflict",
	deleted: "Removed %0",
	deleteError: "Error removing %0: %1",
	deleteLocalError: "Error removing %0 locally",
	removedNotice: "This tiddler has been deleted.",
	connectionError: "connection could not be established",
	hostError: "Unable to import from this location due to cross-domain restrictions."
};

plugin.sync = function(tiddlers) {
	tiddlers = tiddlers && tiddlers[0] ? tiddlers : store.getTiddlers();
	$.each(tiddlers, function(i, tiddler) {
		var changecount = parseInt(tiddler.fields.changecount, 10);
		if(tiddler.fields.deleted === "true" && changecount === 1) {
			plugin.removeTiddler(tiddler);
		} else if(tiddler.isTouched() && !tiddler.doNotSave() &&
				tiddler.getServerType() && tiddler.fields["server.host"]) { // XXX: server.host could be empty string
			delete tiddler.fields.deleted;
			plugin.saveTiddler(tiddler);
		}
	});
};

plugin.saveTiddler = function(tiddler) {
	try {
		var adaptor = this.getTiddlerServerAdaptor(tiddler);
	} catch(ex) {
		return false;
	}
	var context = {
		tiddler: tiddler,
		changecount: tiddler.fields.changecount,
		workspace: tiddler.fields["server.workspace"]
	};
	var serverTitle = tiddler.fields["server.title"]; // indicates renames
	if(!serverTitle) {
		tiddler.fields["server.title"] = tiddler.title;
	} else if(tiddler.title != serverTitle) {
		return adaptor.moveTiddler({ title: serverTitle },
			{ title: tiddler.title }, context, null, this.saveTiddlerCallback);
	}
	var req = adaptor.putTiddler(tiddler, context, {}, this.saveTiddlerCallback);
	return req ? tiddler : false;
};

plugin.saveTiddlerCallback = function(context, userParams) {
	var tiddler = context.tiddler;
	if(context.status) {
		if(tiddler.fields.changecount == context.changecount) { //# check for changes since save was triggered
			tiddler.clearChangeCount();
		} else if(tiddler.fields.changecount > 0) {
			tiddler.fields.changecount -= context.changecount;
		}
		plugin.reportSuccess("saved", tiddler);
		store.setDirty(false);
	} else {
		if(context.httpStatus == 412) {
			plugin.reportFailure("saveConflict", tiddler);
		} else {
			plugin.reportFailure("saveError", tiddler, context);
		}
	}
};

plugin.removeTiddler = function(tiddler) {
	try {
		var adaptor = this.getTiddlerServerAdaptor(tiddler);
	} catch(ex) {
		return false;
	}
	var context = {
		host: tiddler.fields["server.host"],
		workspace: tiddler.fields["server.workspace"],
		tiddler: tiddler
	};
	var req = adaptor.deleteTiddler(tiddler, context, {}, this.removeTiddlerCallback);
	return req ? tiddler : false;
};

plugin.removeTiddlerCallback = function(context, userParams) {
	var tiddler = context.tiddler;
	if(context.status) {
		if(tiddler.fields.deleted === "true") {
			store.deleteTiddler(tiddler.title);
		} else {
			plugin.reportFailure("deleteLocalError", tiddler);
		}
		plugin.reportSuccess("deleted", tiddler);
		store.setDirty(false);
	} else {
		plugin.reportFailure("deleteError", tiddler, context);
	}
};

plugin.getTiddlerServerAdaptor = function(tiddler) { // XXX: rename?
	var type = tiddler.fields["server.type"] || config.defaultCustomFields["server.type"];
	return new config.adaptors[type]();
};

plugin.reportSuccess = function(msg, tiddler) {
	displayMessage(plugin.locale[msg].format([tiddler.title]));
};

plugin.reportFailure = function(msg, tiddler, context) {
	var desc = (context && context.httpStatus) ? context.statusText :
		plugin.locale.connectionError;
	displayMessage(plugin.locale[msg].format([tiddler.title, desc]));
};

config.macros.saveToWeb = { // XXX: hijack existing sync macro?
	locale: { // TODO: merge with plugin.locale?
		btnLabel: "save to web",
		btnTooltip: "synchronize changes",
		btnAccessKey: null
	},

	handler: function(place, macroName, params, wikifier, paramString, tiddler) {
		createTiddlyButton(place, this.locale.btnLabel, this.locale.btnTooltip,
			plugin.sync, null, null, this.locale.btnAccessKey);
	}
};

// hijack saveChanges to trigger remote saving
var _saveChanges = saveChanges;
saveChanges = function(onlyIfDirty, tiddlers) {
	if(window.location.protocol == "file:") {
		_saveChanges.apply(this, arguments);
	} else {
		plugin.sync(tiddlers);
	}
};

// override removeTiddler to flag tiddler as deleted -- XXX: use hijack to preserve compatibility?
TiddlyWiki.prototype.removeTiddler = function(title) { // XXX: should override deleteTiddler instance method?
	var tiddler = this.fetchTiddler(title);
	if(tiddler) {
		tiddler.tags = ["excludeLists", "excludeSearch", "excludeMissing"];
		tiddler.text = plugin.locale.removedNotice;
		tiddler.fields.deleted = "true"; // XXX: rename to removed/tiddlerRemoved?
		tiddler.fields.changecount = "1";
		this.notify(title, true);
		this.setDirty(true);
	}
};

// hijack ImportTiddlers wizard to handle cross-domain restrictions
var _onOpen = config.macros.importTiddlers.onOpen;
config.macros.importTiddlers.onOpen = function(ev) {
	var btn = $(resolveTarget(ev));
	var url = btn.closest(".wizard").find("input[name=txtPath]").val();
	if(window.location.protocol != "file:" && url.indexOf("://") != -1) {
		var host = url.split("/")[2];
		var macro = config.macros.importTiddlers;
		if(host != window.location.host) {
			btn.text(macro.cancelLabel).attr("title", macro.cancelPrompt);
			btn[0].onclick = macro.onCancel;
			$('<span class="status" />').text(plugin.locale.hostError).insertAfter(btn);
			return false;
		}
	}
	return _onOpen.apply(this, arguments);
};

})(jQuery);
//}}}
/***
|''Name''|TiddlySpaceToolbar|
|''Description''|augments tiddler toolbar commands with SVG icons|
|''Author''|Osmosoft|
|''Version''|0.6.6|
|''Status''|@@beta@@|
|''Source''|http://github.com/TiddlySpace/tiddlyspace/raw/master/src/plugins/TiddlySpaceToolbar.js|
|''CodeRepository''|http://github.com/TiddlySpace/tiddlyspace|
|''License''|[[BSD|http://www.opensource.org/licenses/bsd-license.php]]|
|''CoreVersion''|2.5.0|
|''Requires''|ImageMacroPlugin|
|''Keywords''|toolbar icons SVG|
!Description
replaces tiddler toolbar commands with SVG icons if available
!Notes
requires [[ImageMacroPlugin|http://svn.tiddlywiki.org/Trunk/contributors/JonRobson/plugins/ImageMacroPlugin/plugins/ImageMacroPlugin.tid]]

SVG icons are drawn from tiddlers titled {{{<command>.svg}}}
In readonly mode a tiddler called {{{<command>ReadOnly.svg}}} will be used if it exists.
!TODO
* rename (IconToolbarPlugin?)
* support more than one more popup menu in the toolbar.
!Code
***/
//{{{
(function($) {

if(!config.macros.image) {
	throw "Missing dependency: ImageMacroPlugin";
}

var macro = config.macros.toolbar;

macro.icons = {
	cloneTiddler: "editTiddler"
};

var _handler = macro.handler;
macro.handler = function(place, macroName, params, wikifier,
		paramString, tiddler) {
	var toolbar = $(place);
	toolbar.attr({
		refresh: "macro",
		macroName: macroName
	}).data("args", arguments);
	var status = _handler.apply(this, arguments);
	if(tiddler.isReadOnly()) {
		toolbar.addClass("toolbarReadOnly");
	} else {
		toolbar.removeClass("toolbarReadOnly");
	}
	var parsedParams = paramString.parseParams("name")[0];
	if(parsedParams.icons && parsedParams.icons == "yes") {
		this.augmentCommandButtons(place);
	}
	if(parsedParams.more && parsedParams.more == "popup") {
		// note we must override the onclick event like in createTiddlyButton
		// otherwise the click event is the popup AND the slider
		$(".moreCommand", place).each(function(i, el) {
			el.onclick = macro.onClickMorePopUp;
		});
		// buttons that are after a less command should not be in more menu.
		$(".lessCommand ~ .button", place).appendTo(place);
		$(".lessCommand", place).remove();
	}
	return status;
};

macro.refresh = function(place, params) {
	var args = $(place).empty().data("args");
	this.handler.apply(this, args);
};

var imageMacro = config.macros.image;
macro.augmentCommandButtons = function(toolbar) {
	$(".button", toolbar).each(function(i, el) {
		var cmd = $(el).attr("commandname");
		cmd = cmd ? cmd : "moreCommand"; // XXX: special-casing of moreCommand due to ticket #1234
		var icon = store.tiddlerExists(cmd) ? cmd : macro.icons[cmd];
		var text = $(el).text();
		if(readOnly) {
			var readOnlyAlternative = "%0ReadOnly".format([icon]);
			if(store.tiddlerExists(readOnlyAlternative)) {
				icon = readOnlyAlternative;
			}
		}
		if(store.tiddlerExists(icon)) {
			$(el).css({display: "inline-block"}).empty();
			imageMacro.renderImage(el, icon, { alt: text });
		}
	});
};

// provide onClickMore to provide extra commands in a popup
macro.onClickMorePopUp = function(ev) {
	ev = ev || window.event;
	var sibling = this.nextSibling;
	if(sibling) {
		var commands = sibling.childNodes;
		var popup = Popup.create(this);
		$(popup).addClass("taggedTiddlerList");
		for(var i = 0; i < commands.length; i++) {
			var li = createTiddlyElement(popup, "li", null);
			var oldCommand = commands[i];
			var command = oldCommand.cloneNode(true);
			command.onclick = oldCommand.onclick;
			li.appendChild(command);
		}
		Popup.show();
	}
	ev.cancelBubble = true;
	if(ev.stopPropagation) {
		ev.stopPropagation();
	}
	return false;
};

})(jQuery);
//}}}
/***
|!''Name:''|!easyInsert|
|''Description:''|insert text template at caret position|
|''Version:''|0.0.2|
|''Date:''|19/05/2013|
|''Source:''|[[easyInsert|http://acarvalho.tiddlyspace.com/#easyInsert]]|
|''Author:''|André de Carvalho|
|''License:''|[[BSD open source license]]|
|''~CoreVersion:''|2.x|
|''Browser:''|Firefox 1.0.4+; Firefox 1.5; InternetExplorer 6.0|
|''Requires:''|@@color:red;''[[E.A.S.E]]''@@|
***/
//{{{
config.commands.insert = new TWkd.Ease('Insert','insert template text at caret position');
config.commands.insert.addMode({
 name:'Image',
 tooltip:'image template',
 operation:function(){
config.commands.format.putInPlace(""+TWkd.context.selection.content+"<<Image \"FR\" \"320\" \"filename\" \".\" \"\\filepath\\\">>",TWkd.context.selection);
 }
});
config.commands.insert.addMode({
 name:'Image with caption',
 tooltip:'image with caption template',
 operation:function(){
config.commands.format.putInPlace(""+TWkd.context.selection.content+"<<Image \"FR\" \"320\" \"filename\" \".\" \"\\filepath\\\" \"\" \"caption\">>",TWkd.context.selection);
 }
});
config.commands.insert.addMode({
 name:'Bib reference',
 tooltip:'bibliographical reference template',
 operation:function(){
config.commands.format.putInPlace(""+TWkd.context.selection.content+"<<BibRef \"reference\">>",TWkd.context.selection);
 }
});
config.commands.insert.addMode({
 name:'Popnote',
 tooltip:'selection to inline popnote',
 operation:function(){
config.commands.format.putInPlace("<<quote \'"+TWkd.context.selection.content+"\' \'targettiddler\'>>",TWkd.context.selection);
 }
});
//}}}
/***
|''Name''|TiddlySpaceSearcher|
|''Version''|0.2.5|
|''Requires''|TiddlySpaceConfig TiddlySpaceFollowingPlugin|
***/
//{{{
(function($) {
var tiddlyspace = config.extensions.tiddlyspace;
var tsScan = config.macros.tsScan;

config.shadowTiddlers.SearchTemplate = "<<view server.bag SiteIcon label:no width:24 height:24 preserveAspectRatio:yes>> <<view server.bag spaceLink title external:no>> in space <<view server.bag spaceLink>>";
config.shadowTiddlers.StyleSheetSearch = [".resultsArea .siteIcon { display: inline; }",
	".searchForm {text-align: left;}"].join("\n");
store.addNotification("StyleSheetSearch", refreshStyles);

var search = config.macros.tsSearch = {
	locale: {
		advanced: "Advanced Options",
		header: "Search",
		resultsHeader: "Results (%0)",
		find: "find",
		noResults: "No tiddlers matched your search query",
		query: "QUERY: ",
		error: "please provide a search query or a tag, modifier or title!",
		titleAdvanced: "where the title is",
		modifierAdvanced: "where the last modifier is",
		spaceAdvanced: "only in the space: ",
		notspaceAdvanced: "but not in the spaces: ",
		tagsAdvanced: "with the tags: "
	},
	andConstructor: function(container, label, fieldname, negationMode) {
		var tags = $("<div />").appendTo(container);
		$('<span />').text(label).appendTo(tags);
		var id = "area" + Math.random();
		container = $("<span />").attr("id", id).appendTo(tags)[0];
		function add(container) {
			var el = $('<input type="text" />').attr("field", fieldname).appendTo(container);
			if(negationMode) {
				el.attr("negation", "true");
			}
		}
		add(container);
		var el = $("<button />").text("AND").click(function(ev) {
			add($(ev.target).data("container"));
			ev.preventDefault();
		}).appendTo(tags);
		$(el).data("container", container);
	},
	fieldConstructor: function(container, label, field) {
		container = $("<div />").appendTo(container)[0];
		$("<span />").text(label).appendTo(container);
		$("<input />").attr("text", "input").attr("field", field).appendTo(container);
	},
	advancedOptions: function(form) {
		var locale = search.locale;
		var container = $("<div />").addClass("tsAdvancedOptions").appendTo(form)[0];
		$("<h2/ >").text(search.locale.advanced).appendTo(container);
		$("<div />").addClass("separator").appendTo(container);
		search.fieldConstructor(container, locale.titleAdvanced, "title");
		search.fieldConstructor(container, locale.modifierAdvanced, "modifier");
		search.fieldConstructor(container, locale.spaceAdvanced, "space");
		search.andConstructor(container, locale.notspaceAdvanced, "space", true);
		search.andConstructor(container, locale.tagsAdvanced, "tag");
	},
	constructSearchQuery: function(form) {
		var data = [], select = [];
		var query = $("[name=q]", form).val();
		if(query) {
			data.push("q=%0".format(query));
		}

		// add tags, fields etc..
		$("[field]", form).each(function(i, el) {
			var val = $(el).val();
			var name = $(el).attr("field");
			var negate = $(el).attr("negation") == "true";
			if(val && name) {
				val = encodeURIComponent(val);
				val = negate ? "!" + val : val;
				if(name == "space") {
					val += "_public";
					name = "bag";
				}
				if(negate) {
					select.push("select=%0:%1".format(name,val));
				} else {
					var prefix = data.length === 0 ? "q=" : "";
					data.push('%0%1:"%2"'.format(prefix, name, val));
				}
			}
		});
		var dataString = data.join(" ");
		if(dataString.length === 0 && !query) {
			return false;
		}
		var selectStatement = select.join("&");
		if(dataString.length > 0 && selectStatement.length > 0) {
			dataString += "&";
		}
		dataString += selectStatement;
		return "/search?%0".format(dataString);
	},
	constructForm: function(place) {
		var locale = search.locale;
		$("<h1 />").text(locale.header).appendTo(place);
		var form = $("<form />").appendTo(place)[0];
		$('<input type="text" name="q" />').appendTo(form);
		$('<input type="submit" />').val(locale.find).appendTo(form);
		search.advancedOptions(form);
		var query = $('<h2 class="query"/>').appendTo(place)[0];
		var results = $("<div />").appendTo(place).addClass("resultsArea")[0];
		var lookup = function(url) {
			if(!url) {
				results.empty().addClass("error").text(locale.error);
				return;
			}
			config.extensions.tiddlyweb.getStatus(function(status) {
				$(query).text(locale.query);
				var href = status.server_host.url + url;
				$("<a />").attr("href", href).text(href).appendTo(query);
				tsScan.scan(results, { url: url, emptyMessage: search.locale.noResults, cache: true,
					template: "SearchTemplate", sort: "title", callback: function(tiddlers) {
						$("<h2 />").text(locale.resultsHeader.format(tiddlers.length)).prependTo(results);
					}
				});
			});
		};
		$(form).submit(function(ev) {
			ev.preventDefault();
			var url = search.constructSearchQuery(form);
			config.macros.tsSearch.lastSearch = url;
			lookup(url);
		});
		if(search.lastSearch) {
			lookup(search.lastSearch);
		}
		return form;
	},
	handler: function(place) {
		var container = $("<div />").addClass("searchForm").appendTo(place)[0];
		search.constructForm(container);
	}
};

})(jQuery);
//}}}
<<Image "FR" "350" "IC350992.png" "http://i.msdn.microsoft.com/" "dynimg/" "" "Rich Client Application MS archetype">>
//"This section of the guide contains a series of topics that will help you to understand the capabilities, features, benefits, and liabilities of each of the common application types that you may decide to create. The first topic contains an overview of the basic application types such as Web, mobile, rich client, services, and RIA. "//

In [[Application Archetypes|http://msdn.microsoft.com/en-us/library/ee658107.aspx]]
Microsoft Application Architecture Guide 2.0 <<BibRef "AppArch 2.0">>

The application archetype is an essential step towards a proper [[Modularization]] of your system that, in turn, will be crucial for [[Encapsulation]] and [[Coupling]] and [[Cohesion]] control. 





----
@@color:#c4d6ed; ^^
Description: Application Archetype concept and references.
^^@@
{{imgfloatleft{[img(150px+,+)[http://www.sparxsystems.com/images/products/logos/EA.png]]}}}{{imgfloatright{[img(250px+,+)[http://www.sparxsystems.com/images/products/ea/recording_thumb.jpg]]}}}


Enterprise Architect is my primary tool in software development specification and documentation activities. For me it is a full life-cycle tool that I use from Inception, through code documenting and reuse management up to the end of life of each solution.

|EA specific articles in this site|h
|<<list filter [tag[EA]]>>|


[[Sparx Enterprise Architect|http://www.sparxsystems.com/]] [[CASE]] tool.
----
!!Additional resources
* [[Sparx Systems Enterprise Architect Community Site|http://community.sparxsystems.com/]]
* [[Exploring EA|http://exploringea.com/]] - Learning, experimenting and extending Sparx Systems Enterprise Architect
* [[Enterprise Architect (Sparx Systems) User Group|http://www.linkedin.com/groups?home=&gid=1356]] - Linkdin group on EA

----
@@color:#c4d6ed; ^^
Description: Sparx Enterprise Architect CASE tool.
^^@@
Strong [[cohesion|Cohesion]] and loose coupling are a good thing in software design.
Coupling (or dependency) control is one of the most important tasks in a large, complex and evolving system. It also has even more importance in an n-tier system.

See [[Namespace and Filesystem Guidelines]], [[Namespace Coupling Guidelines]] and [[Namespace Code Placement Guidelines]] as the first measure to fight //spaghetti coupling//. 

Improper coupling is a major obstacle to reusability, maintainability and testability
----
See also : [[Application Archetype]] [[Modularization]] [[Cohesion]]
@@color:#c4d6ed; ^^
Description: Coupling concept explanation.
^^@@
http://htmljs.tiddlyspace.com/jquery.js
http://htmljs.tiddlyspace.com/htmljs-wikiupgrade.js
Click the "new tiddler" button towards the top right of the screen to write something in your space. You'll need to give it a title, some content and, optionally, some tags that will help you identify it later.

!Stuck for ideas?
Not sure what to write about? Not sure what to keep in your space? Other people use ~TiddlySpace for almost anything. How about some of the following:

* [[Save interesting sites|http://bookmarks.tiddlyspace.com]], images or articles from around the web so that you can refer back to them.
* [[Record your family tree|http://familytree.tiddlyspace.com]], store notes on long lost relatives or ancestors and map their relationship to you.
* [[Make up a pocketbook|http://pocketbook.tiddlyspace.com]] to store some useful information in, then print it out, [[fold it up|http://www.pocketmod.com/]], and take it with you.
* [[Plan your holiday|http://the-web-is-your-oyster.tiddlyspace.com/]], record where you're planning to go, note down places of interest and refer back to it later.
* [[Create a mindmap|http://mindmaps.tiddlyspace.com/]] to visualise your inner thoughts and see how they relate to each other.
* [[Set up a questionnaire|http://questionnaire.tiddlyspace.com/]] and get all your friends to answer it.

If you don't like any of those ideas, you can still use this space directly to keep notes and link them together, make a todo list and keep track of everything you're doing, or any one of a hundred million other things.

Still stuck? Check out the @featured space for more suggestions.

You can also [[socialise with others|How to socialise]].
//One point of confusion regarding abstraction is its use as both a process and an entity. Abstraction, as a process, denotes the extracting of the essential details about an item, or a group of items, while ignoring the inessential details. Abstraction, as an entity, denotes a model, a view, or some other focused representation for an actual item. Abstraction is most often used as a complexity mastering technique. For example, we often hear people say such things as: "just give me the highlights" or "just the facts, please." What these people are asking for are abstractions.//

* Edward V. Berard - Abstraction, Encapsulation and Information Hiding	[[[Berard]|BibliographyPage##Berard]]
----
@@color:#c4d6ed; ^^
Description: concept and references.
^^@@
Systematic reuse opposes to //ad hoc// (or opportunistic) reuse as it involves defined practices, processes, management  and infrastructure that allow [[Continuous Improvement]].
//Ad hoc// reuse, or opportunistic reuse, is just a scavenging practice unable to scale and doomed to fall way back of systematic reuse potential. It is usually performed as [[Reuse by Copy|Reuse by Reference]] and, as such, it does not promote [[Continuous Improvement]] and is destined to [[rot|Software Rot]].

''Systematic reuse starts, and has its major potential, at processes, analysis and specification, not on code.''
This is an often overlooked aspect as, most people, think in __reuse code__ as the first reuse topic. ''The fact is that reuse is easier towards abstraction.'' Its easier to reuse a set of [[Feature]]s (business needs) than the specific [[Software Requirement]]s they originate, its easier to reuse a set of requirements than the specific code that was produced in response to them, its easier to reuse an interface than a concrete class. Of course that, if systematic reuse is in the mindset of your analysis and specification, chances are that you will also produce more reusable code.

''Systematic reuse improves overall quality of development artefacts as it provides [[Continuous Improvement]] opportunities.'' Each reuse instance is an opportunity to [[refactor|Refactor]], optimize, correct and enhance and, if [[Reuse by Copy|Reuse by Reference]] is avoided, these improvements propagate to all the other, past, present and future reuse instances.

''Systematic reuse is a major competitiveness factor.'' On tendering it allows us to focus on the specific Customer request challenges and not on technical common problems, this makes us more [[agile|Agile Methodologies]] and improves the quality of our response. Reuse (of proper reusable artefacts) also has an huge impact on cost contributing to a more competitive proposal. By using common, known and tested approaches we also reduce risk and improve estimation accuracy.

In [[Implementing Systematic Reuse]] we point out some guidelines that may be useful in this endeavour.
----
!!Other references on the topic
* Aravamudhan Narayanan (Vijay),  on [[Art of Software Reuse|http://artofsoftwarereuse.com/]] - Enabling Organizational Agility using Systematic Software Reuse
----
See also : [[Emergent Reuse]], [[Reuse oriented CVS]], [[Reuse Obstacles]]
----
@@color:#c4d6ed; ^^
Description: Systematic Reuse concept explanation and discussion.
^^@@
/***
|Name|SinglePageModePluginInfo|
|Source|http://www.TiddlyTools.com/#SinglePageModePlugin|
|Documentation|http://www.TiddlyTools.com/#SinglePageModePluginInfo|
|Version|2.9.6|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|documentation|
|Description|Documentation for SinglePageModePlugin|
Normally, as you click on the links in TiddlyWiki, more and more tiddlers are displayed on the page. The order of this tiddler display depends upon when and where you have clicked. Some people like this non-linear method of reading the document, while others have reported that when many tiddlers have been opened, it can get somewhat confusing.  SinglePageModePlugin allows you to configure TiddlyWiki to navigate more like a traditional multipage web site with only one item displayed at a time.
!!!!!Usage
<<<
When the plugin is enabled, only one tiddler will be displayed at a time and the browser window's titlebar is updated to include the current tiddler title.  The browser's location URL is also updated with a 'permalink' for the current tiddler so that it is easier to create a browser 'bookmark' for the current tiddler.  Alternatively, even when displaying multiple tiddlers //is// permitted, you can still reduce the potential for confusion by forcing  tiddlers to always open at the top (or bottom) of the page instead of being displayed following the tiddler containing the link that was clicked.
<<<
!!!!!Configuration
<<<
<<option chkSinglePageMode>> Display one tiddler at a time
><<option chkSinglePagePermalink>> Automatically permalink current tiddler
><<option chkSinglePageKeepFoldedTiddlers>> Don't close tiddlers that are folded
><<option chkSinglePageKeepEditedTiddlers>> Don't close tiddlers that are being edited
<<option chkTopOfPageMode>> Open tiddlers at the top of the page
<<option chkBottomOfPageMode>> Open tiddlers at the bottom of the page
<<option chkSinglePageAutoScroll>> Automatically scroll tiddler into view (if needed)

Notes:
* {{block{
The "display one tiddler at a time" option can also be //temporarily// set/reset by including a 'paramifier' in the document URL: {{{#SPM:true}}} or {{{#SPM:false}}}. You can also use {{{SPM:expression}}}, where 'expression' is any javascript statement that evaluates to true or false.  This allows you to create hard-coded links in other documents that can selectively enable/disable the use of this option based on various programmatic conditions, such as the current username. For example, using
&nbsp;&nbsp;&nbsp;{{{#SPM:config.options.txtUserName!="SomeName"}}}
enables 'one tiddler at a time' display for all users //other than// "~SomeName")}}}
* If more than one display mode is selected, 'one at a time' display takes precedence over both 'top' and 'bottom' settings, and if 'one at a time' setting is not used, 'top of page' takes precedence over 'bottom of page'.
* When using Apple's Safari browser, automatically setting the permalink causes an error and is disabled.
<<<
!!!!!Revisions
<<<
2008.10.17 2.9.6 changed chkSinglePageAutoScroll default to false
2008.06.12 2.9.5 corrected 'scroll to top of page' logic in auto-scroll handling
2008.06.11 2.9.4 added chkSinglePageKeepEditedTiddlers option
2008.06.05 2.9.3 in displayTiddler(), bypass single/top/bottom mode handling if startingUp.  Allows multiple tiddlers to be displayed during startup processing (e.g., #story:DefaultTiddlers), even if single/top/bottom mode is enabled.
2008.04.18 2.9.2 in displayTiddler() and checkLastURL(), handling for Unicode in tiddler titles (remove explicit conversion between Unicode and UTF, as this is apparently done automatically by encode/decodeURIComponent, resulting in double-encoding!
2008.04.08 2.9.1 don't automatically add options to AdvancedOptions shadow tiddler
2008.04.02 2.9.0 in displayTiddler(), when single-page mode is in use and a tiddler is being edited, ask for permission to save-and-close that tiddler, instead of just leaving it open.
2008.03.29 2.8.3 in displayTiddler(), get title from tiddler object (if needed).  Fixes errors caused when calling function passes a tiddler *object* instead of a tiddler *title*
2008.03.14 2.8.2 in displayTiddler(), if editing specified tiddler, just move it to top/bottom of story *without* re-rendering (prevents discard of partial edits).
2008.03.06 2.8.1 in paramifier handler, start 'checkURL' timer if chkSinglePageMode is enabled
2008.03.06 2.8.0 added option, {{{config.options.chkSinglePageKeepFoldedTiddlers}}}, so folded tiddlers won't be closed when using single-page mode.  Also, in checkURL(), if hash is a ''permaview'' (e.g., "#foo bar baz"), then display multiple tiddlers rather than attempting to display "foo bar baz" as a single tiddler
2008.03.05 2.7.0 added support for "SPM:" URL paramifier
2008.03.01 2.6.0 in hijack of displayTiddler(), added 'title' argument to closeAllTiddlers() so that target tiddler isn't closed-and-reopened if it was already displayed.  Also, added config.options.chkSinglePageAutoScrolloption to bypass automatic 'scroll into view' logic (note: core still does it's own ensureVisible() handling)
2007.12.22 2.5.3 in checkLastURL(), use decodeURIComponent() instead of decodeURI so that tiddler titles with commas (and/or other punctuation) are correctly handled.
2007.10.26 2.5.2 documentation cleanup
2007.10.08 2.5.1 in displayTiddler(), when using single-page or top-of-page mode, scrollTo(0,0) to ensure that page header is in view.
2007.09.13 2.5.0 for TPM/BPM modes, don't force tiddler to redisplay if already shown.  Allows transition between view/edit or collapsed/view templates, without repositioning displayed tiddler.
2007.09.12 2.4.0 added option to disable automatic permalink feature.  Also, Safari is now excluded from permalinking action to avoid bug where tiddlers don't display after hash is updated.
2007.03.03 2.3.1 fix typo when adding BPM option to AdvancedOptions (prevented checkbox from appearing)
2007.03.03 2.3.0 added support for BottomOfPageMode (BPM) based on request from DaveGarbutt
2007.02.06 2.2.3 in Story.prototype.displayTiddler(), use convertUnicodeToUTF8() for correct I18N string handling when creating URL hash string from tiddler title (based on bug report from BidiX)
2007.01.08 2.2.2 use apply() to invoke hijacked core functions
2006.07.04 2.2.1 in hijack for displayTiddlers(), suspend TPM as well as SPM so that DefaultTiddlers displays in the correct order.
2006.06.01 2.2.0 added chkTopOfPageMode (TPM) handling
2006.02.04 2.1.1 moved global variable declarations to config.* to avoid FireFox 1.5.0.1 crash bug when assigning to globals
2005.12.27 2.1.0 hijack displayTiddlers() so that SPM can be suspended during startup while displaying the DefaultTiddlers (or #hash list).  Also, corrected initialization for undefined SPM flag to "false", so default behavior is to display multiple tiddlers
2005.12.27 2.0.0 Update for TW2.0
2005.11.24 1.1.2 When the back and forward buttons are used, the page now changes to match the URL.  Based on code added by Clint Checketts
2005.10.14 1.1.1 permalink creation now calls encodeTiddlyLink() to handle tiddler titles with spaces in them
2005.10.14 1.1.0 added automatic setting of window title and location bar ('auto-permalink').  feature suggestion by David Dickens.
2005.10.09 1.0.1 combined documentation and code in a single tiddler
2005.08.15 1.0.0 Initial Release
<<<
<!--{{{-->
<div class='toolbar' macro='toolbar [[ToolbarCommands::EditToolbar]]'>
<span class='toolbar' macro='gotoTiddler insert'"></span> 
</div>
<div class='title' macro='view title'></div>
<div class='editor' macro='edit title'></div>
<div macro='annotations'></div>
<div macro='toolbar format insert'></div>
<div class='editor' macro='edit text'></div>
<div class='editor' macro='edit tags'></div><div class='editorFooter'><span macro='message views.editor.tagPrompt'></span><span macro='tagChooser excludeLists'></span></div>
<!--}}}-->
/***
|''Name''|TiddlySpaceFilters|
|''Description''|provide TiddlySpace-specific filter extensions|
|''Author''|Jon Robson|
|''Version''|0.6.1|
|''Status''|@@beta@@|
|''CoreVersion''|2.6.2|
|''Requires''|TiddlySpaceConfig|
|''License''|[[BSD|http://www.opensource.org/licenses/bsd-license.php]]|
!Usage
{{{
<<tsList Private>>
<<tsList Public>>
<<tsList Draft>>
}}}
!Code
***/
//{{{
(function($) {

var tiddlyspace = config.extensions.tiddlyspace;
var privateBag = tiddlyspace.getCurrentBag("private");
var publicBag = tiddlyspace.getCurrentBag("public");

config.filterHelpers = {
	is: {
		"private": function(tiddler) {
			var bag = tiddler.fields["server.bag"];
			return bag == privateBag;
		},
		"public": function(tiddler) {
			var bag = tiddler.fields["server.bag"];
			return bag == publicBag;
		},
		draft: function(tiddler) {
			var fields = tiddler.fields;
			var bag = fields["server.bag"];
			return (privateBag == bag && fields["publish.name"]) ? true : false;
		},
		local: function(tiddler) {
			return config.filterHelpers.is["public"](tiddler) ||
				config.filterHelpers.is["private"](tiddler);
		},
		unsynced: function(tiddler) {
			return tiddler ? tiddler.isTouched() : false;
		}
	}
};

config.filters.is = function(results, match) {
	var candidates = store.getTiddlers("title");
	var type = match[3];
	for (var i = 0; i < candidates.length; i++) {
		var tiddler = candidates[i];
		var helper = config.filterHelpers.is[type];
		if(helper && helper(tiddler)) {
			results.pushUnique(tiddler);
		}
	}
	return results;
};

})(jQuery);
//}}}
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xl="http://www.w3.org/1999/xlink" version="1.1" viewBox="450 366 38 57"
width="30" height="30">
	<g stroke="none" stroke-opacity="1" stroke-dasharray="none" fill="none" fill-opacity="1">
		<g>
			<path d="M 452.1094 421.2422 L 450 421.2422 L 450 423 L 487.9688 423 L 487.9688 421.2422 L 485.8595 421.2422 
			L 485.8595 377.29688 L 487.9688 377.29688 L 487.9688 375.53906 L 485.8595 375.53906 
			C 485.8595 375.53906 481.12463 371.59341 473.02023 370.52802 C 472.6824 368.9689 471.72098 366.75 468.9844 366.75 
			C 466.24783 366.75 465.28638 368.9689 464.94864 370.52802 
			C 456.84418 371.59341 452.1094 375.53906 452.1094 375.53906 L 450 375.53906 L 450 377.29688 L 452.1094 377.29688 
			Z M 467.12247 370.32086 L 467.12247 370.32086 C 467.3805 369.42395 467.90762 368.50781 468.9844 368.50781 
			C 470.0612 368.50781 470.5883 369.42395 470.84634 370.32086 
			C 470.24136 370.2848 469.62054 370.26562 468.9844 370.26562 
			C 468.34827 370.26562 467.72748 370.2848 467.12247 370.32086 Z M 454.21875 420.92804 L 454.21875 420.92804 
			C 455.46762 420.42087 456.32816 419.35281 456.32816 418.11716 L 456.32816 377.29688 L 458.4375 377.29688 
			L 458.4375 421.2422 L 454.21875 421.2422 Z M 460.5469 420.92804 L 460.5469 420.92804 
			C 461.79578 420.42087 462.65625 419.35281 462.65625 418.11716 L 462.65625 377.29688 L 464.76566 377.29688 
			L 464.76566 421.2422 L 460.5469 421.2422 Z M 466.87503 420.92804 L 466.87503 420.92804 
			C 468.1239 420.42087 468.9844 419.35281 468.9844 418.11716 L 468.9844 377.29688 L 471.09378 377.29688 
			L 471.09378 421.2422 L 466.87503 421.2422 Z M 473.2032 420.92804 L 473.2032 420.92804 
			C 474.45203 420.42087 475.31256 419.35281 475.31256 418.11716 L 475.31256 377.29688 L 477.4219 377.29688 
			L 477.4219 421.2422 L 473.2032 421.2422 Z M 479.5313 420.92804 L 479.5313 420.92804 
			C 480.78018 420.42087 481.64066 419.35281 481.64066 418.11716 L 481.64066 377.29688 L 483.75006 377.29688 
			L 483.75006 421.2422 L 479.5313 421.2422 Z" fill="black" class="glyph"/>
		</g>
	</g>
</svg>
/***
|''Name''|RandomColorPalettePlugin|
|''Description''|Adds a random color palette to TiddlyWiki|
|''Author''|Jon Robson|
|''Version''|1.4.0|
|''Status''|stable|
|''Source''|https://github.com/jdlrobson/TiddlyWikiPlugins/raw/master/plugins/RandomColorPalettePlugin/RandomColorPalettePlugin.js|
|''License''|[[BSD|http://www.opensource.org/licenses/bsd-license.php]]|
!Usage
{{{
<<RandomColorPalette>>
}}}
Sets and saves a random color palette on execution

{{{
<<RandomColorPaletteButton>>
}}}
Creates a button, which when clicked will change the color palette
More information at http://macros.tiddlyspace.com/#%5B%5BRandomColorPaletteButton%20macro%5D%5D
!Code
***/
//{{{
RGB.prototype.toRGBString = function() {
	return "rgb(%0,%1,%2)".format(parseInt(this.r * 255, 10),
		parseInt(this.g * 255, 10), parseInt(this.b * 255, 10))
}
function HSL_TO_RGB(h, s, l) { // h (hue) between 0 and 360, s (saturation) & l (lightness) between 0 and 1
	var c = l <= 0.5 ? 2 * l * s : ( 2 - (2 * l)) * s;
	var h1 = h / 60;
	var x = c * (1 - Math.abs((h1 % 2) - 1)); 
	var r, g, b;
	if(typeof(h) == 'undefined') {
		r = 0;
		g = 0;
		b = 0;
	} else if(0 <= h1 && h1 < 1) {
		r = c;
		g = x;
		b = 0;
	} else if(1 <= h1 && h1 < 2) {
		r = x;
		g = c;
		b = 0;
	} else if(2 <= h1 && h1 < 3) {
		r = 0;
		g = c;
		b = x;
	} else if(3 <= h1 && h1 < 4) {
		r = 0;
		g = x;
		b = c;
	} else if(4 <= h1 && h1 < 5) {
		r = x;
		g = 0;
		b = c;
	} else if(5 <= h1 && h1 < 6) {
		r = c;
		g = 0;
		b = x;
	}
	m = l - (0.5 * c);
	return new RGB(r + m, g + m, b + m);
}

(function($){
	var macro = config.macros.RandomColorPalette = {
		messagesOn: false, 
		changedPaletteText: "We have assigned you a random theme by adjusting the [[ColorPalette]] tiddler.\nDon't like it? Click <<RandomColorPalette>> for another one.", 
		handler: function(place, macroName, params, wikifier, paramString, tiddler) {
			paramString = paramString || "";
			var options = macro.getOptions(paramString);
			macro.generatePalette(options, true);
		},
		optionTypes: {
			floats: ["hue", "saturation", "darkest", "lightness", "huevariance", "dark", "pale", "light", "mid",
				"saturation_light", "saturation_pale", "saturation_mid", "saturation_dark"
			]
		},
		getOptions: function(paramString) {
			var args = paramString.parseParams("name", null, true, false, true)[0];
			var options = {};
			var numbers = macro.optionTypes.floats;
			for(var i in args) {
				options[i] = numbers.indexOf(i) > -1 ? parseFloat(args[i][0], 10) : args[i][0];
			}
			return options;
		},
		generateRandomNumber: function(min, max, info) {
			var num = (Math.random() * 1);
			info = !info ? { attempts:0 } : info;
			info.attempts += 1;
			var good = true;
			if(min == max) {
				return max;
			}
			if(min && num < min) {
				good = false;
			} else if(max && num > max) {
				good = false;
			}
			if(!good) {
				if(info.attempts < 5) {
					return macro.generateRandomNumber(min, max, info);
				} else {
					if(max) {
						return max;
					} else if(min) {
						return min;
					} else {
						return 1;
					}
				}
			}
			return num;
		},
		getExistingPalette: function(asJSON) {
			var title = "ColorPalette";
			var tiddlerText;
			if(store.tiddlerExists(title)) {
				tiddlerText = store.getTiddlerText(title);
			} else if(store.isShadowTiddler(title)){
				tiddlerText = config.shadowTiddlers[title];
			}
			if(asJSON) {
				var json = {};
				if(tiddlerText) {
					var lines = tiddlerText.split("\n");
					for(var i = 0; i < lines.length; i++) {
						var definition = lines[i].split(":");
						if(definition.length == 2) {
							var name = definition[0].trim();
							var value = definition[1].trim();
							json[name] = value;
						}
					}
				}
				return json;
			} else {
				return tiddlerText;
			}
		},
		generatePalette: function(options, save) {
			var outputRGB = options.rgb;
			var palette = macro.getExistingPalette(true);
			var hue = options.hue || Math.floor(Math.random() * 359);
			var saturation = options.saturation || macro.generateRandomNumber(0.3, 0.7);
			var dark = options.dark || options.darkest || macro.generateRandomNumber(0, 0.10);
			var pale = options.pale || options.lightness || macro.generateRandomNumber(0.90, 1);
			var delta = ( ( pale - dark ) / 3 );
			var mid = options.mid || dark + delta;
			var light = options.light || dark + (delta * 2);
			var lightness_values = {Dark: dark, Mid: mid, Light: light, Pale: pale};
			var saturation_values = {};
			for(i in lightness_values) {
				if(true) {
					saturation_values[i] = options["saturation_" + i.toLowerCase()] || saturation;
				}
			}

			var opposite_hue = (hue + 180) % 360;
			var seed = options.huevariance || Math.floor((85 * Math.random()) + 5); // we want it to be at least 5 degrees
			var huetwo = (opposite_hue + seed) % 360;
			var huethree = (opposite_hue - seed) % 360;
			if(huetwo < 0) {
				huetwo = 360 + huetwo;
			}
			if(huethree < 0) {
				huethree = 360 + huethree;
			}
			for(var j in lightness_values) {
				if(true) {
					var saturation = saturation_values[j];
					palette["Primary" + j] = HSL_TO_RGB(hue, saturation, lightness_values[j]);
					palette["Secondary" + j] = HSL_TO_RGB(huetwo, saturation, lightness_values[j]);
					palette["Tertiary" + j] = HSL_TO_RGB(huethree, saturation, lightness_values[j]);
				}
			}
			palette.Background = HSL_TO_RGB(hue, saturation, 0.92);
			palette.Foreground = HSL_TO_RGB(hue, saturation, 0.08);
			palette.ColorPaletteParameters = ["HSL([", hue, "|", seed, "], [", saturation_values.Pale, "|",
				saturation_values.Light, "|", saturation_values.Mid, "|", saturation_values.Dark, "],",
				"[", dark, "|", mid, "|", light, "|", pale, "])"].join("");
			// construct new ColorPalette
			var text = ["/*{{{*/\n"];
			var colorcode;
			for(var id in palette) {
				if(true) {
					var color = palette[id];
					colorcode = outputRGB ? color.toRGBString() : color.toString();
					text.push("%0: %1\n".format(id, colorcode));
				}
			}
			text.push("/*}}}*/");
			text = text.join("");
			if(save) {
				macro.saveColorPalette(text);
			}
			return text;
		},
		saveColorPalette: function(text) {
			var tid = store.getTiddler("ColorPalette");
			if(!tid) {
				tid = new Tiddler("ColorPalette");
				tid.fields = merge({}, config.defaultCustomFields);
			} // TODO: detect that the ColorPalette in the space comes from outside recipe
			tid.fields["server.page.revision"] = "false"; // edit conflicts dont matter

			// save the color palette in tid
			tid = store.saveTiddler(tid.title, tid.title, text, tid.modifier, tid.modified,
				tid.tags, tid.fields, false, tid.created, tid.creator);
			// an interval is used to cope with users clicking on the palette button quickly.
			if(macro._nextSave) {
				window.clearTimeout(macro._nextSave);
			}
			macro._nextSave = window.setTimeout(function() {
					autoSaveChanges(null, [tid]);
				}, 2000);
			// temporary workaround for IE.
			$.twStylesheet.remove({ id: "StyleSheetColors" });
			$.twStylesheet.remove({ id: "StyleSheet" });
			refreshAll();
			macro.reportChange();
			return tid;
		},
		reportChange: function() {
			if(macro.messagesOn) { // only display message once..
				var msgPlace = getMessageDiv();
				if(!$(".changedPalette", msgPlace)[0]) {
					var tempPlace = document.createElement("div");
					wikify("{{changedPalette{" + macro.changedPaletteText + "}}}", tempPlace);
					msgPlace.appendChild(tempPlace);
				}
			}
		}
	};
	var btnMacro = config.macros.RandomColorPaletteButton = {
			text: "New ColorPalette",
			tooltip: "Generate a random colour scheme for your TiddlyWiki",
			makeButton: function(place, options) {
				var btnHandler = function(ev) {
					var t = $(ev.target);
					var options = t.data("options");
					macro.generatePalette(options, true);
					ev.preventDefault();
					return false;
				};
				var btn = createTiddlyButton(place, this.text, this.tooltip, btnHandler);
				$(btn).data("options", options);
				return btn;
			},
			handler: function(place, macroName, params, wikifier, paramString, tiddler) {
				var options = macro.getOptions(paramString);
				btnMacro.makeButton(place, options);
			}
	};
})(jQuery);
//}}}
!!Data Flow Diagrams
* [[Data Flow Diagram]] - Data Flow Diagrams (DFD) were proposed as the essential view in the historical Structured Analysis and System Specification by Tom ~DeMarco, Yourdon Press, New York, 1978. 
* [[Use Case Diagram]] - Use Case Diagrams (UC) are a very useful communication mean to use with users and stakeholders.
!!Application Archetype
* [[Application Archetype]] - illustrates the fundamental tier and layer organization of a software architecture. 
!!Sequence diagrams
* [[UML Tutorial: Sequence Diagrams - Robert C. Martin - 1998|http://www.objectmentor.com/resources/articles/UMLSequenceDiagrams.pdf]] - In this column we will be discussing UML Sequence diagrams. Sequence diagrams contain the same information as Collaboration diagrams, but emphasize the sequence of the messages instead of the relationships between the objects.
!!CASE Tools
* [[Sparx Enterprise Architect]] - a comprehensive tool that can handle almost all modelling elements and scenarios. This tiddler also lists all my articles on <<tag EA>> usage.
----
@@color:#c4d6ed; ^^
Description: Unified Modelling Language references
^^@@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xl="http://www.w3.org/1999/xlink" version="1.1" viewBox="78 222 60 60" 
width="30" height="30">
<g stroke="none" stroke-opacity="1" stroke-dasharray="none" fill="none" fill-opacity="1">
	<g>
		<path d="M 107.92718 244.14815 L 86.651474 222.89253 L 78.85206 230.69925 L 100.120415 251.9476 L 78.774 273.27396 
		L 86.57342 281.08075 L 107.927216 259.74707 L 129.39981 281.19946 L 137.19922 273.39267 L 115.73397 251.94763 
		L 137.121155 230.58054 L 129.32175 222.77374 Z" fill="black" class="glyph"/>
	</g>
</g>
</svg>
/***
|''Name''|TiddlyWebConfig|
|''Description''|configuration settings for TiddlyWebWiki|
|''Author''|FND|
|''Version''|1.3.2|
|''Status''|stable|
|''Source''|http://svn.tiddlywiki.org/Trunk/association/plugins/TiddlyWebConfig.js|
|''License''|[[BSD|http://www.opensource.org/licenses/bsd-license.php]]|
|''Requires''|TiddlyWebAdaptor ServerSideSavingPlugin|
|''Keywords''|serverSide TiddlyWeb|
!Code
***/
//{{{
(function($) {

if(!config.extensions.ServerSideSavingPlugin) {
	throw "Missing dependency: ServerSideSavingPlugin";
}
if(!config.adaptors.tiddlyweb) {
	throw "Missing dependency: TiddlyWebAdaptor";
}

if(window.location.protocol != "file:") {
	config.options.chkAutoSave = true;
}

var adaptor = tiddler.getAdaptor();
var recipe = tiddler.fields["server.recipe"];
var workspace = recipe ? "recipes/" + recipe : "bags/common";

var plugin = config.extensions.tiddlyweb = {
	host: tiddler.fields["server.host"].replace(/\/$/, ""),
	username: null,
	status: {},

	getStatus: null, // assigned later
	getUserInfo: function(callback) {
		this.getStatus(function(status) {
			callback({
				name: plugin.username,
				anon: plugin.username ? plugin.username == "GUEST" : true
			});
		});
	},
	hasPermission: function(type, tiddler) {
		var perms = tiddler.fields["server.permissions"];
		if(perms) {
			return perms.split(", ").contains(type);
		} else {
			return true;
		}
	}
};

config.defaultCustomFields = {
	"server.type": tiddler.getServerType(),
	"server.host": plugin.host,
	"server.workspace": workspace
};

// modify toolbar commands

config.shadowTiddlers.ToolbarCommands = config.shadowTiddlers.ToolbarCommands.
	replace("syncing ", "revisions syncing ");

config.commands.saveTiddler.isEnabled = function(tiddler) {
	return plugin.hasPermission("write", tiddler) && !tiddler.isReadOnly();
};

config.commands.deleteTiddler.isEnabled = function(tiddler) {
	return !readOnly && plugin.hasPermission("delete", tiddler);
};

// hijack option macro to disable username editing
var _optionMacro = config.macros.option.handler;
config.macros.option.handler = function(place, macroName, params, wikifier,
		paramString) {
	if(params[0] == "txtUserName") {
		params[0] = "options." + params[0];
		var self = this;
		var args = arguments;
		args[0] = $("<span />").appendTo(place)[0];
		plugin.getUserInfo(function(user) {
			config.macros.message.handler.apply(self, args);
		});
	} else {
		_optionMacro.apply(this, arguments);
	}
};

// hijack isReadOnly to take into account permissions and content type
var _isReadOnly = Tiddler.prototype.isReadOnly;
Tiddler.prototype.isReadOnly = function() {
	return _isReadOnly.apply(this, arguments) ||
		!plugin.hasPermission("write", this);
};

var getStatus = function(callback) {
	if(plugin.status.version) {
		callback(plugin.status);
	} else {
		var self = getStatus;
		if(self.pending) {
			if(callback) {
				self.queue.push(callback);
			}
		} else {
			self.pending = true;
			self.queue = callback ? [callback] : [];
			var _callback = function(context, userParams) {
				var status = context.serverStatus || {};
				for(var key in status) {
					if(key == "username") {
						plugin.username = status[key];
						config.macros.option.propagateOption("txtUserName",
							"value", plugin.username, "input");
					} else {
						plugin.status[key] = status[key];
					}
				}
				for(var i = 0; i < self.queue.length; i++) {
					self.queue[i](plugin.status);
				}
				delete self.queue;
				delete self.pending;
			};
			adaptor.getStatus({ host: plugin.host }, null, _callback);
		}
	}
};
(plugin.getStatus = getStatus)(); // XXX: hacky (arcane combo of assignment plus execution)

})(jQuery);
//}}}
There are many obstacles to implementing [[Systematic Reuse]]. Some are practical and technical considerations, some are management attitudes and myths, some are strategic choices, some are just reflex of lack of experience and immaturity.

!Project Centric fanatic views
A common minimalistic management view is to think that projects shall consider only the shortest possible view to accomplish their immediate targets and never consider any medium-term goals, these are top management tasks, project members are just task oriented code doers incapable of taking reasonable medium-term economical decisions.
This has a known effect of stalling technical progress and effectively prevent and even discourage any kind of reuse.

!Lack of established guidelines for namespace and coupling control
Chaotic namespaces ([[filesystem, namespace and packaging|Namespace and Filesystem Guidelines]]) and uncontrolled spaghetti [[coupling|Coupling]] are one of the major technical  obstacles to reuse. They undermine confidence in the profitability of reuse and bring nasty surprises to those who dare to risk reusing. They are, however, quite simple to avoid with proper planning and clear guidelines enforced. I do recommend these two aspects to be addressed at the beginning of any reuse improvement programme. [[Namespace and Filesystem Guidelines]] and [[Namespace Coupling Guidelines]] provide some very simple approaches to deal with the subject.

!Reuse by Copy
[[Reuse by Copy|Reuse by Reference]] is induced by the technical myth that you must completely isolate each project's code from all other projects. This completely impairs continuous improvement of reusable artefacts and creates a nightmare of hacked versions that for sure discourage reusable artefact authors of maintaining and improving them. At the very minimum any reusable artefact shall have an owner and the owner shall be informed of each and every reuse instance and be given the opportunity to know and comment any changes made to the artefact. 

!Lack of established archetypes
Chaotic [[modularizations|Modularization]] often prevent reuse even inside the same project. An established [[archetype|Application Archetype]] catalogue will help in orienting [[modularizations|Modularization]] of your systems in order to reduce [[Coupling]] and increase [[Cohesion]] and these are major factors on reuseability.

!The tool myth
Before choosing tools to manage reuse assets or processes you must be able to produce reusable assets and have those assets. To produce reusable assets you must invest in promoting homogeneity (compatibility) and collaboration (continuous, collaborative improvement). A tool without a method is an obstacle...
See [[Implementing Systematic Reuse]] for, I think, a better approach.

!Concurrent Versioning System methods
Choosing the wrong [[Concurrent Versioning System]] may be one of the worst obstacles to [[Systematic Reuse]]. Certain methods encourage divergence (branching) and do not promote convergence and, thus, [[Continuous Improvement]], collaboration and sharing.
See [[Reuse oriented CVS]].
----
/%
@@color:#c4d6ed; ^^
Description: Reuse Obstacles identification and discussion
^^@@
%/
/***
|''Name''|ToggleTiddlerPrivacyPlugin|
|''Version''|0.7.1|
|''Status''|@@beta@@|
|''Description''|Allows you to set the privacy of new tiddlers and external tiddlers within an EditTemplate, and allows you to set a default privacy setting|
|''CoreVersion''|2.6.1|
|''Requires''|TiddlySpaceConfig|
|''Source''|http://github.com/TiddlySpace/tiddlyspace/raw/master/src/plugins/ToggleTiddlerPrivacyPlugin.js|
!Notes
When used in conjunction with TiddlySpaceTiddlerIconsPlugin changing the privacy setting will also interact with any privacy icons.

Currently use of
{{{<<setPrivacy defaultValue:public>>}}} is in conflict with {{{<<newTiddler fields:"server.workspace:x_private">>}}}

There is an option, found in the tweak tab of the backstage, called txtPrivacyMode. Set this to either ''public'' or ''private'' depending on your security preference. If you choose not to set it then it will default to ''public''.
!Params
defaultValue:[private|public]
Allows you to set the default privacy value (Default is private)

!Code
***/
//{{{
(function($) {

	var tiddlyspace = config.extensions.tiddlyspace,
		macro;
	macro = config.macros.setPrivacy = {
		handler: function(place, macroName, params, wikifier, paramString, tiddler) {
			if(readOnly) {
				return;
			}
			var el = $(story.findContainingTiddler(place)),
				args = paramString.parseParams("name",
					null, true, false, true)[0],
				container = $("<div />").
					addClass("privacySettings").
					appendTo(place)[0],
				currentSpace = tiddlyspace.currentSpace.name,
				currentBag = tiddler ? tiddler.fields["server.bag"] : false,
				// XXX: is the following reliable?
				isNewTiddler = el.hasClass("missing") || !currentBag,
				tiddlerStatus = tiddlyspace.getTiddlerStatusType(tiddler),
				customFields = el.attr("tiddlyfields"),
				defaultValue = "public",
				options = config.macros.tiddlerOrigin ?
						config.macros.tiddlerOrigin.getOptions(paramString) :
						{};
			customFields = customFields ? customFields.decodeHashMap() : {};
			if(isNewTiddler || !["public", "private", "unsyncedPrivate",
					"unsyncedPublic"].contains(tiddlerStatus)) {
				if(args.defaultValue) {
					defaultValue = args.defaultValue[0].toLowerCase();
				} else {
					defaultValue = config.options.chkPrivateMode ?
							"private" : "public";
				}
				defaultValue = defaultValue ?
						"%0_%1".format(currentSpace, defaultValue) :
						customFields["server.bag"];
				this.createRoundel(container, tiddler, currentSpace,
						defaultValue, options);
			}
		},
		updateEditFields: function(tiddlerEl, bag) {
			var saveBagField = $('[edit="server.bag"]', tiddlerEl),
				saveWorkspaceField = $('[edit="server.workspace"]', tiddlerEl),
				input = $("<input />").attr("type", "hidden"),
				workspace = "bags/" + bag;
			if(saveBagField.length === 0) {
				input.clone().attr("edit", "server.bag").val(bag).
					appendTo(tiddlerEl);
			} else {
				saveBagField.val(bag);
			}
			// reset to prevent side effects
			$(tiddlerEl).attr("tiddlyFields", "");
			if(saveWorkspaceField.length === 0) {
				input.clone().attr("edit", "server.workspace").
					val(workspace).appendTo(tiddlerEl);
			} else {
				saveWorkspaceField.val(workspace);
			}
		},
		setBag: function(tiddlerEl, newBag, options) {
			var bagStatus,
				title = $(tiddlerEl).attr("tiddler"),
				tiddler = store.getTiddler(title),
				originButton = $(".originButton", tiddlerEl)[0],
				refreshIcon,
				newWorkspace = "bags/" + newBag,
				rPrivate = $("input[type=radio].isPrivate", tiddlerEl),
				rPublic = $("input[type=radio].isPublic", tiddlerEl);
			refreshIcon = function(type) {
				var originMacro = config.macros.tiddlerOrigin;
				if(originButton && originMacro) {
					options.noclick = true;
					originMacro.showPrivacyRoundel(tiddler, type,
							originButton, options);
				}
			};
			macro.updateEditFields(tiddlerEl, newBag);
			if(tiddler) {
				tiddler.fields["server.bag"] = newBag;
				// for external tiddlers
				tiddler.fields["server.workspace"] = newWorkspace;
			}
			if(newBag.indexOf("_public") > -1) {
				rPrivate.attr("checked", false);
				rPublic.attr("checked", true);
				bagStatus = "public";
			} else {
				rPublic.attr("checked", false); // explicitly do this for ie
				rPrivate.attr("checked", true);
				bagStatus = "private";
			}
			refreshIcon(bagStatus);
		},
		createRoundel: function(container, tiddler, currentSpace,
							   defaultValue, options) {
			var privateBag = "%0_private".format(currentSpace),
				publicBag = "%0_public".format(currentSpace),
				rbtn = $("<input />").attr("type", "radio").
					attr("name", tiddler.title),
				el = story.findContainingTiddler(container);
			rbtn.clone().val("private").addClass("isPrivate").
				appendTo(container);
			$("<label />").text("private").appendTo(container); // TODO: i18n
			rbtn.clone().val("public").addClass("isPublic")
				.appendTo(container);
			$("<label />").text("public").appendTo(container); // TODO: i18n
			$("[type=radio]", container).click(function(ev) {
				var btn = $(ev.target);
				tiddler.fields["server.page.revision"] = "false";
				if(btn.hasClass("isPrivate")) { // private button clicked.
					$(el).addClass("isPrivate").removeClass("isPublic");
					macro.setBag(el, privateBag, options);
				} else {
					$(el).addClass("isPublic").removeClass("isPrivate");
					macro.setBag(el, publicBag, options);
				}
			});
			window.setTimeout(function() {
				macro.setBag(el, defaultValue, options);
			}, 100);
			// annoyingly this is needed as customFields are added to end of EditTemplate so are not present yet
			// and don't seem to respect any existing customFields.
		}
	};

}(jQuery));
//}}}
''Opportunistic Productization is a disciplined management and engineering activity oriented to achieve scale savings and continuous improvement on the opportunity to produce similar solutions for different customers.''

Opportunistic Productization may be seen as an higher level [[Systematic Reuse]].
The concept is useful for project-oriented software houses. It cames into play when you have a Customer request that is similar to something you already developed for another Customer.

In these scenarios you have an opportunity and several dangers. 
The opportunity is to evolve your solution to near an off-the-shelf, high quality, product you will be able to resell more times with almost no cost and very good Customer satisfaction levels. 
The dangers are that you will ''dump price'' (and Customer's perceived value for the solution) and engage in a series of adaptation hacks that, ultimately, will became more expensive than a complete reimplementation. The second risk is that, if you are lucky in the first hack, you will try a second based on the same estimation. This is a severe mistake as [[software rot|Software Rot]] happened for sure in the first adaptation and is more than likely to increase at the second. 

Opportunistic Productization may lead to a full Product Development process but not necessarily. Product Development is a different, and with different methods and techniques, activity.

<<Image "FR" "250" "Gartner-magic-quadrant-animated.gif" "https://dl.dropbox.com/" "s/pl96dh24fvq83r6/" "?dl=1" "Gartner magic quadrants">>
If, in a second, similar, sell you do not have resources for more, at least encourage your team to establish a clear [[Application Archetype]] and [[refactor|Refactor]] what they can towards better [[encapsulation|Encapsulation]] and [[modularization|Modularization]].

In the image on the right you can see an animation using [[Gartner Magic Quadrants|http://www.gartner.com/technology/research/methodologies/research_mq.jsp]] that illustrates your product position along several opportunistic productization cycles. If you took the opportunity your vision and your realisation ability increased so you can now aim to the top right corner. At this point, unless you exhausted the market, productization ability is no longer just an hypotheses, it is a proved fact, now you should consider a proper Product Development Process.
The number of cycles may vary depending on your investment and on the characteristics of the project and the market it targets.

One good rule of thumb to access the quality of a second productization effort is that the results shall be seen as an upgrade opportunity for the prior Customers, that is, the results are more customizable and increased in overall quality. To achieve this you should assure that, at least, technical management stays the same across projects. You must also assure that some, if not all, of the reuse savings are invested in improving the (to be) product.

----
@@color:#c4d6ed; ^^
Description: Opportunistic Productization concept explanation,
^^@@
!SpaceUnplugged
{{unpluggedSpaceTab{
{{wizard{
<<image unsyncedIcon width:48>> Sync is currently unavailable in ~TiddlyWiki due to security constraints in modern browsers. Research is being done to build a suitable alternative. In the meantime if you have changed content in an offline ~TiddlyWiki, you can get your content back into ~TiddlySpace by using the ''import'' functionality from the backstage of the online wiki.
}}}
}}}

!Menu
<<message messages.memberStatus>> <<homeLink>>
{{unsyncedList{<<message messages.syncListHeading>> <<list filter [is[unsynced]]>>}}}

running TiddlySpace@glossary version <<message extensions.tiddlyweb.status.tiddlyspace_version>>
{{autotable{
<<tiddler Backstage##Resources>>
}}}

!Resources
[[blog|@@blog]] [[documentation|@@docs]] [[featured spaces|@@featured]] 

!ImportExport
<<fileImport>>
You can download this TiddlySpace as an offline TiddlyWiki:

{{chunkyButton{<<exportSpace>>}}}

!BackstageTiddlers
|upload a <<message messages.privacySetting>> file: <<binaryUpload>>|<<closeAll>><<permaview>><<newTiddler>><<newJournal "DD MMM YYYY" "journal">><<saveChanges>>|
|>|<<search>>|
|>|<<tiddler Backstage##Tiddlers>>|

!Tiddlers
<<tabs
	txtMainTab
	"Recent" "Recently edited tiddlers" TabTimeline
	"All" "All tiddlers" TabAll
	"Public" "All public tiddlers" [[TiddlySpaceTabs##Public]]
	"Private" "All private tiddlers" [[TiddlySpaceTabs##Private]]
	"Tags" "All tags" TabTags
	"Spaces" "Tiddlers grouped by space" [[TiddlySpaceTabs##Spaces]]
	"Missing" "Missing tiddlers" TabMoreMissing
	"Orphans" "Orphaned tiddlers" TabMoreOrphans
	"Shadows" "Shadowed tiddlers" TabMoreShadowed
>>

!BatchOps
<<tabs
	txtPublisherTab
	"Private" "Move tiddlers from private to public" Backstage##BatchPrivate
	"Public" "Move tiddlers from public to private" Backstage##BatchPublic
>>

!BatchPrivate
<<TiddlySpacePublisher type:private>>

!BatchPublic
<<TiddlySpacePublisher type:public>>

!Plugins
''Note:'' Many of these plugins are core TiddlySpace plugins and cannot be changed unless first cloned.

<<tiddler PluginManager>>

!Tweaks
These options change behavior in TiddlyWiki //only// and may be ineffective in TiddlySpace.

<<tiddler AdvancedOptions>>
"//Fundamental to any science or engineering discipline is a common vocabulary for expressing its concepts, and a language for relating them together. The goal of patterns within the software community is to create a body of literature to help software developers resolve recurring problems encountered throughout all of software development. Patterns help create a shared language for communicating insight and experience about these problems and their solutions.//"

Brad Appleton on [[The Hillside Group|http://hillside.net/patterns/]]

----
/%
@@color:#c4d6ed; ^^
Description: Brad Appleton on patterns and communication
^^@@
%/
/***
|''Name''|TiddlySpaceRevertRevision|
|''Description''|Revert to a previous revision|
|''Author''|BenGillies|
|''Version''|0.1|
|''Status''|unstable|
|''Source''|http://github.com/TiddlySpace/tiddlyspace|
|''CodeRepository''|http://github.com/TiddlySpace/tiddlyspace|
|''License''|[[BSD|http://www.opensource.org/licenses/bsd-license.php]]|
|''CoreVersion''|2.6.0|
|''Requires''|TiddlyWebAdaptor TiddlySpaceRevisionView|
!Usage
Add a control button to revert to a particular revision.

The button must be called from within a revision, as generated by TiddlySpaceRevisionView
!Code
***/
//{{{
(function($) {

config.commands.revert = {
	text: "revert",
	tooltip: "make this revision the current one",
	handler: function(ev, src, title) {
		var revElem = story.getTiddler(title);
		var tidToRevert = store.getTiddler($(revElem).attr("revName"));

		var revision = store.getTiddler(title);
		if ((revision) && (tidToRevert)) {
			tidToRevert.text = revision.text;
			var newFields = merge({}, revision.fields);
			for (var fieldName in newFields) {
				if (fieldName.substr(0, 7) === "server.") {
					delete newFields[fieldName];
				}
			}
			merge(tidToRevert.fields, newFields);
			tidToRevert.tags = merge([], revision.tags);
			tidToRevert.fields.changecount = 1;
			delete tidToRevert.fields.doNotSave;

			store.saveTiddler(tidToRevert.title, tidToRevert.title,
				tidToRevert.text, null, null, tidToRevert.tags,
				tidToRevert.fields, false, tidToRevert.created, tidToRevert.creator);

			autoSaveChanges(true);
		}
	}
};

})(jQuery);
//}}}
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xl="http://www.w3.org/1999/xlink" version="1.1" viewBox="2 724 68 55" 
width="30" height="30">
<g stroke="none" stroke-opacity="1" stroke-dasharray="none" fill="none" fill-opacity="1">
	<g>
		<path d="M 2.25 756 L 11.25 747 L 24.75 760.4994 L 60.750004 724.4994 L 69.75 733.49902 
		L 24.749977 778.49976 Z" fill="#101010" class="glyph"/>
	</g>
</g>
</svg>
/***
|''Name''|ImportExternalLinksPlugin|
|''Author''|Jon Robson|
|''Version''|0.3.0|
|''Requires''|TiddlySpaceConfig TiddlySpaceLinkPlugin TiddlySpaceCloneCommand|
|''Description''|Turns space links into ajax links so you don't have to leave the comfort of your own TiddlyWiki|
!Notes
This maybe should hides the editTiddler, cloneTiddler commands. Ideally the toolbar commands should hide themselves but we need a strong concept of "this is a sucked in tiddler" to do that.
***/
//{{{
(function($){
var tiddlyspace = config.extensions.tiddlyspace;
_createSpaceLink = createSpaceLink;
if(_createSpaceLink) {
	createSpaceLink = function(place, spaceName, title, alt, isBag) {
		var tooltip = "Click to open in current document. Right click to open in original space.";
		_createSpaceLink(place, spaceName, title, alt, isBag);
		var workspace;
		if(isBag) {
			workspace = "bags/%0".format(spaceName);
		} else {
			workspace = "bags/%0_public".format(spaceName);
		}
		if(title && spaceName != tiddlyspace.currentSpace.name) {
			var link = $("a:last", place);
			var newlink = $("<a />").text("[link]").after(link[0]);
			// very hacky
			var updateInterval = setInterval(function() {
				var href = link.attr("href");
				if(href) {
					$(newlink).attr("href", href);
					clearInterval(updateInterval);
				}
			}, 200);
			
			if(link.parent(".replyLink").length == 0) { // don't suck in a reply link.
				link.attr("title", tooltip).addClass("importLink").click(function(ev) {
					if(config.floorboards) {
						config.floorboards.pushUnique("%0_public".format(spaceName));
					}
					tiddlyspace.displayServerTiddler(ev.target, title, workspace, function(el) {
						// TODO: the commands should disable themselves based on the meta information.
						//$("[commandname=editTiddler], [commandname=cloneTiddler]", el).hide(); 
					});
					ev.preventDefault();
				});
			}
		}
	};
}

var _cloneHandler = config.commands.cloneTiddler.handler;
config.commands.cloneTiddler.handler = function(event, src, title) {
	var _tiddler = store.getTiddler(title);
	var source = _tiddler ? _tiddler.fields["server.bag"] : false;
	var imported = _tiddler ? _tiddler.fields["tiddler.source"] : false;
	var realTitle = _tiddler ? _tiddler.fields["server.title"] : title;
	_cloneHandler.apply(this, [event, src, title]);
	var tidEl = story.getTiddler(title);
	$(story.getTiddlerField(title, "title")).val(realTitle);
	if(source) {
		$("<input />").attr("type", "hidden").attr("edit", "tiddler.source").val(source).appendTo(tidEl);
		$("<input />").attr("type", "hidden").attr("edit", "server.activity").appendTo(tidEl);
	}
}
})(jQuery);
//}}}
var user, userbag;
var friends = [];
var host = "http://tiddlyspace.com";

$.ajaxSetup({
	beforeSend: function(xhr) {
		xhr.setRequestHeader("X-ControlView", "false");
	}
});

function printMessage(txt) {
	alert(txt);
}

function printError(txt) {
	alert(txt);
}

var simpleDate = (function() {

	var measures = {
		second: 1,
		minute: 60,
		hour: 3600,
		day: 86400,
		week: 604800,
		month: 2592000,
		year: 31536000
	};

	var chkMultiple = function(amount, type) {
		return (amount > 1) ? amount + " " + type + "s":"a " + type;
	};

	return function(thedate) {

		var dateStr, amount,
			current = new Date().getTime(),
			diff = (current - thedate.getTime()) / 1000; // work with seconds

		if(diff > measures.year) {
			amount = Math.round(diff/measures.year);
			dateStr = "about " + chkMultiple(amount, "year") + " ago";
		} else if(diff > measures.month) {
			amount = Math.round(diff/measures.month);
			//if(typeof amount == "")
			dateStr = "about " + chkMultiple(amount, "month") + " ago";
		} else if(diff > measures.week) {
			amount = Math.round(diff/measures.week);
			dateStr = "about " + chkMultiple(amount, "week") + " ago";
		} else if(diff > measures.day) {
			amount = Math.round(diff/measures.day);
			dateStr = "about " + chkMultiple(amount, "day") + " ago";
		} else if(diff > measures.hour) {
			amount = Math.round(diff/measures.hour);
			dateStr = "about " + chkMultiple(amount, "hour") + " ago";
		} else if(diff > measures.minute) {
			amount = Math.round(diff/measures.minute);
			dateStr = "about " + chkMultiple(amount, "minute") + " ago";
		} else {
			dateStr = "a few seconds ago";
		}

		return dateStr;

	};
})();

function prettyDate(t) {
	var date = new Date(Date.UTC(
		parseInt(t.substr(0, 4), 10),
		parseInt(t.substr(4, 2), 10) - 1,
		parseInt(t.substr(6, 2), 10),
		parseInt(t.substr(8, 2), 10),
		parseInt(t.substr(10, 2), 10),
		parseInt(t.substr(12, 2) || "0", 10),
		parseInt(t.substr(14, 3) || "0", 10)
	));
	return simpleDate(date);
}

function endsWith(str, suffix) {
	return str.indexOf(suffix) == str.length - suffix.length;
}

function isShadow(tid) {
	var shadows = ["MarkupPreHead", "DefaultTiddlers", "PageTemplate", "SideBarTabs",
		"GettingStarted", "MainMenu", "SiteTitle", "SiteSubtitle", "ColorPalette",
		"SiteIcon", "ViewTemplate", "EditTemplate", "ServerSettings", "MarkupPostHead",
		"MarkupPostBody", "MarkupPreBody"];
	return tid.title.indexOf("StyleSheet") === 0 ||
		tid.title.indexOf("SideBar") === 0 ||
		shadows.indexOf(tid.title) > -1 || endsWith(tid.title, "SetupFlag") ? true : false;
}

function isPlugin(tid) {
	return tid.tags.indexOf("systemConfig") > -1 ? true : false;
}

function isArtifact(tid) {
	var follow = tid.tags.indexOf("follow") > -1;
	var type = tid.type;
	if(follow || type) {
		return true;
	} else {
		return false;
	}
}

function chooseTiddlers(tiddlers) {
	var _tiddlers = [];
	for(var i = 0; i < tiddlers.length; i++) {
		var tid = tiddlers[i];
		if(!isPlugin(tid) && !isShadow(tid) && !isArtifact(tid)) {
			_tiddlers.push(tid);
		}
	}
	return _tiddlers;
}

function bubbleDown() {
	var friends = $(".friend");
	friends.css({ position: "relative" });
	var target;
	friends.each(function(i, el) {
		if(!target && $(el).hasClass("silentFriend") &&
			$(el).next(".friend").hasClass("noisyFriend")) {
			target = el;
		}
	});
	if(target) {
		var other = $(target).next(".friend");
		// we want to move target above the prev element
		// target is an element which has the class noisy and the previous node is quiet
		var swapDuration = 50;
		var otherHeight = other.height();
		var thisHeight = $(target).height();
		$(target).animate({ top: + otherHeight }, { duration: swapDuration });
		$(other).animate({ top:  - thisHeight }, { duration: swapDuration,
				complete: function() {
					var newTarget = $(target).clone(true).insertAfter(other)[0];
					$(target).remove();
					$(other).css({ top: 0 });
					$(newTarget).css({ top: 0 });
					bubbleDown();
				}
		});
	}
}

function renderTiddlerList(container,friend) {
	var tidList = $("<ul />").appendTo(container)[0];
	$("<li />").text("loading").appendTo(tidList);
	var oncompletion = function() {
		if($(".errorFriend,.silentFriend,.noisyFriend").length === $(".friend").length) {
			bubbleDown();
		}
	}
	$.ajax({ dataType: "json",
		url: "/search?q=modifier:" + friend + "&select=modified:>3d&sort=-modified",
		error: function() {
			$(container).addClass("errorFriend");
			oncompletion();
		},
		success: function(tiddlers) {
			$(tidList).empty();
			tiddlers = chooseTiddlers(tiddlers);
			if(tiddlers.length === 0) {
				$(container).addClass("silentFriend");
				$("<li />").text("No recent activity.").appendTo(tidList);
				oncompletion();
				return;
			} else {
				$(container).addClass("noisyFriend").removeClass("inactiveFriend");
				oncompletion();
			}
			for(var i=0; i < tiddlers.length; i++) {
				var tiddler = tiddlers[i];
				var item = $("<li />").appendTo(tidList)[0];
				var win;
				var space = tiddler.bag.split("_")[0];
				var spaceUrl = "http://" + space + ".tiddlyspace.com";
				var path = "/bags/" + tiddler.bag + "/tiddlers/" + encodeURIComponent(tiddler.title);
				var link = $("<a />").text(tiddler.title).
					attr("href", spaceUrl + path).
					data("path", path).
					click(function(ev) {
						var win = $(ev.target).data("win");
						if($(ev.target).hasClass("active")) {
							$(win).toggle(1000);
						} else {
							$(ev.target).addClass("active");
							$(".text", win).text("loading...");
							$(win).show();
							$.ajax({
								url: $(ev.target).data("path"),
								data: {
									render: "y"
								},
								dataType: "json",
								success: function(tiddler) {
									$(".text",win).html(tiddler.render);
									$(win).show(1000);
								},
								error: function() {
									$(".text", win).text("error loading that tiddler");
								}
							});
						}
						ev.preventDefault();
					}).
					appendTo(item)[0];
				var space = tiddler.bag.split("_")[0];
				$("<span />").text(" in ").appendTo(item);
				$("<a />").attr("href", spaceUrl).text(space).appendTo(item);
				$("<span />").text(" (" + prettyDate(tiddler.modified) + ")").appendTo(item);
				win = $("<div />").addClass("tiddler").appendTo(item)[0];
				$("<div />").addClass("text").appendTo(win);
				var toolbar = $("<div />").addClass("toolbar").appendTo(win)[0];
				var extra = $("<div />").addClass("extra").appendTo(win)[0];
				$("<button />").data("bag", tiddler.bag).data("title", tiddler.title).text("give feedback").
					data("revision", tiddler.revision).click(function(ev) {
					var title = $(ev.target).data("title");
					var revision = $(ev.target).data("revision");
					var bag = $(ev.target).data("bag");
					var revisionURL = host + "/bags/" + bag + "/tiddlers/" + encodeURIComponent(title) + "/revisions/" + revision;
					var space = bag.split("_")[0];
					var area = $(ev.target).parents(".tiddler").children(".extra")[0];
					$(area).hide();
					$("<textarea />").appendTo(area);
					$("<button />").text("save feedback").click(function(ev) {
						var tid = new tiddlyweb.Tiddler("Feedback for " + title, userbag);
						tid.tags = ["feedback", "@" + space];
						tid.text = ["In reply to [[", title, "]]@", space,
							" (revision [[", revision, "|", revisionURL, "]])\n\n"].join("") + $("textarea", area).val();
						tid.put(function(tiddler) {
							$(area).empty();
							$("<span />").text("your comment: ").appendTo(area);
							$("<a />").attr("href", "/" + encodeURIComponent(tiddler.title)).text(tiddler.title).appendTo(area);
						}, function() {
							printError("error commenting!");
						});
					}).appendTo(area);
					$(area).show(1000);
					ev.preventDefault();
					$(ev.target).remove();
					return false;
				}).appendTo(toolbar);

				$(win).hide();
				$(link).data("win", win);
			}
		}
	})
}

function removeFriend(friend) {
	var tiddler = new tiddlyweb.Tiddler("@" + friend, userbag);
	var success = function() {
		printMessage("User removed from friends");
		var newFriends = [];
		for(var i = 0; i < friends.length; i++) {
			var f = friends[i];
			if(f !== friend) {
				newFriends.push(f);
			}
		}
		friends = newFriends;
		$("#friend-" + friend).hide(2000);
	};
	tiddler["delete"](success, function() {
		var old = new tiddlyweb.Tiddler(friend, userbag);
		old["delete"](success, function() {
			printError("Unable to remove friend " + friend);
		})
	})
}

function renderFriend(list, friend) {
	var bag = friend + "_public";
	var item = $("<li />").addClass("friend").attr("id", "friend-" + friend).addClass("inactiveFriend").appendTo(list)[0];
	$("<img />").attr("alt", friend).attr("title", friend).
		attr("src", host + "/bags/" + bag + "/tiddlers/SiteIcon").css({ width: 48, height: 48 }).appendTo(item);
	var heading = $("<h2>").appendTo(item)[0];
	$("<a />").attr("href", "#friend-" + friend).attr("name", "friend-" + friend).text(friend).appendTo(heading);
	$("<button />").data("who", friend).text("remove from friends").
		click(function(ev) {
			if(confirm("Are you sure you want to remove " + friend + " as a friend?")) {
				removeFriend($(ev.target).data("who"));
			}
		}).appendTo(item)[0];
	renderTiddlerList(item,friend);
}

function renderFriends() {
	var list = $("<ul />").appendTo("#friends")[0];
	$("<li />").text("Activity of your friends will appear below when available").appendTo(list);
	for(var i = 0; i < friends.length; i++) {
		var friend = friends[i];
		renderFriend(list, friend);
	}
}

function followWidget() {
	$("#friends").empty();
	var container = $("<div />").addClass("addfriends").appendTo("#friends")[0];
	$("<input />").attr("name", "friend").appendTo(container);
	$("<button />").text("add friend").click(function(ev) {
		var friend = $(ev.target).parent().children("[name='friend']").val();
		if(friends.indexOf(friend) > -1) {
			return printError("You already follow " + friend + "!");
		}

		var title;
		if(friend.indexOf("@") !== 0) {
			title = "@" + friend;
		} else {
			title = friend;
		}

		$.ajax({ dataType: "text", url: "/users/" + friend,
			success: function() {
				var tid = new tiddlyweb.Tiddler(title, userbag);
				tid.tags = ["follow", "excludeLists"];
				tid.put(function(tiddler) {
					printMessage("Added friend " + friend);
					renderFriend($("#friends ul")[0], friend);
					window.location.hash = "#friend-" + friend;
				}, function() {
					printError("Failed to add friend " + friend);
				})
			},
			error: function() {
				printError("No one with name " + friend + " exists!");
			}
		});
	}).appendTo(container);
	renderFriends();
}
$.ajax({
	url: "/status",
	dataType: "json",
	success: function(status) {
		user = status.username;
		userbag = new tiddlyweb.Bag(user + "_public", "/");
		$.ajax({ url: "/bags/" + user + "_public/tiddlers?select=tag:follow", dataType: "json", success: function(tiddlers) {
				for(var i = 0; i < tiddlers.length; i++) {
					var title = tiddlers[i].title;
					if(title.indexOf("@") === 0) {
						title = title.substr(1, title.length);
					}
					friends.push(title);
				}
				friends.sort();
				followWidget();
			}
		});
	}
})
!Tag page for OOP (Object Oriented Programming)

[[From Wikipedia, the free encyclopedia|http://en.wikipedia.org/wiki/Object-oriented_programming]] - Object-oriented programming (OOP) is a programming paradigm using "objects" – data structures consisting of data fields and methods together with their interactions – to design applications and computer programs. Programming techniques may include features such as [[data abstraction, encapsulation, messaging, modularity, polymorphism, and inheritance|ObjectOrientedProgramming]]. Many modern programming languages now support OOP, at least as an option.

The main entry point for the subject on this wiki is [[Object Oriented Programming|ObjectOrientedProgramming]] page.

!Welcome to André de Carvalho's ~TiddlySpace profile.

I'm involved with Software Development since the 80's and have worked from Turbo Pascal (3.01a), Clipper and Fox Pro (on SCO Xenix ;), through Delphi and now I mostly use C#.

I'm clearly a data-oriented ~WinForms guy that hates to "//program in XML//" and has not too much patience for browser limitations. 

Maybe I'm old fashioned but I do like good conceptual data models, the challenge of investigating a business problem and produce an elegant object oriented architectural solution and then to implement a robust and performance wise application that is expandable and reusable.

Wikis, and specially [[TiddlyWiki|http://www.tiddlywiki.com/]], were the first browser application that really interested me and now I'm starting to discover [[TiddlySpace|http://tiddlyspace.com/]]...

[[My Wiki|http://acarvalho.tiddlyspace.com/]] at ~TiddlySpace gathers information and my thoughts about Software Development processes, techniques, methodologies and concepts that others my find useful.

I do encourage you to interact with my space if you share some interest on these subjects.

----
@@color:#c4d6ed; ^^
Description: André de Carvalho's ~TiddlySpace profile
^^@@
Scope : Elements, Packages
<<Image "FR" "350" "EA%20Element%20Properties%20-%20Status%20and%20Version.jpg" "https://dl.dropbox.com/" "s/tjoknyicii3ssm9/" "?dl=1" "EA element properties dialog.">>
The following topics establish the state flow for elements of the model in their ''Status'' attribute.
The Status attribute is a main filtering factor and shall be used to clearly state the development status of each element and to identify what is already done and what needs to be done towards them.

Status is a major reporting and management item as it allows to filter the different completion state of the elements therefore providing good situational awareness and even quantitative assessments.
Unfortunately in EA the state's list is shared for all element types so you must have different states and state flows for different elements but the dropbox of each element will show them all. A clear state chart for each type is, therefore, essential to allow for a coherent and useful usage of the attribute. 

Take notice that not all of the states shall be used in each concretization phase.
Status is closely related with [[Version|EA Usage - Attribute Version]] and, typically, it is a status transition that triggers version changes.
!!Requirements and Features
In Requirements and Features the status attribute is used, primarily, to convey information about what is done and what is to be done. It is also used to mark baselined elements, that is, elements that can not be changed without proper cautions.
<<Image "FR" "350" "EA%20Element%20Properties%20-%20Status%20%28FT-SR%29.jpg" "https://dl.dropbox.com/" "s/ejokdrbg24bxoa6/" "?dl=1" "Features and Requirements">>
*DRAFT
**Scope : all elements.
**The element has been sketched by Customer or team member It is in an initial state and needs further work and validation. 
*REVIEWED
**Scope : all elements.
**The DRAFT element has been reviewed and approved by team leadership.
**It may be presented to Customer for Validation. 
*VALIDATED
**Scope : Requirement or Feature.
**The Requirement or Feature has been informally validated by Stakeholders.
**Further changes shall change minor version and regress to DRAFT. 
*APPROVED
**Scope : Requirement or Feature.
**The element is formally approved by the Customer.
**From this point on formal Change Management procedures apply.
**Major version is set to 1. On change it shall increment. 
*SPECIFIED
**Scope : Requirement.
**The requirement has been assigned to a Component and Acceptance Tests defined. 
*IMPLEMENTED
**Scope : Requirement or Feature.
**The element has been implemented. 
*UPDATED
**Scope : Requirement or Feature.
**The element has been updated to reflect implementation changes/improvements.
**Minor version is incremented. 
*TESTED
**Scope : Requirement or Feature.
**Implementation of the element has been Verified and Validated. 

----
See also : [[Sparx Enterprise Architect]]
/%
@@color:#c4d6ed; ^^
Description: Enterprise Architect attribute usage guideline - Status
^^@@
%/
Scope : Elements, Packages
Values : Low | Medium | High
<<Image "FR" "350" "EA-Element-Properties-Difficulty.png" "https://dl.dropbox.com/" "s/al3olln0c4xkpuh/" "?dl=1" "EA element properties dialog.">>
The difficulty attribute shall be used to identify areas (features, requirements, modules) that present major challenges to the project.
This is very important for estimation, planning, know-how gathering, testing and risk management.

We propose the use of a very simple three level scale :
|Level|Description|h
|Low|Below normal complexity. Well known domain with available experience and proved implementations. Formal reusable module available as-is. Low, stable and known business complexity.|
|Medium|Normal implementation problem where we do not expect major issues. No new technologies. Medium business complexity|
|High|Domain novelty (technical or business). Complex, not stable business definition. Severe performance, security or availability constraints. Criticality.|

The difficulty determination shall start at [[RFP analysis|RFP Analysis Guidelines]] and be a major concern at [[Technical Proposal|Technical Proposal Production Guidelines]] specially in the Major Challenges chapter. It is also very important on [[Specification|Software Specification]] to help selecting the main targets for testing and the modules that present more risk and need more attention.
On Estimation, specially if you use a [[PERT]] three point estimate, this identification will be very useful to establish, and justify, the pessimistic and optimistic offset of each task.
----
See also : [[Sparx Enterprise Architect]]
/%
@@color:#c4d6ed; ^^
Description: Enterprise Architect attribute usage guideline - Difficulty
^^@@
%/
<<Image "FR" "350" "EA-Usage-Requirements-Diagram.png" "https://dl.dropbox.com/" "s/qltfyj1odu0elud/" "?dl=1" "EA requirements diagram.">>
The Requirements Diagram is an Extended (non UML) diagram used in Inception and Specification stages.
Its main usage is to capture statements that define scope, behaviour and requirements of the system to be developed. It is also used to relate [[Features|Feature]] and [[Requirements|Software Requirement]] with Issues, Assumptions and Ideas.

Features and Requirements (and Ideas, Issues and Assumptions) have some common characteristics :
*they are univocal elements, that is, they are numbered in a way that makes them unique in the model scope.
*their information is normalized, that is, they should not have redundant or duplicated statements
*they are atomic, that is, their statement and status (and other attributes) shall not depend on each other but be contained in a single element. This clearly excludes approaches with requirements inside other requirements or dependency relationships between requirements. Of course Package inclusion provides a common context and an implicit relationship for contained requirements but no stronger ties shall be established between requirements at the same concretisation level.

The requirements are the most concrete expression and they must follow a strict [[SMART Requirements]] guideline, on the other hand, Proposed Features and, specially, Requested Features are allowed a more relaxed expression guideline. Never forget, however, that Proposed Features are what establishes scope and support estimation.

Requirement type elements (Requirement, Feature, Issue, etc.) shall be as atomic as possible in order to allow to control state (an element shall always have a defined, unambiguous state) and contain change impact. Atomicity is also an essential characteristic if we want to extract quantitative volume metrics of these elements in any meaningful way, and these are essential for objective management and planing.
For requirement elements of the same kind, in the same life-cycle phase (or concretisation stage), shared context and conceptual or logical grouping shall be provided by package inclusion and not by any other kind of relationship. That is, you shall not compose Proposed Features with other Proposed Features or make them dependent from each other. Even association relationships are not advisable in this scenario. Of course this is not the case of relationships of different kind. A Proposed Feature may depend on an Assumption, a Requested Feature may depend on an Issue, a Proposed Feature shall dependency trace to a Requested Feature, etc. Also a Proposed Feature or Software Requirement may be made composite to include a State Machine or other diagram if it helps to explain it.

<<Image "FR" "350" "EA-Usage-Requirements-Diagram-elements.png" "https://dl.dropbox.com/" "s/gdgy4qju10mby8u/" "?dl=1" "EA requirements diagram, other elements.">>
Requested Features, Proposed Features and Software Requirements may ''Depend'' on ''Issues'' and ''Assumptions'' and they also may be ''Associated'' to ''Ideas''.
''Issues'' are questions or doubts or pending matters that are essential to understand, specify or implement the dependent elements.
''Assumptions'' are choices or scenarios that we assume as true and that are a condition to dependent elements.
''Ideas'' are ideas, that is, opportunities, improvements, further business that we identify along the project and that we preserve this way for future reference when and if the opportunity emerges.

----
See also : [[Sparx Enterprise Architect]] [[Writing Good Requirements]]
/%
@@color:#c4d6ed; ^^
Description: Enterprise Architect diagram usage guideline - Requirements
^^@@
%/
Once you have some content then you may choose to determine a tiddler, or set of tiddlers to display each time you load ~TiddlySpace. This is determined by the [[DefaultTiddlers]].
<!DOCTYPE html>
<html>
<head>
	<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
	<title>This Space</title>
	<link href="/bags/common/tiddlers/profile.css" type='text/css' rel='stylesheet' >
	<link href="/bags/common/tiddlers/admin.css" type='text/css' rel='stylesheet' >
	<!--[if lte IE 8]>
	<script type="text/javascript" src="/bags/common/tiddlers/json2.js"></script>
	<script type="text/javascript" src="/bags/common/tiddlers/es5-shim.min.js"></script>
	<![endif]-->
</head>
<body>
<div id="container">
	<div id="text-html" class="main section">
		<a class="app" href="/">home</a>
		<div class="left">
		<h2>About this space <button class='toggleNext'></button></h2>
		<div id="siteinfo"></div>
		<h2>Site Icon</h2>
		<div>
			<img id="siteicon" class="siteicon">
			<form id="upload" method="POST" enctype="multipart/form-data">
				<input type="hidden" name="title" value="SiteIcon" />
				<input type="hidden" name="tags" value="excludeLists">
				<input type="hidden" name="csrf_token" class="csrf" />
				<input type="file" name="file" accept="image/*" />
				<input class="btn" type="submit" value="upload" />
			</form>
			<div id="dropzone">Drop file here
				<img class="notloading" src="/bags/common/tiddlers/ajax-loader.gif" alt="submitting SiteIcon" />
			</div>
		</div>
		<h2>Vital Statistics</h2>
		<div id="info">please wait while information is loaded about this space...</div>
		<button class="spacereset">Reset Space</button>
		<div class="reset-confirm-wrap messageArea">
			<button class="close-btn" title="cancel reset">×</button>
			<p>Are you sure you want to reset the space? You can't go back! This will remove all the content from the space!</p>
			<form class="cf">
				<label for="reset-confirm">Enter the space name to confirm.</label>
				<input type="text" name="reset-confirm" class="reset-confirm-input inputBox" />
				<button type="submit">Reset Now</button>
			</form>
			<div class="reset-message-area">
				<p class="performing">Resetting...</p>
				<p class="finished">Reset Done!</p>
				<p class="recipe-error-msg">Error removing includes. Please remove manually.</p>
			</div>
		</div>
		</div>
		<div class="right">
		<div class="ts-membership">
			<h2>
				Add Member
				<a href="http://docs.tiddlyspace.com/What%20is%20a%20member%3F" title="What is a Member?" class="help">What is a Member?</a>
			</h2>
			<div>
				<p>Add a new member to your space by entering their name below. Enter a space name instead and prefix with @ to add everyone who is already a member of that space.</p>
				<form class="ts-members">
					<input class="inputBox" type="text" name="username">
					<input type="submit" value="Add Member" class="btn" />
				</form>
			</div>
			<h2>
				Existing Members <button class='toggleNext'></button>
			</h2>
			<div>
				Your space currently has the following members: 
				<ul class="ts-members"></ul>
			</div>
			<h2>
				Include Space
				<a class="help" href="http://docs.tiddlyspace.com/What%20is%20space%20inclusion%3F" title="What is inclusion?">What is Inclusion?</a>
			</h2>
			<form class="ts-includes">
				<input class="inputBox" type="text" name="spacename">
				<input type="submit" value="Include Space" class="btn" />
			</form>
		</div>
		<div>
			<h2>Included Spaces <button class='toggleNext'></button></h2>
			<div>
			This space includes the following spaces:
			<ul class="ts-includes"></ul>
			</div>
		</div>
		</div>
		<div class="clear"></div>
	</div>
</div>
<script src='/bags/common/tiddlers/backstage.js'></script>
<script src='/bags/common/tiddlers/jquery.js'></script>
<script src='/bags/tiddlyspace/tiddlers/chrjs'></script>
<script src='/bags/common/tiddlers/chrjs.space'></script>
<script src='/bags/common/tiddlers/chrjs.users'></script>
<script src='/bags/common/tiddlers/chrjs.identities'></script>
<script src='/bags/tiddlyspace/tiddlers/TiddlySpaceCSRF'></script>
<script src='/bags/common/tiddlers/jquery-form.js'></script>
<script src="/bags/common/tiddlers/siteiconupload.js"></script>
<script src="/bags/common/tiddlers/ts.js"></script>
<script src="/status.js"></script>
<script src="/bags/common/tiddlers/space.js"></script>
</body>
</html>
[[Reuse by Reference]] has to face several obstacles and, if not properly planned and supported, will produce a nightmare in maintenance and development. But, on the other hand, [[Reuse by Reference]] is the only way to achieve [[Continuous Improvement]] on reusable assets and to capitalize inter-project and inter-team synergies. That's the difference between a solo freelancer developer and a team in a solid and mature company.

This approach assumes you are using a proper [[CVS]] system that holds all your project's data and reusable assets.

!!Filesystem 
The first concern shall be to put in place a proper filesystem structure and reuse strategy that is used, known, and enforced, among all your projects. Your filesystem structure and reuse strategy shall be part of your shared infrastructure specification.

The filesystem shall have folders for, among others, specification items, quality management, project plans and, of course, code. Inside the code folder you must use relative paths for your dependencies and, if you want to share reusable code, you may use the CVS system to produce something like symbolic links, that is, you may checkout reusable modules to the project's filesystem keeping relative dependencies stable and the base code in a shared common place.

The option of checking out common code to the project's folder and not to a shared location intends to allow for each project to depend on specific versions of the reused modules and also to only have to deal with the modules you indeed reuse in each project and not with all of your reusable assets.

On the next image you can see an example of a filesystem structure that promotes [[Reuse by Reference]] and allows for reusable modules to be stored at a central shared location on [[CVS]] while being used (and edited) at each project's filesystem.
<<Image "FR" "" "Reuse%20Filesystem%20Structure.jpg" "https://dl.dropbox.com/" "s/ddp713d8htzcihs/" "?dl=1" "Filesystem structure for reuse.">>
On the left is the [[CVS]] filesystem structure organized according to our proposed [[Namespace and Filesystem Guidelines]], on the right is the development filesystem structure, that is, the checked out filesystem on the developer's machine.
Suppose now that you have a reusable module that is a façade for third-party logging systems like Log4Net and that you want to reuse it in your Project1 project. You have several choices :
# Get a copy of the module and third-party and put it on the project's Implementation folder
# Checkout the module and third-party to your CVSROOT and establish dependencies to it
# Checkout the module and third-party to your project's Implementation folder reproducing it's relative path
The first approach works but you are hiding the module from all other projects, if you improve or correct it the changes will not be visible for others.
The second approach also works but, aside for the difficulty of maintaining relative paths, it prevents the scenario where you have several projects reusing different versions of the reusable module and makes building, deployment and archiving more difficult. It may also bring unnecessary modules to your filesystem and project's environment.
In the third approach you check out only the needed modules from //Internal// folder to a reproduction of the [[standard filesystem structure|Namespace and Filesystem Guidelines]], this way they keep their relative paths and, although they point to the same location on the [[CVS]] you can check out specific tags (versions) for each project. If you change the reusable module you may promote the tag to a branch and commit your changes to the shared module. The reusable module owner can later decide to merge your changes in a new release.

To make thing easier for your users (the developers), and to prevent future maintenance needs, you shall produce a small batch file for each of your reusable modules that will perform the checkout to the folder where it is placed. This way re-users just have to place these batch files where they are needed and run them, this is essential if you do automated [[Continuous Integration]].
{{{
cvs -z9 -r checkout -P -r LOGGING-REL-01_00_002 -d Logging -- Internal/[YourCompanyAcronym]/SYS/Common/Logging

cvs -z9 -r checkout -P -r LOGGING-REL-01_00_002 -d Log4Net -- Internal/Third-Parties/Apache/Log4Net
}}}
The above command will check out the Logging module from [[CVS]] on tag ~LOGGING-REL-01_00_002 and place it in a Logging folder beneath the current directory. The second command will check out the Apache's Log4Net from your repository.

To specify, disseminate and enforce a proper and shared filesystem structure and reuse methodology is the first step for succeeding in [[Systematic Reuse]] efforts and is also a condition for performing [[Emergent Reuse]] effectively.
----
See also : [[Namespace Coupling Guidelines]], [[Namespace Code Placement Guidelines]] and [[Namespace and Filesystem Guidelines]] [[Reuse oriented CVS]]
----
@@color:#c4d6ed; ^^
Description: Promoting Reuse by Reference through a proper filesystem structure guideline
^^@@
User-agent: *
Disallow: /bags/*
Disallow: /recipes/*
Disallow: /search.kml
Disallow: /search.atom
/***
|''Name''|ErrorHandlerPlugin|
|''Version''|0.4.3|
|''Author''|Jon Robson|
|''Description''|Localised tiddler save errors including edit conflict resolution.|
|''CoreVersion''|2.6.1|
|''Requires''|TiddlySpaceConfig|
***/
//{{{
(function($) {

var tiddlyspace = config.extensions.tiddlyspace;
var currentSpace = tiddlyspace.currentSpace.name;
tiddlyspace.getLocalTitle = function(title, workspace, suffix) {
	var endsWith = config.extensions.BinaryTiddlersPlugin.endsWith;
	if(!suffix) {
		var isPublic = endsWith(workspace, "_public");
		suffix = tiddlyspace.resolveSpaceName(workspace);
		if(currentSpace == suffix) {
			suffix = isPublic ? "public" : "private";
		} else {
			suffix = "@%0".format(suffix);
		}
	}
	return "%0 *(%1)*".format(title, suffix);
};

var sssp = config.extensions.ServerSideSavingPlugin;

var msgs = config.messages.editConflict = {
	loading: "Loading..",
	resolve: "[[Edit Conflict]]@glossary: this tiddler may have been changed by someone else.",
	reviewDiff: "review (recommended)",
	reviewDiffTooltip: "review changes made to this tiddler",
	reviewDiffError: "error retrieving revision.",
	save: "overwrite",
	saveTooltip: "make this revision the top revision of this tiddler",
	discard: "cancel",
	discardTooltip: "undo changes to this tiddler and get most recent version",
	diffTitle: "%0",
	diffFieldTitle: "%0 - fields",
	diffTextTitle: "%0 - text",
	updating: "updating your version...",
	diffHeader: ["Review the changes that have been made whilst you were editing this tiddler. ",
		"Fold relevant changes back into your version.\n",
		"{{removed{Red}}} highlight shows content removed. ",
		"{{added{Green}}} highlight shows content added.\n"].join(""),
	diffTextHeader: "View changes in text",
	diffFieldsHeader: "View changes in fields"
};

var plugin = config.extensions.errorHandler = {
	diffTags: ["excludeLists", "excludeMissing", "excludeSearch"],
	displayMessage: function(message, tiddler, context) {
		var desc = context && context.httpStatus ? context.statusText :
			sssp.locale.connectionError;
		var reportArea = plugin.reportError(tiddler.title);
		var msg = $("<div />").appendTo(reportArea);
		if(message == "saveConflict") {
			wikify(msgs.resolve, msg[0]);
			var choiceArea = $("<div />").appendTo(reportArea)[0];
			plugin.editConflictHandler(choiceArea, tiddler);
		} else {
			msg.text(sssp.locale[message].format(tiddler.title, desc));
		}
	},
	editConflictHandler: function(container, tiddler) {
		var title = tiddler.title;
		var myrev = tiddler.fields["server.page.revision"];
		// note user now needs to edit, fix problem and save. 
		// TODO: make sure this gets reset in save callback
		store.getTiddler(title).fields["server.page.revision"] = "false";

		var diffBtn = createTiddlyButton(container, msgs.reviewDiff, msgs.reviewDiffTooltip, function(ev) {
			var title = $(ev.target).data("title");
			plugin.displayDiff(ev.target, store.getTiddler(title), myrev);
		});
		var saveBtn = createTiddlyButton(container, msgs.save, msgs.saveTooltip, function(ev) {
				var title = $(ev.target).data("title");
				var tid = store.saveTiddler(store.getTiddler(title));
				autoSaveChanges(null, [tid]);
			});
		var ignoreBtn = createTiddlyButton(container, msgs.discard, msgs.discardTooltip, function(ev) {
			var title = $(ev.target).text(msgs.updating).data("title");
			plugin.resetToServerVersion(store.getTiddler(title));
		});
		$([diffBtn, ignoreBtn, saveBtn]).data("title", title);
	},
	getDiffTiddlerTexts: function(diffText) {
		var chunks = diffText.split("\n  \n");
		if(chunks.length < 2) {
			return [chunks[0], ""];
		} else {
			var diffFieldsText = "{{diff{\n%0\n}}}".format(chunks[0]);
			diffText = '{{diff{\n%0\n}}}'.format(chunks.splice(1, chunks.length).join("\n"));
			return [diffText, diffFieldsText];
		}
	},
	makeDiffTiddler: function(title, diff) {
		var newTiddler = new Tiddler(title);
		var tags = plugin.diffTags;
		newTiddler.text = msgs.loading;
		newTiddler.fields.doNotSave = true;
		newTiddler.tags = diff ? tags.concat(["diff"]) : tags;
		newTiddler = store.saveTiddler(newTiddler);
		$.extend(store.getTiddler(title).fields,
			config.defaultCustomFields); // allow option to save it
		return newTiddler;
	},
	displayDiff: function(src, tiddler, latestRevision) {
		var adaptor = tiddler.getAdaptor();
		var title = tiddler.title;
		var ts = new Date().formatString("0hh:0mm:0ss");
		var suffix = "edit conflict %0".format(ts);
		var diffTitle = tiddlyspace.getLocalTitle(msgs.diffTitle.format(title), "", suffix);
		var diffTextTitle = tiddlyspace.getLocalTitle(msgs.diffTextTitle.format(title), "", suffix);
		var diffFieldsTitle = tiddlyspace.getLocalTitle(msgs.diffFieldTitle.format(title), "", suffix);
		plugin.makeDiffTiddler(diffTextTitle, true);
		plugin.makeDiffTiddler(diffFieldsTitle, true);
		var newTiddler = plugin.makeDiffTiddler(diffTitle, false);
		newTiddler.text = ['%0\n<<slider chkViewDiffText "%1" "%2">>\n',
			'<<slider chkViewDiffField "%3" "%4">>'].join("").
			format(msgs.diffHeader, diffTextTitle, msgs.diffTextHeader,
				diffFieldsTitle, msgs.diffFieldsHeader);
		store.saveTiddler(newTiddler);

		var callback = function(r) {
			var text = plugin.getDiffTiddlerTexts(r);
			store.getTiddler(diffTextTitle).text = text[0];
			store.getTiddler(diffFieldsTitle).text = text[1];
			story.refreshTiddler(diffTitle, null, true);
		};
		var workspace = "bags/%0".format(tiddler.fields["server.bag"]);
		ajaxReq({
			type: "get",
			dataType: "text",
			url: "/diff?format=unified&rev1=%0/%1/%2&rev2=%0/%1".format(workspace, title, latestRevision),
			success: callback,
			error: function() {
				displayMessage(msgs.reviewDiffError);
			}
		});
		story.displayTiddler(src, diffTitle);
	},
	resetToServerVersion: function(tiddler) {
		var adaptor = tiddler.getAdaptor();
		var ctx = { 
			host: tiddler.fields["server.host"],
			workspace: "bags/" + tiddler.fields["server.bag"]
		};
		adaptor.getTiddler(tiddler.title, ctx, null, function(context) {
			store.saveTiddler(context.tiddler);
			story.refreshTiddler(tiddler.title);
			store.setDirty(false);
		});
	},
	reportError: function(title) {
		var el = story.getTiddler(title);
		if(!el) {
			el = story.displayTiddler(null, title);
		}
		return $("<div />").addClass("error annotation").prependTo(el)[0];
	}
};

sssp.reportFailure = function(message, tiddler, context) {
	config.options.chkViewDiffText = config.options.chkViewDiffText === undefined ?
		true : config.options.chkViewDiffText;
	config.options.chkViewDiffFields = config.options.chkViewDiffFields || false;
	plugin.displayMessage(message, tiddler, context);
};

})(jQuery);
//}}}
|Area|Author|Title|Year|Abstract/Ref.|h
|Architecture|D.L. Parnas|<html><a name="Parnas 1972" /></html>[[On the Criteria To Be Used in Decomposing Systems Into Modules|http://www.cs.umd.edu/class/spring2003/cmsc838p/Design/criteria.pdf]]|1972|This paper discusses modularization as a mechanism for improving the flexibility and comprehensibility of a system while allowing the shortening of its development time. The effectiveness of a "modularization" is dependent upon the criteria used in dividing the system into modules. A system design problem is presented and both a conventional and unconventional decomposition are described. It is shown that the unconventional decompositions have distinct advantages for the goals outlined. The criteria used in arriving at the decompositions are discussed. The unconventional decomposition, if implemented with the conventional assumption that a module consists of one or more subroutines, will be less efficient in most cases. An alternative approach to implementation which does not have this effect is sketched.|
|~|~|~|~|{{{<<BibRef "Parnas 1972">>}}}|
|~|J.D. Meier, Alex Homer, David Hill, Jason Taylor, Prashant Bansode, Lonnie Wall, Rob Boucher Jr, Akshay Bogawat|<html><a name="AppArch 2.0" /></html>[[Microsoft Application Architecture Guide 2.0 |http://apparchguide.codeplex.com/]]|2008|This guide provides design-level guidance for the architecture and design of applications built on the .NET Framework. It focuses on the most common types of applications, partitioning application functionality into layers, components, and services, and walks through their key design characteristics. This guide is a collaborative effort between patterns & practices, product teams, and industry experts.|
|~|~|~|~|{{{<<BibRef "AppArch 2.0">>}}}|
|Coding|Steven C. ~McConnell|<html><a name="McConnell 2004" /></html>[[Code Complete 2nd Ed.|http://www.cc2e.com/Default.aspx]]|2004|Widely considered one of the best practical guides to programming, Steve ~McConnell’s original CODE COMPLETE has been helping developers write better software for more than a decade. Now this classic book has been fully updated and revised with leading-edge practices—and hundreds of new code samples—illustrating the art and science of software construction. Capturing the body of knowledge available from research, academia, and everyday commercial practice, ~McConnell synthesizes the most effective techniques and must-know principles into clear, pragmatic guidance. No matter what your experience level, development environment, or project size, this book will inform and stimulate your thinking—and help you build the highest quality code.|
|~|~|~|~|{{{<<BibRef "McConnell 2004">>}}}|
|~|Venkat Subramaniam and Andy Hunt|<html><a name="Venkat 2006" /></html>[[Practices of an Agile Developer|http://pragprog.com/book/pad/practices-of-an-agile-developer]]|2006|Want to be a better developer? This book collects the personal habits, ideas, and approaches of successful agile software developers and presents them in a series of short, easy-to-digest tips. You’ll learn how to improve your software development process, see what real agile practices feel like, avoid the common temptations that kill projects, and keep agile practices in balance.|
|~|~|~|~|{{{<<BibRef "Venkat 2006">>}}}|
|Concepts|Edward V. Berard|<html><a name="Berard" /></html>[[Abstraction, Encapsulation and Information Hiding|http://www.tonymarston.co.uk/php-mysql/abstraction.txt]]||The fundamental reference on these concepts|
|~|~|~|~|{{{<<BibRef Berard>>}}}|
|~|Mike Mannion and Barry Keepence|<html><a name="Mannion,Keepence 1995" /></html>[[SMART requirements|http://www.win.tue.nl/~wstomv/edu/2ip30/references/smart-requirements.pdf]]|1995|Systems Analysis, or as it is increasingly known as today, Requirements Engineering, is a time consuming, expensive but critical phase in software (and system) development. The "perfect" Requirements Specification should exhibit a number of qualities including correctness, completeness and consistency. Within a Requirements Specification individual requirements at the microscopic level should be justified, clear, unambiguous and verifiable. However, in many cases Systems Analysts or Requirements Engineers describe requirements which fall short of these demands. In addition, outside reviewers faced with presenting an independent qualitative assessment of a Requirements Specification have few guidelines to assist them. In this paper we present a simple technique, borrowed from objective setting in Management Psychology, to assist the construction and evaluation of individual requirements.|
|~|~|~|~|{{{<<BibRef "Mannion,Keepence 1995">>}}}|
|Processes|[[International Institute of Business Analysis (IIBA)|http://www.iiba.org]]|<html><a name="BABOK 2008" /></html>[[A Guide to the Business Analysis Body of Knowledge® (BABOK® Guide) v.2 draft|http://www.iiba.org/imis15/IIBA/Professional_Development/Business_Analysis_Body_of_Knowledge/IIBA_Website/Professional_Development/Business_Analysis_Body_of_Knowledge_pages/Business_Analysis_Body_of_Knowledge.aspx]]|2008|A Guide to the Business Analysis Body of Knowledge® (BABOK® Guide) is the collection of knowledge within the profession of business analysis and reflects current generally accepted practices. As with other professions, the body of knowledge is defined and enhanced by the business analysis professionals who apply it in their daily work role.|
|~|~|~|~|{{{<<BibRef "BABOK 2008">>}}}|
|Systems Engineering|Alexander Kossiakoff, et al.|<html><a name="Kossiakoff 2011" /></html>Systems engineering principles and practice 2ed.|2011|Learning how to be a successful systems engineer is entirely different from learning how to excel at a traditional engineering discipline. It requires developing the ability to think in a special way, to acquire the “ systems engineering viewpoint, ” and to make the central objective the system as a whole and the success of its mission. The systems engineer faces three directions: the system user ’ s needs and concerns, the project manager’ s financial and schedule constraints, and the capabilities and ambitions of the engineering specialists who have to develop and build the elements of the system.|
|~|~|~|~|{{{<<BibRef "Kossiakoff 2011">>}}}|||||||
|~|~|~|~||
----
@@color:#c4d6ed; ^^
Description: Bibliographical references for all articles. 
^^@@
On developing we produce different types of code in what generalization (and, as such, re-usability) is concerned :
* ''Sub-systems'' : These are highly <<quote 'cohesive' 'Cohesion>> modules with no <<quote 'coupling' 'Coupling>>. They do one thing and do it well without any external dependencies. This code is highly reusable and shall also be well <<quote 'encapsulated' 'Encapsulation>> and exposed through an as simple as possible <<q