Background: #fff
Foreground: #000
PrimaryPale: #8cf
PrimaryLight: #18f
PrimaryMid: #04b
PrimaryDark: #014
SecondaryPale: #ffc
SecondaryLight: #fe8
SecondaryMid: #db4
SecondaryDark: #841
TertiaryPale: #eee
TertiaryLight: #ccc
TertiaryMid: #999
TertiaryDark: #666
Error: #f88
/*{{{*/
body {background:[[ColorPalette::Background]]; color:[[ColorPalette::Foreground]];}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

hr {height:1px;}

a {text-decoration:none;}

dt {font-weight:bold;}

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

.txtOptionInput {width:11em;}

#contentWrapper .chkOptionInput {border:0;}

.externalLink {text-decoration:underline;}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

.whenBackstage {display:none;}
.backstageVisible .whenBackstage {display:block;}
/*}}}*/
/***
StyleSheet for use when a translation requires any css style changes.
This StyleSheet can be used directly by languages such as Chinese, Japanese and Korean which need larger font sizes.
***/
/*{{{*/
body {font-size:0.8em;}
#sidebarOptions {font-size:1.05em;}
#sidebarOptions a {font-style:normal;}
#sidebarOptions .sliderPanel {font-size:0.95em;}
.subtitle {font-size:0.8em;}
.viewer table.listView {font-size:0.95em;}
/*}}}*/
/*{{{*/
@media print {
#mainMenu, #sidebar, #messageArea, .toolbar, #backstageButton, #backstageArea {display: none ! important;}
#displayArea {margin: 1em 1em 0em 1em;}
/* Fixes a feature in Firefox 1.5.0.2 where print preview displays the noscript content */
noscript {display:none;}
}
/*}}}*/
<!--{{{-->
<div class='header' macro='gradient vert [[ColorPalette::PrimaryLight]] [[ColorPalette::PrimaryMid]]'>
<div class='headerShadow'>
<span class='siteTitle' refresh='content' tiddler='SiteTitle'></span>&nbsp;
<span class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'></span>

</div>
<div class='headerForeground'>
<span class='siteTitle' refresh='content' tiddler='SiteTitle'></span>&nbsp;
<span class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'></span>
</div>
</div>
<div id='mainMenu' refresh='content' tiddler='MainMenu'></div>

<div id='sidebar'>
<div id='sidebarOptions' refresh='content' tiddler='SideBarOptions'></div>
<div id='sidebarTabs' refresh='content' force='true' tiddler='SideBarTabs'></div>
</div>
<div id='displayArea'>
<div id='messageArea'></div>
<div id='tiddlerDisplay'></div>

</div>
<!--}}}-->
<!--{{{-->
<div class='toolbar' macro='toolbar [[ToolbarCommands::ViewToolbar]]'></div>
<div class='title' macro='view title'></div>
<div class='subtitle'><span macro='view modifier link'></span>, <span macro='view modified date'></span> (<span macro='message views.wikified.createdPrompt'></span> <span macro='view created date'></span>)</div>

<div class='tagging' macro='tagging'></div>
<div class='tagged' macro='tags'></div>
<div class='viewer' macro='view text wikified'></div>
<div class='tagClear'></div>
<!--}}}-->
<!--{{{-->

<div class='toolbar' macro='toolbar [[ToolbarCommands::EditToolbar]]'></div>
<div class='title' macro='view title'></div>
<div class='editor' macro='edit title'></div>
<div macro='annotations'></div>
<div class='editor' macro='edit text'></div>
<div class='editor' macro='edit tags'></div><div class='editorFooter'><span macro='message views.editor.tagPrompt'></span><span macro='tagChooser excludeLists'></span></div>

<!--}}}-->
To get started with this blank TiddlyWiki, you'll need to modify the following tiddlers:
* SiteTitle & SiteSubtitle: The title and subtitle of the site, as shown above (after saving, they will also appear in the browser title bar)
* MainMenu: The menu (usually on the left)
* DefaultTiddlers: Contains the names of the tiddlers that you want to appear when the TiddlyWiki is opened
You'll also need to enter your username for signing your edits: <<option txtUserName>>
These InterfaceOptions for customising TiddlyWiki are saved in your browser

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

<<option txtUserName>>
<<option chkSaveBackups>> SaveBackups

<<option chkAutoSave>> AutoSave
<<option chkRegExpSearch>> RegExpSearch
<<option chkCaseSensitiveSearch>> CaseSensitiveSearch
<<option chkAnimate>> EnableAnimations

----
Also see AdvancedOptions
<<importTiddlers>>
/*{{{*/

// may be required for mikes comments plugi
//window.saveChanges = function(){};

setStylesheet(
	"label {width:8em; float:left; text-align:right; width:9em; font-size:1.1em; padding:3px;  height:1.5em: top:-20px; margin: 0px -2px 0 0;}"+ 
//	"div.wizardFooter {padding-left:0em}"+ 
	"div.wizardStep > input {display:fixed; padding:3px; margin-bottom:5px; margin-top:0px; margin-right:0px}",
'labelStyles');




config.backstageTasks.remove("upgrade");
config.backstageTasks.remove("save");
config.backstageTasks.remove("sync");


//  ccAutoSave config//

config.options.chkAutoSave = true;

if(!config.extensions) { config.extensions = {}; } //# obsolete from v2.4.2
config.extensions.ServerSideSavingPlugin = {
	adaptor: config.adaptors.cctiddly
};


window.ccTiddlyVersion = '1.8.2';
window.workspacePermission= {};
window.url = "http://www.andreanis.de/_tiddly";
window.url= 'http://www.andreanis.de/_tiddly/';
window.workspace = "";
window.fullUrl = window.url;	
window.useModRewrite = 1;
//if (config.options.txtTheme == "")
//config.options.txtTheme = 'purpleTheme';
workspacePermission.upload = 1;workspacePermission.anonC = 1 ;
workspacePermission.anonR = 1; 
workspacePermission.anonU = 1;
workspacePermission.anonD = 1;

workspacePermission.userC = 1 ;
workspacePermission.userR = 1; 
workspacePermission.userU = 1;
workspacePermission.userD = 1;
workspacePermission.canCreateWorkspace = 1;


window.workspace_delete = "A";
window.workspace_udate = "A";

var serverside={
	url:"http://www.andreanis.de/_tiddly",		//server url, for use in local TW or TW hosted elsewhere
	workspace:"",
	queryString:"",
	debug:0,		//debug mode, display alert box for each action
	passwordTime:0,		//defines how long password variable store in cookie. 0 = indefinite
	messageDuration:5000,				//displayMessage autoclose duration (in milliseconds), 0=leave open
	loggedIn:0,
	can_create_account:"1",
	openId:"1"
};

config.defaultCustomFields = {"server.host":window.url, "server.type":"cctiddly", "server.workspace":window.workspace};
config.shadowTiddlers.OptionsPanel = "[[help|Help]] <br />[[settings|AdvancedOptions]]<br /><<ccOptions>>";

readOnly =false;
config.options.chkHttpReadOnly = false;		//make it HTTP writable by default
config.options.chkSaveBackups = false;		//disable save backup
//config.options.chkAutoSave = true;			//disable autosave
config.options.chkUsePreForStorage = false;

/*}}}*/
powerpapepowerpape
<<ccAdmin>>


Please see the TiddlyWiki community wiki documentation : http://tiddlywiki.org/wiki/TiddlyWiki_Markup

!!!{{{<<today>>}}}
Shows current date.

!!!{{{<<version>>}}} 
This macro shows the version number of the current TiddlyWiki document.

!!!{{{<<Alltags>>}}}
Lists all tags. Clicking on a tag lists all the tiddlers assigned that tag. 

!!!{{{<<List [type]>>}}} 
Parameters : (all (default), missing, orphans, shadowed, touched, filter)

!!!{{{<<Timeline [date] [length] [format]>>}}} 
 The timeline macro creates a list of tiddlers sorted by a date specified.

Example : 
{{{<<timeline "modified" "0" "ddd, YYYY-0MM-0DD">>}}}

Produces : 
<<timeline "modified" "0" "ddd, YYYY-0MM-0DD">>
!!!{{{<<Slider cookie tiddler label tooltip>>}}}
The slider macro allows embedding tiddlers within another tiddler, with the option to toggle the visibility of the transcluded contents.

    * cookie: variable to save the state of the slider
    * tiddler: name of the tiddler to include in the slider
    * label: title text of the slider
    * tooltip: tooltip text of the slider 

 Example
{{{<<slider chkTestSlider [[OptionsPanel]] "Options" "Open advanced options">>}}}

Produces : 
<<slider chkTestSlider [[OptionsPanel]] "Options" "Open advanced options">>
!!!{{{<<Tabs>>}}}
The tabs macro creates an area where it displays one of several tiddlers alternately, as the user clicks on the tab labels at the top.

It is used like this:

{{{<<tabs ID Label1 Tip1 Tiddler1 Label2 Tip2 Tiddler2 [Label3 ...]>>}}}

produces :
<<tabs ID Label1 Tip1 Tiddler1 Label2 Tip2 Tiddler2 [Label3 ...]>>

    * ID: specifies the name of a cookie used to save the information about which tab was displayed last.
    * Label1, Label2, ... define the labels that are displayed at the top of the area for each tab
    * Tip1, Tip2, ... define tooltips that explain, somewhat more verbosely than the labels, what you can expect to find on each tab.
    * Tiddler1, Tiddler2, ... name the tiddlers that are displayed on each tab. 

Obviously, there must be exactly three strings for each tab.

The syntax for the tabs macro looks like this:

{{{<<tabs txt[cookieName]
	"[label]" "[title]" [[tiddler]]
	"[label]" "[title]" [[tiddler]]
	...
     >>}}}

produces :

<<tabs txt[cookieName]
	"[label]" "[title]" [[tiddler]]
	"[label]" "[title]" [[tiddler]]
	...
     >>

!!!{{{<<Tagging [tag]>>}}}
This macro generates a list of tiddlers that carry the specified tag.

<<tagging [tag]>>

If the tag parameter is not specified, the current tiddler's name will be used instead.
!!!{{{<<Tagchooser>>}}}
!!!{{{<<NewJournal>>}}}
This macro generates a button to create a journal tiddler, using the current time and date as title.

It is otherwise identical to the NewTiddler macro.

Example : 
{{{<<newJournal [date format]>>}}}

Produces : 
<<newJournal [date format]>>

The optional parameter can be used to specify a custom date format.

In addition, all of the NewTiddler macro's parameters are valid.

!!!{{{<<NewTiddler>>}}}

 Usage

<<newTiddler [parameters]>>

Parameters

This macro uses named parameters. All parameters are optional.
|Parameter|Description|
|label |button label|
|prompt|button tooltip|
|title|title for the new tiddler (defaults to "New Tiddler")|
|text|contents for the new tiddler|
|tag|tag to be applied to the new tiddler (parameter can be used repeatedly to specify multiple tags)|
|accessKey|single letter to use as access key to trigger the button|
|focus|which of the editable fields to default the focus to (e.g. "title", "text", "tags")|
|template|template tiddler to use to display the new tiddler (defaults to EditTemplate)|
|fields|custom fields to be assigned to the new tiddler, in name:value;name:value; format|

Only fields contained as input fields in the specified template can be primed with an initial value.
[edit] Example

<<newTiddler
	label:"New Tiddler"
	text:"Hello world."
	tag:"test"
	tag:"an example"
	accessKey:"1"
	focus:"tags"
>>



!!!{{{<<Savechanges>>}}}



!!!{{{<<Search>>}}}

This macro creates an input field to perform full-text searches on a TiddlyWiki document's tiddler contents.
[edit] Usage

Example : 
{{{<<search [value]>>}}}

Produces : 

<<search [value]>>

By specifiying the value parameter, the search form can be "preloaded" with the desired term.
[edit] Options
This section is still incomplete. You can help by contributing to its expansion.
Please improve the article, or discuss the issue on the talk page.

    * case-sensitive
    * regular expressions 


!!!{{{<<Gradient>>}}}

The Gradient macro allows simple horizontal and vertical coloured gradients. They are constructed from coloured HTML elements, and don't require any images to work.
The Gradient macro is an extended macro that processes the text after it up until the next '

>>

' sequence. It looks like this:
Example : 
{{{<<gradient vert #ffffff #ffdddd #ff8888>>gradient fill>>}}}

Produces : 
<<gradient vert #ffffff #ffdddd #ff8888>>gradient fill>>

The first parameter can be vert or horiz to indicate the direction of the gradient. The following parameters are two or more colours (CSS RGB(r,g,b) format is also acceptable). The macro constructs a smooth linear gradient between each of the colours in turn.

Inline CSS definitions can be added to gradient fills like this:


Example : 
{{{<<gradient vert #000000 #660000 #aa2222>>color:#ffffff;font-size:12pt;Darkness>>}}}

Produces : 
<<gradient vert #000000 #660000 #aa2222>>color:#ffffff;font-size:12pt;Darkness>>

!!!{{{<<Closeall>>}}}
!!!{{{<<Permaview>>}}}
Changes the browser address bar to a permalink to the current Tiddler or the set of open tiddlers. It is used with the ToolbarMacro like this:

Example : 
{{{<<toolbar permalink>>}}}
Produces : 
<<toolbar permalink>>

!!!{{{<<Toolbar>>}}}
The ToolbarMacro is used in the TemplateMechanism to define the toolbar that appearthat appear either in EditMode or in ViewMode. The arguments to the ToolbarMacro is a list of command names, as discussed in the CommandMechanism..

You can precede a command name with a "+" to specify a default command that is automatically chosen when a tiddler is double-clicked, or the ctrl-Enter key combination pressed. Similarly, precede it with "-" to specify a command to be chosen when the Escape key is pressed.
!!!{{{<<Annotations>>}}}

!!!{{{<<Edit>>}}}
The command <<edit>> switches from ViewMode to EditMode. The EditMacro is either a double mouse click inside the tiddler or the entry 'edit' in the tiddler's Toolbar. It is used in ViewTemplate as ToolbarMacro like this:
Example : 
{{{<<toolbar +editTiddler>>}}}
Produces : 
<<toolbar +editTiddler>>

!!!{{{<<Message>>}}}
!!!{{{<<Refreshdisplay>>}}}
!!!{{{<<View fieldname how...>>}}}
Retrieves a specified field (given by fieldname) from the tiddler to be displayed and outputs its value in one of the following ways (the optional //how// parameter):

    * (unspecified): render as is (without formatting)
    * link: format as a link (using createTiddlyLink)
    * wikified: format using all the normal rendering rules
    * date: expects a value of the form YYYYMMDDHHMM and outputs it using either a specified format (...) or config.views.wikified.dateFormat 

The standard field names are:

    * title - the tiddler title
    * tiddler - the tiddler title (as well)
    * text - the text of the tiddler
    * modifier - the person who last modified it
    * modified - date&time of last modification
    * created - when it was created
    * tags - the tiddler tags 

If your tiddlers contain custom fields, they could be specified as well.

The view macro is used extensively in the standard tiddler rendering templates (ViewTemplate and EditTemplate).



(this content is a work in progress)

!!!ccTiddly Tiddlers 

[[AnonDefaultTiddlers]]

Allows you to specify a different set of tiddlers to be loaded for anonymous users. Logged in users will be shown the [[DefaultTiddlers]].

[[ccAssignments]]

!!! Predefined ccTiddly Tags 

!!!!wizard
Displays the tiddler without showing the date editor tags or title. 

!!!!private
Only administrators of a workspace can read tiddlers tagged private.

!!! Working Offline : 
To take a copy of a ccTiddly workspace offline add &standalone=1 to the end of the URI and you will be prompted to download an offline file.


!!!{{{<<ccUpload>>}}}
If enabled on the server users can upload files to the ccTiddly server

!!!{{{<<ccLogin>>}}}
Displays the login box if the users is not logged in, if the user is logged in they are shown a logout button

!!!{{{<<ccLoginStatus>>}}}
As with {{{<<ccLogin>>}}} except this displays a link to the login tiddler so can be used where space is tight. 

!!!{{{<<ccCreateWorkspace>>}}}
Allows users with permission to create a workspace and define its permissions.

!!!{{{<<ccEditWorkspace>>}}}
Allows admin users to change the permission of a workspace.

!!!{{{<<ccAdmin>>}}}
Allows admin users to add and remove admin users for a workspace.

!!!{{{<<ccVersion>>}}}
Allows users to confirm which version of ccTiddly they are using.
~TiddlyWiki is a single html file containing all the characteristics of a wiki - all the content, all the functionality (including editing, saving, tagging and searching) and the style sheet. Because it's a single file, it's very portable - you can email it, put it on a web server or share it via a USB stick. ccTiddly provides a serverside backend to ~TiddlyWiki so you can store your content on the web and access it from anywhere. 

Together the two provide a powerful combination which allows you to collaborate with your colleages online, you can then tear a copy of all the work to take on a plane or train journey.  When you have found an internet connection again you can sync your changes with the online copy and you will be notified of any conflicts. 

Some things you could do with ccTiddly workspace include: 

	* A team/public Website
	* A Blog
    * A personal notebook
    * A GTD ("Getting Things Done") productivity tool
    * A collaboration/communication tool
	* A TeamTasks implementation
    * For building websites (this site is a TiddlyWiki file!)
    * For rapid prototyping
    * ...and much more!

You can import and export data to and from all sorts of places. Check out the backstage > import options. There's a more detailed list of features here.

<<slider cctHelpIntro [[ccTiddly Introduction]] "ccTiddly Introduction »" "A introduction to the basics of TiddlyWiki.">>
<<slider cctHelpFormatting [[TiddlyWiki Formatting Guide]] "Tiddly Wiki Formatting Guide »" "A basic guide to TiddlyWiki formatting.">>
<<slider cctHelpccTiddlyMacros [[ccTiddly Macros]] "ccTiddly Macros »" "A Guide to all the ccTiddly Macros">>
<<slider cctHelpTiddlyWikiMacros [[TiddlyWiki Macros]] "TiddlyWiki Macros »" "A Guide to all the TiddlyWiki Macros">>

More info on Osmosoft can be found at [[osmosoft.com|http://osmosoft.com/]]
powerpape
|''Description:''|MonkeyPirate|
|''Type:''|tiddlywiki|
|''URL:''|http://mptw.tiddlyspot.com/empty.html|
|''Workspace:''|Main|
|''Description:''|TeamTasks |
|''Type:''|tiddlywiki|
|''URL:''|http://getteamtasks.com/teamtasks.html|
|''image:''|http://127.0.0.1/teamtasks.jpg|
|''Workspace:''|Main|
|''Description:''|TiddlyThemes |
|''Type:''|tiddlywiki|
|''URL:''|http://tiddlythemes.com|
|''Workspace:''|Main|
|''Description:''|TiddlyTools |
|''Type:''|TiddlyWiki|
|''URL:''|http://tiddlytools.com|
|''Workspace:''|Main|
|''Description:''|TiddlyVault |
|''Type:''|TiddlyWiki|
|''URL:''|http://tiddlyvault.tiddlyspot.com/|
|''Workspace:''|Main|
|''Description:''|Visual TW |
|''Type:''|tiddlywiki|
|''URL:''|http://visualtw.ouvaton.org/VisualTW.html|
|''Workspace:''|Main|
|''Description:''|LocalccTiddly|
|''Type:''|cctiddly|
|''URL:''|http://127.0.0.1/Trunk/|
|''Workspace:''|martin|
|''Description:''|ROOT|
|''Type:''|tiddlywiki|
|''URL:''|http://www.andreanis.de/_tiddly/uploads/export.xml|
|''Workspace:''|Main|
|''Description:''|Life Stream |
|''Type:''|tiddlywiki|
|''URL:''|http://simonmcmanus.com|
|''image:''|http://127.0.0.1/simonmcmanustheme.jpg|
|''Workspace:''|Main|
|''Description:''|tiddlydocs|
|''Type:''|tiddlywiki|
|''URL:''|http://www.tiddlydocs.com/|
|''Workspace:'XXXX'|Main|
powerpape
/***
|''Name:''|LoadRemoteFileThroughProxy (previous LoadRemoteFileHijack)|
|''Description:''|When the TiddlyWiki file is located on the web (view over http) the content of [[SiteProxy]] tiddler is added in front of the file url. If [[SiteProxy]] does not exist "/proxy/" is added. |
|''Version:''|1.1.0|
|''Date:''|mar 17, 2007|
|''Source:''|http://tiddlywiki.bidix.info/#LoadRemoteFileHijack|
|''Author:''|BidiX (BidiX (at) bidix (dot) info)|
|''License:''|[[BSD open source license|http://tiddlywiki.bidix.info/#%5B%5BBSD%20open%20source%20license%5D%5D ]]|
|''~CoreVersion:''|2.2.0|
***/
//{{{
	
version.extensions.LoadRemoteFileThroughProxy = {
 major: 1, minor: 1, revision: 0, 
 date: new Date("mar 17, 2007"), 
 source: "http://tiddlywiki.bidix.info/#LoadRemoteFileThroughProxy"};

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

bidix.core.loadRemoteFile = loadRemoteFile;
loadRemoteFile = function(url,callback,params)
{
 if ((document.location.toString().substr(0,4) == "http") && (url.substr(0,4) == "http")){ 
 url = store.getTiddlerText("SiteProxy", "/proxy/") + url;
 }

 return bidix.core.loadRemoteFile(url,callback,params);
}
//}}}
/***
|''Name''|ServerSideSavingPlugin|
|''Description''|server-side saving|
|''Author''|FND|
|''Version''|0.3.2|
|''Status''|@@experimental@@|
|''Source''|http://svn.tiddlywiki.org/Trunk/association/plugins/ServerSideSavingPlugin.js|
|''License''|[[Creative Commons Attribution-ShareAlike 3.0 License|http://creativecommons.org/licenses/by-sa/3.0/]]|
|''Requires''|[[ServerConfig]]|
|''Keywords''|serverSide|
!Notes
This plugin relies on a dedicated configuration plugin to be present.
The specific nature of this plugins 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
!To Do
* conflict detection/resolution
* rename to ServerLinkPlugin?
* attempt to determine default adaptor (and defaultCustomFields) from systemServer tiddlers
* handle deleting/renaming (e.g. by hijacking the respective commands and creating a log)
!Code
***/
//{{{
if(!version.extensions.ServerSideSavingPlugin) { //# ensure that the plugin is only installed once
version.extensions.ServerSideSavingPlugin = { installed: true };

if(!config.extensions) { config.extensions = {}; } //# obsolete from v2.4.2

(function(plugin) { //# set up alias

if(!plugin || !plugin.adaptor) {
	throw "Missing dependency: ServerConfig";
}

plugin = {
	adaptor: plugin.adaptor, //# N.B.: expects config.extensions.ServerSideSavingPlugin.adaptor to be set
	locale: {
		saved: "%0 saved successfully",
		saveError: "Error saving %0: %1",
		deleted: "Removed %0",
		deleteError: "Error removing %0: %1",
		deleteLocalError: "Error removing %0 locally",
		removedNotice: "This tiddler has been deleted."
	},

	sync: function() {
		store.forEachTiddler(function(title, tiddler) {
			if(tiddler.fields.deleted) {
				plugin.removeTiddler(tiddler);
			} else if(tiddler.isTouched() && tiddler.getServerType() && tiddler.fields["server.host"]) {
				plugin.saveTiddler(tiddler);
			}
		});
	},

	saveTiddler: function(tiddler) {
		var adaptor = new this.adaptor();
		var context = {
			tiddler: tiddler,
			changecount: tiddler.fields.changecount
		};
		context.workspace = tiddler.fields["server.workspace"];
		var req = adaptor.putTiddler(tiddler, context, {}, this.saveTiddlerCallback);
		return req ? tiddler : false;
	},

	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;
			}
			displayMessage(plugin.locale.saved.format([tiddler.title]));
			store.setDirty(false);
		} else {
			displayMessage(plugin.locale.saveError.format([tiddler.title, context.statusText]));
		}
	},

	removeTiddler: function(tiddler) {
		var adaptor = new this.adaptor();
		context = { tiddler: tiddler };
		context.workspace = tiddler.fields["server.workspace"];
		var req = adaptor.deleteTiddler(tiddler, context, {}, this.removeTiddlerCallback);
		return req ? tiddler : false;
	},

	removeTiddlerCallback: function(context, userParams) {
		var tiddler = context.tiddler;
		if(context.status) {
			if(tiddler.fields.deleted) {
				store.deleteTiddler(tiddler.title);
			} else {
				displayMessage(plugin.locale.deleteError.format([tiddler.title]));
			}
			displayMessage(plugin.locale.deleted.format([tiddler.title]));
			store.setDirty(false);
		} else {
			displayMessage(plugin.locale.deleteLocalError.format([tiddler.title, context.statusText]));
		}
	}
};

config.macros.saveToWeb = { // XXX: hijack existing sync macro?
	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
plugin.saveChanges = saveChanges;
saveChanges = function(onlyIfDirty, tiddlers) {
	if(window.location.protocol == "file:") {
		plugin.saveChanges.apply(this, arguments);
	} else {
		plugin.sync();
	}
};

// override removeTiddler to flag tiddler as deleted
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.incChangeCount();
		this.notify(title, true);
		this.setDirty(true);
	}
};

})(config.extensions.ServerSideSavingPlugin); //# end of alias

// override saveTiddler to fix core bug (ticket #769) -- XXX: to be fixed in TiddlyWiki v2.4.2
Story.prototype.saveTiddler = function(title,minorUpdate)
{
	var tiddlerElem = this.getTiddler(title);
	if(tiddlerElem) {
		var fields = {};
		this.gatherSaveFields(tiddlerElem,fields);
		var newTitle = fields.title || title;
		if(!store.tiddlerExists(newTitle))
			newTitle = newTitle.trim();
		if(store.tiddlerExists(newTitle) && newTitle != title) {
			if(!confirm(config.messages.overwriteWarning.format([newTitle.toString()])))
				return null;
		}
		if(newTitle != title)
			this.closeTiddler(newTitle,false);
		tiddlerElem.id = this.tiddlerId(newTitle);
		tiddlerElem.setAttribute("tiddler",newTitle);
		tiddlerElem.setAttribute("template",DEFAULT_VIEW_TEMPLATE);
		tiddlerElem.setAttribute("dirty","false");
		if(config.options.chkForceMinorUpdate)
			minorUpdate = !minorUpdate;
		if(!store.tiddlerExists(newTitle))
			minorUpdate = false;
		var newDate = new Date();
		var extendedFields = store.tiddlerExists(newTitle) ? store.fetchTiddler(newTitle).fields : (newTitle!=title && store.tiddlerExists(title) ? store.fetchTiddler(title).fields : merge({},config.defaultCustomFields));
		for(var n in fields) {
			if(!TiddlyWiki.isStandardField(n))
				extendedFields[n] = fields[n];
		}
		var tiddler = store.saveTiddler(title,newTitle,fields.text,minorUpdate ? undefined : config.options.txtUserName,minorUpdate ? undefined : newDate,fields.tags,extendedFields);
		autoSaveChanges(null,[tiddler]);
		return newTitle;
	}
	return null;
};

} //# end of "install only once"
//}}}
/***
|Name|TaggedTemplateTweak|
|Source|http://www.TiddlyTools.com/#TaggedTemplateTweak|
|Documentation|http://www.TiddlyTools.com/#TaggedTemplateTweakInfo|
|Version|1.4.1|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|plugin|
|Requires||
|Overrides|Story.prototype.chooseTemplateForTiddler()|
|Description|use alternative ViewTemplate/EditTemplate for tiddler's tagged with specific tag values|
This tweak extends story.chooseTemplateForTiddler() so that ''whenever a tiddler is marked with a specific tag value, it can be viewed and/or edited using alternatives to the standard tiddler templates.'' 
!!!!!Documentation
>see [[TaggedTemplateTweakInfo]]
!!!!!Revisions
<<<
2008.08.29 [1.4.1] corrected handling for tiddlers with no matching tagged template when non-default theme is in effect (e.g., use "MyTheme##ViewTemplate").
| please see [[TaggedTemplateTweakInfo]] for previous revision details |
2007.06.11 [1.0.0] initial release
<<<
!!!!!Code
***/
//{{{
version.extensions.TaggedTemplateTweak= {major: 1, minor: 4, revision: 1, date: new Date(2008,8,29)};

Story.prototype.taggedTemplate_chooseTemplateForTiddler = Story.prototype.chooseTemplateForTiddler
Story.prototype.chooseTemplateForTiddler = function(title,template)
{
	// get default template from core
	var coreTemplate=this.taggedTemplate_chooseTemplateForTiddler.apply(this,arguments);

	// if the tiddler doesn't exist yet or is untagged, return core result
	var tiddler=store.getTiddler(title);
	if (!tiddler || !tiddler.tags.length)
		return coreTemplate;
	// split core template into theme prefix and template name
	var theme="";
	var template=coreTemplate;
	var parts=template.split(config.textPrimitives.sectionSeparator);
	if (parts[1]) { theme=parts[0]; template=parts[1]; }
	else theme=config.options.txtTheme||""; // fallback if theme is not specified
	theme+=config.textPrimitives.sectionSeparator;

	// look for template whose prefix matches a tag on this tiddler (if any)
	for (i=0; i<tiddler.tags.length; i++) {
		var t=tiddler.tags[i]+template; // add tag prefix to template
		var c=t.substr(0,1).toUpperCase()+t.substr(1); // capitalized for WikiWord title
		if (store.getTiddlerText(theme+t))	{ return theme+t; } // theme##tagTemplate
		if (store.getTiddlerText(theme+c))	{ return theme+c; } // theme##TagTemplate
		if (store.getTiddlerText(t)) 		{ return t; }	     // tagTemplate
		if (store.getTiddlerText(c))		{ return c; }	     // TagTemplate
	}
	return coreTemplate; // no matching tag, return core result
}
//}}}
config.macros.taggedTabs={};

config.macros.taggedTabs.handler=function(place,macroName,params,wikifier,paramString,tiddler,errorMsg){
	var params = paramString.parseParams("taggedTabset",null,true,false,false);
	var tagged = store.getTaggedTiddlers(params[1].value,"title").reverse();
	var cookie = "taggedTabs";
	var wrapper = createTiddlyElement(null,"div",null,"tabsetWrapper taggedTabset" + cookie);
	var tabset = createTiddlyElement(wrapper,"div",null,"tabset");
	var validTab = false;
	tabset.setAttribute("cookie",cookie);
	for(var t=0; t<tagged.length; t++) {
		var label = tagged[t].title;
		if(label=='ccLogin') 
			tabLabel = config.macros.ccLogin.buttonLogin;
		else
			tabLabel = label;
		var prompt = tagged[t].title;
		var tab = createTiddlyButton(tabset,tabLabel,prompt,config.macros.tabs.onClickTab,"tab tabUnselected");
		tab.setAttribute("tab",label);
		tab.setAttribute("content",label);
		if(config.options[cookie] == label)
			validTab = true;
	}
	if(!validTab)
		config.options[cookie] = tagged[0].title;
	place.appendChild(wrapper);
	config.macros.tabs.switchTab(tabset, config.options[cookie]);
	
	setStylesheet("div.tiddler .tab {font-size:1.2em;  font-weight:bold;padding-left:2em; padding-right:2em; margin-left:0px; margin-right:1em; padding-bottom:2px}"+
	"div.tiddler .wizard { margin:0px; }"+
	" div.tabContents .wizard { margin:0px; }"+
	".tabsetWrapper .wizard h1 {display:none}"+
	".tabsetWrapper .wizard h2 {padding:0.5em}"+
	".viewer {float:right; width:90%;}"+

"div.viewer  div.tabsetWrapper{width:90%}"+
	"a.tabSelected{ filter:'alpha(opacity:60)'; }"+
	"div.tabset {padding:0px}"+
	"div.tabContents {padding:0px; background:transparent}",
	 "taggedTabs");
	
};



//}}}
/***
|Name|TaggedTemplateTweak|
|Source|http://www.TiddlyTools.com/#TaggedTemplateTweak|
|Documentation|http://www.TiddlyTools.com/#TaggedTemplateTweakInfo|
|Version|1.4.1|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|plugin|
|Requires||
|Overrides|Story.prototype.chooseTemplateForTiddler()|
|Description|use alternative ViewTemplate/EditTemplate for tiddler's tagged with specific tag values|
This tweak extends story.chooseTemplateForTiddler() so that ''whenever a tiddler is marked with a specific tag value, it can be viewed and/or edited using alternatives to the standard tiddler templates.'' 
!!!!!Documentation
>see [[TaggedTemplateTweakInfo]]
!!!!!Revisions
<<<
2008.08.29 [1.4.1] corrected handling for tiddlers with no matching tagged template when non-default theme is in effect (e.g., use "MyTheme##ViewTemplate").
| please see [[TaggedTemplateTweakInfo]] for previous revision details |
2007.06.11 [1.0.0] initial release
<<<
!!!!!Code
***/
//{{{
	
version.extensions.TaggedTemplateTweak= {major: 1, minor: 4, revision: 1, date: new Date(2008,8,29)};

Story.prototype.taggedTemplate_chooseTemplateForTiddler = Story.prototype.chooseTemplateForTiddler
Story.prototype.chooseTemplateForTiddler = function(title,template)
{
	// get default template from core
	var coreTemplate=this.taggedTemplate_chooseTemplateForTiddler.apply(this,arguments);

	// if the tiddler doesn't exist yet or is untagged, return core result
	var tiddler=store.getTiddler(title);
	if (!tiddler || !tiddler.tags.length)
		return coreTemplate;

	// split core template into theme prefix and template name
	var theme="";
	var template=coreTemplate;
	var parts=template.split(config.textPrimitives.sectionSeparator);
	if (parts[1]) { theme=parts[0]; template=parts[1]; }
	else theme=config.options.txtTheme||""; // fallback if theme is not specified
	theme+=config.textPrimitives.sectionSeparator;

	// look for template whose prefix matches a tag on this tiddler (if any)
	for (i=0; i<tiddler.tags.length; i++) {
		var t=tiddler.tags[i]+template; // add tag prefix to template
		var c=t.substr(0,1).toUpperCase()+t.substr(1); // capitalized for WikiWord title
		if (store.getTiddlerText(theme+t))	{ return theme+t; } // theme##tagTemplate
		if (store.getTiddlerText(theme+c))	{ return theme+c; } // theme##TagTemplate
		if (store.getTiddlerText(t)) 		{ return t; }	     // tagTemplate
		if (store.getTiddlerText(c))		{ return c; }	     // TagTemplate
	}
	return coreTemplate; // no matching tag, return core result
}

powerpape
<<ccChangePassword>>
handle/proxy.php?feed=
<<ccStats>>
|~ViewToolbar|closeTiddler closeOthers +newChild newParent +editTiddler > fields -syncing permalink -revisions references jump|
|~EditToolbar|+saveTiddler copyTiddler -cancelTiddler deleteTiddlerHosted|
[[Login]]
<<ccLogin>>
<<ccCreateWorkspace>>
<<ccFile>>
<<taggedTabs loginBox>>
<<taggedTabs loginBox>>
<<ccEditWorkspace>>
<<ccUpload>>
<div class='toolbar' macro='toolbar closeTiddler closeOthers'></div>
<div class='viewer' macro='view text wikified'></div>
<div class='tagClear'></div>
powerpape
// ccAdaptorCommandsPlugin //
function ccTiddlyAdaptor(){}
merge(ccTiddlyAdaptor,{ 
	errorTitleNotSaved:"<h1>Your changes were NOT saved.</h1>", 
	errorTextSessionExpired:"Your Session has expired. <br /> You will need to log into the new window and then copy your changes from this window into the new window. ", 
	errorTextConfig:"There was a conflict when saving. <br /> Please open the page in a new window to see the changes.",
	errorTextUnknown:"An unknown error occured.",
	errorClose:"close",
	buttonOpenNewWindow:"Open a Window where I can save my changes	.... ",
	buttonHideThisMessage:"Hide this message", 
	msgErrorCode:"Error Code : "
});


if(!config.extensions) { config.extensions = {}; } //# obsolete from v2.4.2
config.extensions.ServerSideSavingPlugin = {
	adaptor: config.adaptors.cctiddly
};

//{{{
	
	config.commands.revisions = {};
	merge(config.commands.revisions,{
		text: "revisions",
		tooltip: "View another revision of this tiddler",
		loading: "loading...",
		done: "Revision downloaded",
		revisionTooltip: "View this revision",
		popupNone: "No revisions",
		revisionTemplate: "%0 r:%1 m:%2",
		dateFormat:"YYYY mmm 0DD 0hh:0mm"	
	});

	config.commands.deleteTiddlerHosted = {};
	merge(config.commands.deleteTiddlerHosted,{
		text: "delete",
		tooltip: "Delete this tiddler",
		warning: "Are you sure you want to delete '%0'?",
		hideReadOnly: true,
		done: "Deleted "
	});
	
	
// Ensure that the plugin is only installed once.
if(!version.extensions.AdaptorCommandsPlugin) {
	version.extensions.AdaptorCommandsPlugin = {installed:true};



// implementing closeTiddler without the clearMessage();
Story.prototype.closeTiddler = function(title,animate,unused)
{
	var tiddlerElem = this.getTiddler(title);
	if(tiddlerElem) {
		this.scrubTiddler(tiddlerElem);
		if(config.options.chkAnimate && animate && anim && typeof Slider == "function")
			anim.startAnimating(new Slider(tiddlerElem,false,null,"all"));
		else {
			removeNode(tiddlerElem);
			forceReflow();
		}
	}
};

function getServerType(fields)
{
	if(!fields)
		return null;
	var serverType = fields['server.type'];
	if(!serverType)
		serverType = fields['wikiformat'];
	if(!serverType)
		serverType = config.defaultCustomFields['server.type'];
	if(!serverType && typeof RevisionAdaptor != 'undefined' && fields.uuid)
		serverType = RevisionAdaptor.serverType;
	return serverType;
}

function invokeAdaptor(fnName,param1,param2,context,userParams,callback,fields)
{
	var serverType = getServerType(fields);
	if(!serverType)
		return null;
	var adaptor = new config.adaptors[serverType];
	if(!adaptor)
		return false;
	if(!config.adaptors[serverType].prototype[fnName])
		return false;
	adaptor.openHost(fields['server.host']);
	adaptor.openWorkspace(fields['server.workspace']);
	var ret = false;
	if(param1)
		ret = param2 ? adaptor[fnName](param1,param2,context,userParams,callback) : adaptor[fnName](param1,context,userParams,callback);
	else
		ret = adaptor[fnName](context,userParams,callback);
	return ret;
}

//# Returns true if function fnName is available for the serverType specified in fields
//# Used by (eg): config.commands.download.isEnabled
function isAdaptorFunctionSupported(fnName,fields)
{
	var serverType = getServerType(fields);
	if(!serverType || !config.adaptors[serverType])
		return false;
	if(!config.adaptors[serverType].isLocal && !fields['server.host'])
		return false;
	var fn = config.adaptors[serverType].prototype[fnName];
	return fn ? true : false;
}

config.commands.revisions.isEnabled = function(tiddler)
{
	return isAdaptorFunctionSupported('getTiddlerRevisionList',tiddler.fields);
};

config.commands.revisions.handler = function(event,src,title)
{
	var tiddler = store.fetchTiddler(title);
	userParams = {};
	userParams.tiddler = tiddler;
	userParams.src = src;
	userParams.dateFormat = config.commands.revisions.dateFormat;
	var revisionLimit = 10;
	if(!invokeAdaptor('getTiddlerRevisionList',title,revisionLimit,null,userParams,config.commands.revisions.callback,tiddler.fields))
		return false;
	event.cancelBubble = true;
	if(event.stopPropagation)
		event.stopPropagation();
	return true;
};

config.commands.revisions.callback = function(context,userParams)
// The revisions are returned as tiddlers in the context.revisions array
{
	var revisions = context.revisions;
	popup = Popup.create(userParams.src);
	Popup.show(popup,false);
	if(revisions.length==0) {
		createTiddlyText(createTiddlyElement(popup,'li',null,'disabled'),config.commands.revisions.popupNone);
	} else {
		revisions.sort(function(a,b) {return a.modified < b.modified ? +1 : -1;});
		for(var i=0; i<revisions.length; i++) {
			var tiddler = revisions[i];
			var modified = tiddler.modified.formatString(context.dateFormat||config.commands.revisions.dateFormat);
			var revision = tiddler.fields['server.page.revision'];
			var btn = createTiddlyButton(createTiddlyElement(popup,'li'),
					config.commands.revisions.revisionTemplate.format([modified,revision,tiddler.modifier]),
					tiddler.text||config.commands.revisions.revisionTooltip,
					function() {
						config.commands.revisions.getTiddlerRevision(this.getAttribute('tiddlerTitle'),this.getAttribute('tiddlerModified'),this.getAttribute('tiddlerRevision'),this);
						return false;
						},
					'tiddlyLinkExisting tiddlyLink');
			btn.setAttribute('tiddlerTitle',userParams.tiddler.title);
			btn.setAttribute('tiddlerRevision',revision);
			btn.setAttribute('tiddlerModified',tiddler.modified.convertToYYYYMMDDHHMM());
			if(userParams.tiddler.fields['server.page.revision'] == revision || (!userParams.tiddler.fields['server.page.revision'] && i==0))
				btn.className = 'revisionCurrent';
		}
	}
};

config.commands.revisions.getTiddlerRevision = function(title,modified,revision)
{
	var tiddler = store.fetchTiddler(title);
	var context = {modified:modified};
	return invokeAdaptor('getTiddlerRevision',title,revision,context,null,config.commands.revisions.getTiddlerRevisionCallback,tiddler.fields);
};

config.commands.revisions.getTiddlerRevisionCallback = function(context,userParams)
{
	if(context.status) {
		var tiddler = context.tiddler;
		store.addTiddler(tiddler);
		store.notify(tiddler.title, true);
		story.refreshTiddler(tiddler.title,1,true);
	} else {
		displayMessage(context.statusText);
	}
};

config.commands.deleteTiddlerHosted.handler = function(event,src,title)
{
	var tiddler = store.fetchTiddler(title);
		if(!tiddler)
			return false;
		var deleteIt = true;
		if(config.options.chkConfirmDelete)
		        deleteIt = confirm(this.warning.format([title]));
		if(deleteIt) {
			var ret = invokeAdaptor('deleteTiddler',title,null,null,null,config.commands.deleteTiddlerHosted.callback,tiddler.fields);
			if(ret){
				store.removeTiddler(title);
				story.closeTiddler(title,true);
			}
		}
		return false;

};

config.commands.deleteTiddlerHosted.callback = function(context,userParams)
{
	if(context.status) {
		displayMessage(config.commands.deleteTiddlerHosted.done + context.title);
	} else {
		if (context.statusText.indexOf("Not Found") == -1)
			displayMessage(context.statusText);
	}
};

}//# end of 'install only once'
//}}}


// ccAdaptor //

//{{{

	window.isLoggedIn = function(){
		return (window.loggedIn == '1') 
	}

	ccTiddlyAdaptor.prototype = new AdaptorBase();

	ccTiddlyAdaptor.mimeType = 'application/json';
	ccTiddlyAdaptor.serverType = 'cctiddly'; // MUST BE LOWER CASE
	ccTiddlyAdaptor.serverParsingErrorMessage = "Error parsing result from server";
	ccTiddlyAdaptor.errorInFunctionMessage = "Error in function ccTiddlyAdaptor.%0";

	ccTiddlyAdaptor.minHostName = function(host){
		return host ? host.replace(/^http:\/\//,'').replace(/\/$/,'') : '';
	};

	// Convert a page title to the normalized form used in uris
	ccTiddlyAdaptor.normalizedTitle = function(title){
		return title;
	};

	// Convert a date in YYYY-MM-DD hh:mm format into a JavaScript Date object
	ccTiddlyAdaptor.dateFromEditTime = function(editTime){
		var dt = editTime;
		return new Date(Date.UTC(dt.substr(0,4),dt.substr(5,2)-1,dt.substr(8,2),dt.substr(11,2),dt.substr(14,2)));
	};

	ccTiddlyAdaptor.prototype.login = function(context,userParams,callback){
		if(window.location.search.substring(1))
			var uriParams = window.location.search.substring(1);
		else
			var uriParams = "";
		context = this.setContext(context,userParams,callback);
		var uriTemplate = '%0/handle/loginFile.php?cctuser=%1&cctpass=%2&'+uriParams;
		var uri = uriTemplate.format([context.host,context.username,context.password]);
		var req = httpReq('GET',uri,ccTiddlyAdaptor.loginCallback,context);
		return typeof req == 'string' ? req : true;
	};

	ccTiddlyAdaptor.loginCallback = function(status,context,responseText,uri,xhr){
		if(xhr.status==401){
			context.status = false;
		}else{
			context.status = true;
			var c='sessionToken'+"="+responseText;
				c+="; expires=Fri, 1 Jan 2811 12:00:00 UTC; host=*";
				document.cookie=c;
		}
		if(context.callback)
			context.callback(context,context.userParams);
	};

	ccTiddlyAdaptor.prototype.register = function(context,userParams,callback){
		context = this.setContext(context,userParams,callback);
		var uriTemplate = '%0/handle/register.php';
		var uri = uriTemplate.format([context.host,context.username,Crypto.hexSha1Str(context.password)]);
		var dataTemplate = 'username=&0&reg_mail=%1&password=%2&password2=%3';
		var data = dataTemplate.format([context.username,context.password1,context.password2]);
		var req = httpReq('POST', uri,ccTiddlyAdaptor.registerCallback,context,null,data);
		return typeof req == 'string' ? req : true;
	};

	ccTiddlyAdaptor.prototype.rename = function(context, userParams, callback){
		if(window.location.search.substring(1))
			var postParams = "&"+window.location.search.substring(1);
		else
			var postParams = "";
		context = this.setContext(context,userParams,callback);
		var uri = window.url+"handle/renameTiddler.php?otitle="+context.title+"&ntitle="+context.newTitle+"&workspace="+window.workspace+postParams;;
		httpReq('POST', uri,ccTiddlyAdaptor.renameCallback,context,null,null);
	};

	ccTiddlyAdaptor.renameCallback = function(status,context,responseText,uri,xhr){
		if(context.callback)
			context.callback(context,context.userParams);
	};

	ccTiddlyAdaptor.registerCallback = function(status,context,responseText,uri,xhr){
		if(status){
			context.status = true;
		}else{
			context.status = false;
		}
		if(context.callback)
			context.callback(context,context.userParams);
	};

	ccTiddlyAdaptor.prototype.getWorkspaceList = function(context,userParams,callback){
	 	context = this.setContext(context,userParams,callback);
		var uriTemplate = '%0/handle/listWorkspaces.php';
		var uri = uriTemplate.format([context.host]);
		var req = httpReq('GET', uri,ccTiddlyAdaptor.getWorkspaceListCallback,context,{'accept':'application/json'});
		return typeof req == 'string' ? req : true;
	};

	ccTiddlyAdaptor.getWorkspaceListCallback = function(status,context,responseText,uri,xhr){
		context.status = false;
		context.workspaces = [];
		context.statusText = ccTiddlyAdaptor.errorInFunctionMessage.format(['getWorkspaceListCallback']);
		if(status){
		try{
			eval('var workspaces=' + responseText);
		}catch (ex){
			context.statusText = exceptionText(ex,ccTiddlyAdaptor.serverParsingErrorMessage);
			if(context.callback)
				context.callback(context,context.userParams);
				return;
			}
			for (var i=0; i < workspaces.length; i++){
				context.workspaces.push({title:workspaces[i]})
			}
			context.status = true;
		}else{
				context.statusText = xhr.statusText;
		}
		if(context.callback)
			context.callback(context,context.userParams);
	};

	ccTiddlyAdaptor.prototype.getTiddlerList = function(context,userParams,callback){
		context = this.setContext(context,userParams,callback);
		var uriTemplate = '%0/handle/listTiddlers.php?workspace=%1';
		var uri = uriTemplate.format([context.host,context.workspace]);
		var req = httpReq('GET', uri,ccTiddlyAdaptor.getTiddlerListCallback,context,{'accept':'application/json'});
		return typeof req == 'string' ? req : true;
	};

	ccTiddlyAdaptor.getTiddlerListCallback = function(status,context,responseText,uri,xhr){
		context.status = false;
		context.statusText = ccTiddlyAdaptor.errorInFunctionMessage.format(['getTiddlerListCallback']);
		if(status){
			try{
				eval('var tiddlers=' + responseText);
			}catch (ex){
				context.statusText = exceptionText(ex,ccTiddlyAdaptor.serverParsingErrorMessage);
				if(context.callback)
					context.callback(context,context.userParams);
				return;
			}
			var list = [];
			for(var i=0; i < tiddlers.length; i++){
				var tiddler = new Tiddler(tiddlers[i]['title']);
				tiddler.fields['server.page.revision'] = tiddlers[i]['revision'];
				list.push(tiddler);
			}
			context.tiddlers = list;
			context.status = true;
		}else{
			context.statusText = xhr.statusText;
		}
		if(context.callback)
			context.callback(context,context.userParams);
	};

	ccTiddlyAdaptor.prototype.generateTiddlerInfo = function(tiddler){
		var info ={};
		var host = this && this.host ? this.host : this.fullHostName(tiddler.fields['server.host']);
		var bag = tiddler.fields['server.bag']
		var workspace = tiddler.fields['server.workspace']
		var uriTemplate = '%0/%1/#%2';
		info.uri = uriTemplate.format([host,workspace,tiddler.title]);
		return info;
	};

	ccTiddlyAdaptor.prototype.getTiddlerRevision = function(title,revision,context,userParams,callback){
		context = this.setContext(context,userParams,callback);
		if(revision)
			context.revision = revision;
		return this.getTiddler(title,context,userParams,callback);
	};

	ccTiddlyAdaptor.prototype.getTiddler = function(title,context,userParams,callback){
		context = this.setContext(context,userParams,callback);
		if(title)
			context.title = title;
		   if(context.revision){
		         var uriTemplate = '%0/handle/revisionDisplay.php?title=%2&workspace=%1&revision=%3';
		  }else{
				var uriTemplate = '%0/handle/getTiddler.php?title=%2&workspace=%1';
		  }

		uri = uriTemplate.format([context.host,context.workspace,ccTiddlyAdaptor.normalizedTitle(title),context.revision]);
		context.tiddler = new Tiddler(title);
		context.tiddler.fields['server.type'] = ccTiddlyAdaptor.serverType;
		context.tiddler.fields['server.host'] = ccTiddlyAdaptor.minHostName(context.host);
		context.tiddler.fields['server.workspace'] = context.workspace;
		var req = httpReq('GET', uri,ccTiddlyAdaptor.getTiddlerCallback,context,{'accept':'application/json'});
		return typeof req == 'string' ? req : true;
	};

	ccTiddlyAdaptor.getTiddlerCallback = function(status,context,responseText,uri,xhr){
	        context.status = false;
	        context.statusText = ccTiddlyAdaptor.errorInFunctionMessage.format(['getTiddlerCallback']);
	        if(status){
	                var info=[]
	                try{
	                    eval('info=' + responseText);
	                }catch (ex){
	                        context.statusText = exceptionText(ex,ccTiddlyAdaptor.serverParsingErrorMessage);
	                        if(context.callback)
	                                context.callback(context,context.userParams);
	                        return;
	                }
	                context.tiddler.text = info['text'];
					context.tiddler.tags = info['tags'].split(" ");
	                context.tiddler.fields['server.page.revision'] = info['server.page.revision'];
					context.tiddler.fields['server.id'] = info['id'];
					context.tiddler.fields = merge(info['fields'], context.tiddler.fields);
				    context.tiddler.modifier = info['modifier'];
	                context.tiddler.modified = Date.convertFromYYYYMMDDHHMM(info['modified']);
	                context.tiddler.created = Date.convertFromYYYYMMDDHHMM(info['created']);
	                context.status = true;
	        }else{
	                context.statusText = xhr.statusText;
	                if(context.callback)
	                        context.callback(context,context.userParams);
	                return;
	        }
	        if(context.callback)
			context.callback(context,context.userParams);
	};

	ccTiddlyAdaptor.prototype.getTiddlerRevisionList = function(title,limit,context,userParams,callback){
		context = this.setContext(context,userParams,callback);
		context.title = title;
		context.revisions = [];
		var tiddler = store.fetchTiddler(title);
		var encodedTitle = encodeURIComponent(title);
		var uriTemplate = '%0/handle/revisionList.php?workspace=%1&title=%2';
		var host = this.fullHostName(this.host);
		var workspace = context.workspace ? context.workspace : tiddler.fields['server.workspace'];
		var uri = uriTemplate.format([host,workspace,encodedTitle]);
		var req = httpReq('GET', uri,ccTiddlyAdaptor.getTiddlerRevisionListCallback,context);
	};

	ccTiddlyAdaptor.getTiddlerRevisionListCallback = function(status,context,responseText,uri,xhr){
		if(responseText.indexOf('<!DOCTYPE html')==1)
			status = false;
		if(xhr.status=="204")
			status = false;
		context.status = false;
		if(status){
			var r =  responseText;
			if(r != '-' && r.trim() != 'revision not found'){
				var revs = r.split('\n');
				for(var i=0; i<revs.length; i++){
					var parts = revs[i].split(' ');
					if(parts.length>1){
						var tiddler = new Tiddler(context.title);
						tiddler.modified = Date.convertFromYYYYMMDDHHMM(parts[0]);
						tiddler.fields['server.page.revision'] = String(parts[1]);
						tiddler.modifier = String(parts[2]);
						tiddler.fields['server.host'] = ccTiddlyAdaptor.minHostName(context.host);
						tiddler.fields['server.type'] = ccTiddlyAdaptor.serverType;
						context.revisions.push(tiddler);
					}
				}
			}
			context.revisions.sort(function(a,b){return a.modified<b.modified?+1:-1;});
			context.status = true;
		}else{
			context.statusText = xhr.statusText;
		}
		if(context.callback)
			context.callback(context,context.userParams);
	};

	ccTiddlyAdaptor.prototype.putTiddler = function(tiddler,context,userParams,callback){
		context = this.setContext(context,userParams,callback);
		context.title = tiddler.title;
		if(window.location.search.substring(1))
			var postParams = window.location.search.substring(1);
		else
			var postParams = "";
		var recipeuriTemplate = '%0/handle/save.php';
		var host = context.host ? context.host : this.fullHostName(tiddler.fields['server.host']);
		var uri = recipeuriTemplate.format([host,context.workspace,tiddler.title]);
		var d = new Date();
		d.setTime(Date.parse(tiddler['modified']));
		d = d.convertToYYYYMMDDHHMM();

		//  SEO Code

		if(workspace)
		 	var breaker = "/";
		else
			var breaker = "";
		var el = createTiddlyElement(document.body, "div", "ccTiddlyTMP", null, null, { "style.display": "none" });
		el.style.display = "none";  // Just in case the above command is ignored
		var formatter = new Formatter(config.formatters);
		var wikifier = new Wikifier(tiddler.text,formatter,null,tiddler);
			wikifier.isStatic = true;
			wikifier.subWikify(el);
		delete formatter;
		var links = el.getElementsByTagName("a");
		for(var i = 0; i < links.length; i++) {
			var tiddlyLink = links[i].getAttribute("tiddlyLink");
		    if(tiddlyLink) {
		        if(hasClass(links[i], "tiddlyLinkNonExisting")) { // target tiddler does not exist
		            links[i].href = "#";
		        } else {
		            links[i].href = url+ workspace + breaker +tiddlyLink + ".html";
		        }
		    }
		}	
		// End SEO Code 

		var fieldString = "";
		for (var name in tiddler.fields){
			if (String(tiddler.fields[name]) && name != "server.page.revision" && name != "changecount")
				fieldString += name +"='"+tiddler.fields[name]+"' ";
		}
		if(!tiddler.fields['server.page.revision'])
			tiddler.fields['server.page.revision'] = 0;		
		else
			tiddler.fields['server.page.revision'] = parseInt(tiddler.fields['server.page.revision'],10);
		context.revision = tiddler.fields['server.page.revision'];
		if(!context.otitle)
			var otitle = tiddler.title;
		else
			var otitle = context.otitle;
		var payload = "workspace="+window.workspace+"&otitle="+encodeURIComponent(otitle)+"&title="+encodeURIComponent(tiddler.title) + "&modified="+tiddler.modified.convertToYYYYMMDDHHMM()+"&modifier="+tiddler.modifier + "&tags="+encodeURIComponent(tiddler.getTags())+"&revision="+encodeURIComponent(tiddler.fields['server.page.revision']) + "&fields="+encodeURIComponent(fieldString)+
	"&body="+encodeURIComponent(tiddler.text)+"&wikifiedBody="+encodeURIComponent(el.innerHTML)+"&id="+tiddler.fields['server.id']+"&"+postParams;
		var req = httpReq('POST', uri,ccTiddlyAdaptor.putTiddlerCallback,context,{'Content-type':'application/x-www-form-urlencoded', "Content-length": payload.length},payload,"application/x-www-form-urlencoded");
		return typeof req == 'string' ? req : true;
	};

	ccTiddlyAdaptor.putTiddlerCallback = function(status,context,responseText,uri,xhr){
		
		if(xhr.status != 201){
			ccTiddlyAdaptor.handleError(xhr.status);
		}else{
			context.status = true;
			if(responseText!="") {
				context.tiddler.fields['server.id'] = responseText;
			}
			context.tiddler.fields['server.page.revision'] = context.revision + 1;
		}
		if(context.callback){
			context.callback(context,context.userParams);
		}
	};
	
	
	ccTiddlyAdaptor.center  = function(el){
		var size = this.getsize(el);
		el.style.left = (Math.round(findWindowWidth()/2) - (size.width /2) + findScrollX())+'px';
		el.style.top = (Math.round(findWindowHeight()/2) - (size.height /2) + findScrollY())+'px';
	}

	ccTiddlyAdaptor.getsize = function (el){
		var x ={};
		x.width = el.offsetWidth || el.style.pixelWidth;
		x.height = el.offsetHeight || el.style.pixelHeight;
		return x;
	}

	ccTiddlyAdaptor.showCloak = function(){
		var cloak = document.getElementById('backstageCloak');
		if (config.browser.isIE){
			cloak.style.height = Math.max(document.documentElement.scrollHeight,document.documentElement.offsetHeight);
			cloak.style.width = document.documentElement.scrollWidth;
		}
		cloak.style.display = "block";
	}

	ccTiddlyAdaptor.hideError = function(){
		var box = document.getElementById('errorBox');
		box.parentNode.removeChild(box);
		document.getElementById('backstageCloak').style.display = "";
	}

	ccTiddlyAdaptor.handleError = function(error_code){
		setStylesheet(
		"#errorBox .button{padding:0.5em 1em; border:1px solid #222; background-color:#ccc; color:black; margin-right:1em;}\n"+
		"html > body > #backstageCloak{height:100%;}"+
		"#errorBox{border:1px solid #ccc;background-color: #eee; color:#111;padding:1em 2em; z-index:9999;}",'errorBoxStyles');
		var box = document.getElementById('errorBox') || createTiddlyElement(document.body,'div','errorBox');
		var error = ccTiddlyAdaptor.errorTitleNotSaved;
		switch(error_code){
			case 401:
				error += ccTiddlyAdaptor.errorTextSessionExpired;
				break;
			case 409:
				error += "\n\n"+ccTiddlyAdaptor.errorTextConfig+"\n \n error code : "+error_code+" \n";
				break;

			default:
				error += ccTiddlyAdaptor.errorTextUnknown+"<br />"+error_code;
		}
		box.innerHTML = " <a style='float:right' href='javascript:onclick=ccTiddlyAdaptor.hideError()'>"+ccTiddlyAdaptor.errorClose+"</a><p>"+error+"</p><br/><br/>";
		createTiddlyButton(box,ccTiddlyAdaptor.buttonOpenNewWindow,null,function(e){ window.open (window.location,"mywindow");	 return false;});
		createTiddlyElement(box,"br");
		createTiddlyElement(box,"br");
		createTiddlyButton(box,ccTiddlyAdaptor.buttonHideThisMessage,null,function(){ccTiddlyAdaptor.hideError();});
		box.style.position = 'absolute';
		ccTiddlyAdaptor.center(box);
		ccTiddlyAdaptor.showCloak();
	}

	ccTiddlyAdaptor.prototype.deleteTiddler = function(title,context,userParams,callback){	
		context = this.setContext(context,userParams,callback);
		context.title = title;
		title = encodeURIComponent(title);
		var uri = tiddler.fields['server.host']+'/handle/delete.php'
		var data = "workspace="+workspace+"&title="+title;
		
		var req = httpReq('POST', uri,ccTiddlyAdaptor.deleteTiddlerCallback,context, null, data);
		return typeof req == 'string' ? req : true;
	};

	ccTiddlyAdaptor.deleteTiddlerCallback = function(status,context,responseText,uri,xhr){
		if(status){
			context.status = true;
		}else{
			context.status = false;
			context.statusText = xhr.statusText;
		}
		if(context.callback)
			context.callback(context,context.userParams);
	};

	config.adaptors[ccTiddlyAdaptor.serverType] = ccTiddlyAdaptor;
//}}}


//}}}

//{{{
	
//  ccAbout //
config.macros.ccAbout={};

config.macros.ccAbout.handler=function(place,macroName,params,wikifier,paramString,tiddler,errorMsg){
	var w = new Wizard();
	var me = config.macros.ccAbout;
	w.createWizard(place,me.stepAboutTitle);
	w.addStep(null, me.stepAboutTextStart + window.ccTiddlyVersion + "<br /><br />" + me.stepAboutTextEnd);
};
//}}}

// ccAdmin //
//{{{
config.macros.ccAdmin = {}
config.macros.ccAdmin.handler = function(place,macroName,params,wikifier,paramString,tiddler, errorMsg){
	var w = new Wizard();
	w.createWizard(place,config.macros.ccAdmin.WizardTitleText);
	config.macros.ccAdmin.refresh(w);
};

config.macros.ccAdmin.refresh= function(w){
	params = {};
	params.w = w;
	params.e = this;
	me = config.macros.ccAdmin;
	doHttp('POST',url+'/handle/workspaceAdmin.php','action=LISTALL&workspace='+workspace,null,null,null,config.macros.ccAdmin.listAllCallback,params);
	w.setButtons([
		{caption: me.buttonDeleteText, tooltip: me.buttonDeleteTooltip, onClick: function(w){ 
			config.macros.ccAdmin.delAdminSubmit(null, params);
		 	return false;
		}}, 
		{caption: me.buttonAddText, tooltip: me.buttonAddTooltip, onClick: function(w){
			config.macros.ccAdmin.addAdminDisplay(null, params); return false } }]);
};

config.macros.ccAdmin.delAdminSubmit = function(e, params){
	var listView = params.w.getValue("listView");
	var rowNames = ListView.getSelectedRows(listView);
	var delUsers = "";
	for(var e=0; e < rowNames.length; e++) 
		delUsers += rowNames[e]+",";
	doHttp('POST',url+'/handle/workspaceAdmin.php','action=DELETEADMIN&username='+delUsers+'&workspace='+workspace,null,null,null,config.macros.ccAdmin.addAdminCallback,params);
	return false; 
};

config.macros.ccAdmin.addAdminDisplay = function(e, params){
	doHttp('POST',url+'/handle/workspaceAdmin.php','action=LISTWORKSPACES',null,null,null,config.macros.ccAdmin.listWorkspaces,params);
};

config.macros.ccAdmin.listWorkspaces = function(status,params,responseText,uri,xhr){
	var frm = createTiddlyElement(null,'form',null,null);
	var me = config.macros.ccAdmin;
	frm.onsubmit = config.macros.ccAdmin.addAdminSubmit;	
	params.w.addStep(me.stepAddTitle,"<input type='hidden' name='admin_placeholder'/>"+me.labelUsername+"<input name=adminUsername><br />"+me.labelWorkspace+"<select name=workspaceName />");
	var workspaces = eval('[ '+responseText+' ]');
	for(var t=0; t<workspaces.length; t++) {
		var o = createTiddlyElement(params.w.formElem.workspaceName, "option", null, null, workspaces[t]);
		o.value=workspaces[t];
		if(workspaces[t] == workspace)
			o.selected = true;
	}
	params.w.formElem.admin_placeholder.parentNode.appendChild(frm);
	params.w.setButtons([
		{caption: me.buttonCancelText, tooltip: me.buttonCancelTooltip, onClick: function(w){ config.macros.ccAdmin.refresh(params.w) } },
		{caption: me.buttonCreateText, tooltip: me.buttonCreateTooltip, onClick: function(){config.macros.ccAdmin.addAdminSubmit(null, params);  } }
	]);
};

config.macros.ccAdmin.addAdminSubmit = function(e, params){
	doHttp('POST',url+'/handle/workspaceAdmin.php','&add_username='+params.w.formElem.adminUsername.value+'&action=addNew&workspace='+params.w.formElem.workspaceName[params.w.formElem.workspaceName.selectedIndex].value,null,null,null,config.macros.ccAdmin.addAdminCallback,params);
	return false; 
};

config.macros.ccAdmin.listAllCallback = function(status,params,responseText,uri,xhr) {
	var me = config.macros.ccAdmin;
	var out = "";
	var adminUsers = [];
	if(xhr.status == 403){
		var html ='';
		params.w.addStep(me.stepErrorText+workspace, me.stepErrorTitle);
		params.w.setButtons([]);
		return false;
	}
	try{
		var a = eval(responseText);
		for(var e=0; e < a.length; e++){
			out += a[e].username;
			adminUsers.push({
			name: a[e].username,
			lastVisit:a[e].lastVisit});
		}
	}catch(ex){
			params.w.addStep(" "+workspace, me.stepNoAdminTitle);
			params.w.setButtons([
				{caption: me.buttonCreateText, tooltip: me.buttonCreateTooltip, onClick: function(){ config.macros.ccAdmin.addAdminDisplay(null, params)}}]);
			return false;
	}
	var html ='<input type="hidden" name="markList"></input>';
	params.w.addStep(me.stepManageWorkspaceTitle+workspace, html);
	var markList = params.w.getElement("markList");
	var listWrapper = document.createElement("div");
	markList.parentNode.insertBefore(listWrapper,markList);
	var listView = ListView.create(listWrapper,adminUsers,config.macros.ccAdmin.listAdminTemplate);
	params.w.setValue("listView",listView);
};

config.macros.ccAdmin.addAdminCallback = function(status,params,responseText,uri,xhr) {
	config.macros.ccAdmin.refresh(params.w);
};
// ccChangePassword //

// {{{
	
	config.macros.ccChangePassword={};
	
	config.macros.ccChangePassword.handler=function(place,macroName,params,wikifier,paramString,tiddler,errorMsg){
		var w = new Wizard();
		var me = config.macros.ccChangePassword;
		w.createWizard(place,me.title);
		w.addStep(me.subTitle+cookieString(document.cookie).txtUserName,me.step1Html);
		w.setButtons([
			{caption: me.buttonChangeText, tooltip: me.buttonChangeToolTip, onClick: function(){config.macros.ccChangePassword.doPost(w);  } }
		]);
	};

	config.macros.ccChangePassword.doPost = function (w) {
		me = config.macros.ccChangePassword;
		if(!w.formElem.new1.value || !w.formElem.new2.value || !w.formElem.old.value) {
			displayMessage(me.noticePasswordUpdateFailed);
			return false;
		}
		if(w.formElem.new1.value != w.formElem.new2.value){
			displayMessage(me.noticePasswordsNoMatch);
			return false;
		}
		doHttp("POST", url+"handle/changePassword.php", "&new1="+Crypto.hexSha1Str(w.formElem.new1.value)+"&new2="+Crypto.hexSha1Str(w.formElem.new2.value)+"&old1="+Crypto.hexSha1Str(w.formElem.old.value),null,null,null,config.macros.ccChangePassword.callback);	
	}

	config.macros.ccChangePassword.callback = function(status,context,responseText,uri,xhr) {
		if(xhr.status == 304)
			displayMessage(me.noticePasswordUpdateFailed);
		else
			displayMessage(me.noticePasswordUpdated);
	}

	//}}}
//{{{

config.macros.ccCreateWorkspace = {};

config.macros.ccCreateWorkspace.setStatus=function(w,element,text){
	var label_var = w.getElement(element);
	removeChildren(label_var.previousSibling);
	var label = document.createTextNode(text);
	label_var.previousSibling.insertBefore(label,null);
}

config.macros.ccCreateWorkspace.workspaceNameKeyPress=function(w){
	params={};
	params.w = w;
	doHttp('POST',url+'/handle/lookupWorkspaceName.php',"ccWorkspaceLookup="+w.formElem["workspace_name"].value+"&free=1",null,null,null,config.macros.ccCreateWorkspace.workspaceNameCallback,params);	
	return false;
};
 	
config.macros.ccCreateWorkspace.workspaceNameCallback=function(status,params,responseText,uri,xhr){
	var me = config.macros.ccCreateWorkspace;
	if(responseText > 0){{
			config.macros.register.setStatus(params.w, "workspace_error", me.errorWorkspaceNameInUse);
			config.macros.register.setStatus(params.w, "workspace_url", "");
	}}else{
		config.macros.register.setStatus(params.w, "workspace_error", me.msgWorkspaceAvailable);
		if (window.useModRewrite == 1)
			config.macros.register.setStatus(params.w, "workspace_url", url+''+params.w.formElem["workspace_name"].value);			 
		else
			config.macros.register.setStatus(params.w, "workspace_url", url+'?workspace='+params.w.formElem["workspace_name"].value);
	}
};

config.macros.ccCreateWorkspace.handler =  function(place,macroName,params,wikifier,paramString,tiddler, errorMsg){
	if (window.workspacePermission.canCreateWorkspace!=1) {
		createTiddlyElement(place,'div', null, "annotation",  config.macros.ccCreateWorkspace.errorPermissions);
		return null;
	}
	var me = config.macros.ccCreateWorkspace;
	var w = new Wizard();
	w.createWizard(place,me.wizardTitle);
	if(config.macros.ccCreateWorkspace.createWorkspaceAdvanced)
		me.stepCreateHtml += config.macros.ccCreateWorkspace.createWorkspaceAdvanced();

	w.addStep(me.stepTitle, me.stepCreateHtml);
	w.formElem["workspace_name"].onkeyup=function() {me.workspaceNameKeyPress(w);};
	w.formElem.onsubmit = function() { config.macros.ccCreateWorkspace.createWorkspaceOnSubmit(w);  return false;};
	w.setButtons([
		{caption: me.buttonCreateWorkspaceText, tooltip: me.buttonCreateWorkspaceTooltip, onClick:function(){config.macros.ccCreateWorkspace.createWorkspaceOnSubmit(w);}
	}]);
};

config.macros.ccCreateWorkspace.createWorkspaceOnSubmit = function(w){
	var params = {}; 
	params.w = w;	
	if(window.useModRewrite == 1)
		params.url = url+w.formElem["workspace_name"].value; 
	else
		params.url = url+'?workspace='+w.formElem["workspace_name"].value;
	var loginResp = doHttp('POST',url+'?&workspace='+w.formElem["workspace_name"].value+"/",'&ccCreateWorkspace=' + encodeURIComponent(w.formElem["workspace_name"].value)+'&amp;ccAnonPerm='+encodeURIComponent("AADD"),null,null,null,config.macros.ccCreateWorkspace.createWorkspaceCallback,params);
	return false; 
};

config.macros.ccCreateWorkspace.createWorkspaceCallback = function(status,params,responseText,uri,xhr) {
	if(xhr.status==201){
		params.w.addStep("Please wait", "This could take afew minutes depending on your internet connection.<img src='http://www.ajaxload.info/cache/FF/FF/FF/00/00/00/37-0.gif'/>"+"<br/><br/><input width='300' name='statusMarker'/>");
		params.w.setButtons([]);
		if(params.selectedPackage) {
	   		var url = store.getTiddlerSlice(params.selectedPackage,'URL');
			loadRemoteFile(url,config.macros.ccCreateWorkspace.fetchFileCallback ,params);
		} else {
			window.location = params.url;
		}
	}else if(xhr.status == 200){
		displayMessage(config.macros.ccCreateWorkspace.errorWorkspaceNameInUse);
	}else if(xhr.status == 403){
		displayMessage(config.macros.ccCreateWorkspace.errorPermissions);	
	}else{
			displayMessage("sd"+responseText);	
	}
};

//}}}


// ccEditWorkspace //


//{{{
config.macros.ccEditWorkspace={};			
config.macros.ccEditWorkspace.handler = function(place, macroName, params, wikifier, paramString, tiddler){
	var me = config.macros.ccEditWorkspace;
	if(workspacePermission.owner !=1){
		createTiddlyElement(place,'div', null, "annotation",  me.errorTextPermissionDenied);
		return null;
	}
	var w = new Wizard();
	w.createWizard(place, this.WizardTitleText);
	var booAdmin = false;
	var booUser = false;
	var booAnon = false;
	// Check which colums to display
	for(i = 0; i <= params.length - 1; i++){
		switch (params[i].toLowerCase()) {
			case 'admin':
				booAdmin = true;
				break;
			case 'user':
				booUser = true;
				break;
			case 'anon':
				booAnon = true;
				break;
		}
	}
	// if nothing passed show all
	if(!booAdmin && !booUser && !booAnon){
		booAdmin = true;
		booUser = true;
		booAnon = true;
	}
	var tableBodyBuffer = new Array();
	tableBodyBuffer.push('<table border=0px class="listView twtable">');
	tableBodyBuffer.push('<tr">');
	tableBodyBuffer.push('<th>' + this.stepLabelPermission + '</th>');
	if(booAnon){
		tableBodyBuffer.push('<th>' + this.stepLabelAnon + '</th>');
	}
	if(booUser){
		tableBodyBuffer.push('<th>' + this.stepLabelUser + '</th>');
	}
	if(booAdmin){
		tableBodyBuffer.push('<th>' + this.stepLabelAdmin + '</th>');
	}
	tableBodyBuffer.push('</tr>');
	tableBodyBuffer.push('<tr>')
	tableBodyBuffer.push('<th align="right">'+this.stepLabelRead+'</th>');
	if(booAnon){
		tableBodyBuffer.push('<td><input name="anR" class="checkInput" type="checkbox" ');
		tableBodyBuffer.push(workspacePermission.anonR == 1 ? 'checked' : '');
		tableBodyBuffer.push(' ></input></td>');
	}
	if(booUser){
		tableBodyBuffer.push('<td><input name="usR" class="checkInput" type="checkbox" ');
		tableBodyBuffer.push(workspacePermission.userR == 1 ? 'checked' : '');
		tableBodyBuffer.push('></input></td>');
	}
	if(booAdmin){
		tableBodyBuffer.push('<td><input name="adR" class="checkInput" type="checkbox" checked disabled></input></td>');
	}
	tableBodyBuffer.push('</tr>');
	tableBodyBuffer.push('<tr>');
	tableBodyBuffer.push('<th  align="right">' + this.stepLabelCreate + '</th>');
	if(booAnon){
		tableBodyBuffer.push('<td><input name="anC" class="checkInput" type="checkbox" ');
		tableBodyBuffer.push(workspacePermission.anonC == 1 ? 'checked' : '');
		tableBodyBuffer.push(' ></input></td>');
	}
	if(booUser){
		tableBodyBuffer.push('<td><input name="usC" class="checkInput" type="checkbox" ');
		tableBodyBuffer.push(workspacePermission.userC == 1 ? 'checked' : '');
		tableBodyBuffer.push(' ></input></td>');
	}
	if(booAdmin){
		tableBodyBuffer.push('<td><input name="adC" class="checkInput" type="checkbox" checked disabled></input></td>');
	}
	tableBodyBuffer.push('</tr>');
	tableBodyBuffer.push('<tr>');
	tableBodyBuffer.push('<th  align="right">' + this.stepLabelUpdate + '</th>');
	if(booAnon){
		tableBodyBuffer.push('<td><input name="anU" class="checkInput" type="checkbox" ');
		tableBodyBuffer.push(workspacePermission.anonU == 1 ? 'checked' : '');
		tableBodyBuffer.push(' ></input></td>');
	}
	if(booUser){
		tableBodyBuffer.push('<td><input name="usU" class="checkInput" type="checkbox" ');
		tableBodyBuffer.push(workspacePermission.userU == 1 ? 'checked' : '');
		tableBodyBuffer.push(' ></input></td>');
	}
	if(booAdmin){
		tableBodyBuffer.push('<td><input name="adU" class="checkInput" type="checkbox" checked disabled></input></td>');
	}
	tableBodyBuffer.push('</tr>');
	tableBodyBuffer.push('<tr>');
	tableBodyBuffer.push('<th  align="right">' + this.stepLabelDelete + '</th>');
	if(booAnon){
		tableBodyBuffer.push('<td><input name="anD" class="checkInput" type="checkbox" ');
		tableBodyBuffer.push(workspacePermission.anonD == 1 ? 'checked' : '');
		tableBodyBuffer.push(' ></input></td>');
	}
	if(booUser){
		tableBodyBuffer.push('<td><input name="usD" class="checkInput" type="checkbox" ');
		tableBodyBuffer.push(workspacePermission.userD == 1 ? 'checked' : '');
		tableBodyBuffer.push(' ></input></td>');
	}
	if(booAdmin){
		tableBodyBuffer.push('<td><input name="adD" class="checkInput" type="checkbox" checked disabled></input></td>');
	}
	tableBodyBuffer.push('</tr>');
	tableBodyBuffer.push('</table>');
	var stepHTML = tableBodyBuffer.join('');
	w.addStep(this.stepEditTitle,stepHTML);
	w.setButtons([
		{caption: this.buttonSubmitCaption, tooltip: this.buttonSubmitToolTip, onClick: function() {me.ewSubmit(place, macroName, params, wikifier, paramString, tiddler,w,booAnon,booUser);}
	}]);

};

config.macros.ccEditWorkspace.ewSubmit = function(place, macroName, params2, wikifier, paramString, tiddler,w, booAnon, booUser){
	var trueStr = "A";
	var falseStr = "U";
	var anon = '';
	var user = '';
	if(booAnon){
		var anonBuffer = new Array();
		anonBuffer.push(w.formElem['anR'].checked ? trueStr : falseStr);
		anonBuffer.push(w.formElem['anC'].checked ? trueStr : falseStr);
		anonBuffer.push(w.formElem['anU'].checked ? trueStr : falseStr);
		anonBuffer.push(w.formElem['anD'].checked ? trueStr : falseStr);
		anon = anonBuffer.join('');
	}
	if(booUser){
		var userBuffer = new Array();
		userBuffer.push(w.formElem['usR'].checked ? trueStr : falseStr);
		userBuffer.push(w.formElem['usC'].checked ? trueStr : falseStr);
		userBuffer.push(w.formElem['usU'].checked ? trueStr : falseStr);
		userBuffer.push(w.formElem['usD'].checked ? trueStr : falseStr);
		user = userBuffer.join('');
	}
	var params = new Array();
	params.w = w;
	params.u = user;
	params.a = anon;
	params.p = place;
	params.m =  macroName;
	params.pr = params2;
	params.wi = wikifier;
	params.ps = paramString;
	params.t = tiddler;
	doHttp('POST', url + '/handle/updateWorkspace.php', 'ccCreateWorkspace=' + encodeURIComponent(workspace) + '&ccAnonPerm=' + encodeURIComponent(anon) + '&ccUserPerm=' + encodeURIComponent(user), null, null, null, config.macros.ccEditWorkspace.editWorkspaceCallback, params);
	return false;
}
config.macros.ccEditWorkspace.editWorkspaceCallback = function(status,params,responseText,uri,xhr){
	var w = params.w;
	var me = config.macros.ccEditWorkspace;
	if(xhr.status == 200){
		// use the incoming parameters to set the workspace permission variables.
		if (params.a != ''){
			workspacePermission.anonR = (params.a.substr(0,1)=='A'?1:0);
			workspacePermission.anonC = (params.a.substr(1,1)=='A'?1:0);
			workspacePermission.anonU = (params.a.substr(2,1)=='A'?1:0);
			workspacePermission.anonD = (params.a.substr(3,1)=='A'?1:0);
		}
		if (params.u != ''){
			workspacePermission.userR = (params.u.substr(0,1)=='A'?1:0);
			workspacePermission.userC = (params.u.substr(1,1)=='A'?1:0);
			workspacePermission.userU = (params.u.substr(2,1)=='A'?1:0);
			workspacePermission.userD = (params.u.substr(3,1)=='A'?1:0);
		}
		w.addStep('',responseText);
		// want to set a back button here
		w.setButtons([
			{caption: me.button1SubmitCaption, tooltip: me.button1SubmitToolTip, onClick: function() {config.macros.ccEditWorkspace.refresh(params.p,	params.m,	params.pr,	params.wi,	params.ps,	params.t);}}
		]);
	}else{
		w.addStep(me.step2Error+': ' + xhr.status,config.macros.ccEditWorkspace.errorUpdateFailed);
	}
	return false;
};
config.macros.ccEditWorkspace.refresh = function(place, macroName, params, wikifier, paramString, tiddler){
	removeChildren(place);
	config.macros.ccEditWorkspace.handler(place, macroName, params, wikifier, paramString, tiddler);
}
//}}}

// ccFile //


//{{{
	
config.macros.ccFile = {};
var iFrameLoad=function(w){
	var uploadIframe = document.getElementById('uploadIframe');
	var a = createTiddlyElement(null, "div");
	a.innerHTML = uploadIframe.contentDocument.body.innerHTML;
	removeChildren(w.formElem.placeholder);
	w.formElem.placeholder.parentNode.appendChild(a);
	var statusArea = w.formElem.placeholder;
	document.getElementById("ccfile").value=""; 
};

config.macros.ccFile.handler=function(place,macroName,params,wikifier,paramString,tiddler, errorMsg){
	var w = new Wizard();
	w.createWizard(place,config.macros.ccFile.wizardTitleText);
	config.macros.ccFile.refresh(w);
};

config.macros.ccFile.refresh=function(w){
	params = {};
	params.w = w;
	params.e = this;
	var me = config.macros.ccFile;
	doHttp('GET',url+'/handle/listFiles.php?workspace='+workspace,'',null,null,null,config.macros.ccFile.listAllCallback,params);
	w.setButtons([
		{caption: me.buttonDeleteText, tooltip: me.buttonDeleteTooltip, onClick: function(w){ 
			config.macros.ccFile.delFileSubmit(null, params);
			 return false;
		}}, 
		{caption: me.buttonUploadText, tooltip: me.buttonUploadTooltip, onClick: function(e){ 
			config.macros.ccFile.addFileDisplay(null, params); return false 
			} }
	]);
};

config.macros.ccFile.delFileSubmit=function(e, params) {
	var listView = params.w.getValue("listView");
	var rowNames = ListView.getSelectedRows(listView);
	for(var e=0; e < rowNames.length; e++) 
	doHttp('POST',url+'/handle/listFiles.php','action=DELETEFILE&file='+rowNames[e]+'&workspace='+workspace,null,null,null,config.macros.ccFile.delFileCallback,params);
	return false; 
};

config.macros.ccFile.delFileCallback=function(status,params,responseText,uri,xhr){
	config.macros.ccFile.refresh(params.w);
};

config.macros.ccFile.addFileDisplay = function(e, params){
	var frm = params.w.formElem;
	if(navigator.appName=="Microsoft Internet Explorer"){
		encType = frm.getAttributeNode("enctype");
	    encType.value = "multipart/form-data";
	}
	frm.setAttribute("enctype","multipart/form-data");
	frm.setAttribute("method","POST");
	frm.action=window.url+"/handle/upload.php"; 
	frm.id="ccUpload";
	frm.target="uploadIframe";
	frm.name = "uploadForm";
	frm.parentNode.appendChild(frm);
	params.w.addStep("ss", "<input id='ccfile' class='input' type='file' name='userFile'/>"+"<input type='hidden' name='placeholder'/>");
	var workspaceName=createTiddlyElement(null,'input','workspaceName','workspaceName');				
	workspaceName .setAttribute('name','workspace');
	workspaceName.type="HIDDEN";
	workspaceName.value=workspace;
	frm.appendChild(workspaceName);
	createTiddlyElement(frm,'br');
	var saveTo=createTiddlyElement(null,"input","saveTo","saveTo");	
	var iframe=document.createElement("iframe");
	iframe.style.display="none";
	iframe.id='uploadIframe';
	iframe.name='uploadIframe';
	iframe.onload = function() {
		iFrameLoad(params.w);
	}	
	frm.appendChild(iframe);
	createTiddlyElement(frm,"div",'uploadStatus');
	params.w.setButtons([
	{caption: config.macros.ccFile.buttonCancelText, tooltip: config.macros.ccFile.buttonCancelTooltip, onClick: function(){config.macros.ccFile.refresh(params.w);}
	},
	{caption: config.macros.ccFile.buttonUploadText, tooltip: config.macros.ccFile.buttonUploadTooltip, onClick: function(){params.w.formElem.submit();}
	}]);
};

function addOption(selectbox,text,value ){
	var optn = document.createElement("OPTION");
	optn.text = text;
	optn.value = value;
	selectbox.options.add(optn);
}

config.macros.ccFileImageBox = function(image){
	var full = image.src;
	setStylesheet(
	"#errorBox .button {padding:0.5em 1em; border:1px solid #222; background-color:#ccc; color:black; margin-right:1em;}\n"+
	"html > body > #backstageCloak {height:"+window.innerHeight*2+"px;}"+
	"#errorBox {border:1px solid #ccc;background-color: #fff; color:#111;padding:1em 2em; z-index:9999;}",'errorBoxStyles');
	var box = document.getElementById('errorBox') || createTiddlyElement(document.body,'div','errorBox');
	box.innerHTML =  "<a style='float:right' href='javascript:onclick=ccTiddlyAdaptor.hideError()'>"+ccTiddlyAdaptor.errorClose+"</a><h3>"+image.src+"</h3><br />";
	box.style.position = 'absolute';
	box.style.width= "800px";
	var img = createTiddlyElement(box, "img");
	img.src = full;
	ccTiddlyAdaptor.center(box);
	ccTiddlyAdaptor.showCloak();
}

config.macros.ccFile.listAllCallback = function(status,params,responseText,uri,xhr){
	var me = config.macros.ccFile;
	var out = "";
	var adminUsers = [];
	if(xhr.status!=200){
		params.w.addStep(me.errorPermissionDeniedTitle, me.errorPermissionDeniedView);
		return true;
	}
	try{
		var a = eval(responseText);
		for(var e=0; e < a.length; e++){ 		
		out += a[e].username;	
			adminUsers.push({
				htmlName: "<html><a href='"+a[e].url+"' target='new'>"+a[e].filename+"</a></html>",
				name: a[e].filename,
				wikiText:'<html><img onclick="config.macros.ccFileImageBox(this)"; src="'+a[e].url+'" style="width: 70px; "/></html>',
				URI:a[e].url,
				lastVisit:a[e].lastVisit,
				fileSize:a[e].fileSize
			});
		}
	}catch (ex){
		params.w.setButtons([
			{caption: me.buttonUploadText, tooltip: me.buttonUploadTooltip, onClick: function(w){				
				config.macros.ccFile.addFileDisplay(e, params);
			} }]);
	}
	params.w.addStep(me.wizardStepText+workspace, "<input type='hidden' name='markList'></input>");
	var markList = params.w.getElement("markList");
	var listWrapper = document.createElement("div");
	markList.parentNode.insertBefore(listWrapper,markList);
	var listView = ListView.create(listWrapper,adminUsers,config.macros.ccFile.listAdminTemplate);
	//params.w.setValue("listAdminView",listAdminView);
	params.w.setValue("listView",listView);
};

config.macros.ccFile.addFileCallback = function(status,params,responseText,uri,xhr){	
	config.macros.ccFile.refresh(params.w);
};

//}}}
// ccLogin //

//{{{

config.macros.ccLogin={sha1:true};
	
function isLoggedIn() {
	if(window.loggedIn)
	 	return true;
	else 
		return false;
}

config.macros.saveChanges.handler=function(place,macroName,params,wikifier,paramString,tiddler){
	if(isLoggedIn()){
		createTiddlyButton(place, config.macros.ccLogin.buttonLogout, config.macros.ccLogin.buttonLogoutToolTip, function(){
				if (window.fullUrl.indexOf("?") >0)
					window.location = window.fullUrl+"&logout=1";
				else
					window.location = window.fullUrl+"?logout=1";
			return false;
		},null,null,this.accessKey);
	}else{
		createTiddlyButton(place,config.macros.ccLogin.buttonlogin, config.macros.ccLogin.buttonLoginToolTip, function() {
			story.displayTiddler(null, "Login");
		},null,null,this.accessKey);
	}
};

var loginState=null;
var registerState=null;

config.macros.ccLogin.handler=function(place,macroName,params,wikifier,paramString,tiddler){
	var params = paramString.parseParams('reload',null,true);
	config.macros.ccLogin.refresh(place, params[0].reload);
};
 
config.macros.ccLogin.refresh=function(place, reload, error){
	removeChildren(place);
	var w = new Wizard();
	if (isLoggedIn()){
		w.createWizard(place,this.stepLogoutTitle);
		w.addStep(null, this.stepLogoutText+decodeURIComponent(cookieString(document.cookie).txtUserName)+"<br /><br />");
		w.setButtons([
			{caption: this.buttonLogout, tooltip: this.buttonLogoutToolTip, onClick: function() {window.location=fullUrl+"?&logout=1"}
		}]);
		return true;
	}
	w.createWizard(place,this.WizardTitleText);
	w.setValue('reload', reload);


	var me=config.macros.ccLogin;
	var oldForm = w.formElem.innerHTML;
	var form = w.formElem;
	if (error!==undefined)
		this.stepLoginTitle=error;	
	w.addStep(this.stepLoginTitle,me.stepLoginIntroTextHtml);
	txtPassword = w.formElem.txtPassword;
	w.formElem.password.style.display="none";
	txtPassword.onkeyup = function() {
		if(me.sha1 == true){
			w.formElem.password.value = Crypto.hexSha1Str(w.formElem.txtPassword.value);
		} else { 
			w.formElem.password.value = w.formElem.txtPassword.value;
		}
	};
	txtPassword.onchange = txtPassword.onkeyup;
	w.formElem.method ="POST";
	w.formElem.onsubmit = function() {config.macros.ccLogin.doLogin(w.formElem["username"].value, w.formElem["password"].value, this, place); return false;};
	var submit = createTiddlyElement(null, "input");
	submit.type="submit";
	submit.style.display="none";
	w.formElem.appendChild(submit);
	var cookieValues=findToken(document.cookie);
	if (cookieValues.txtUserName!==undefined){
		w.formElem["username"].value=decodeURIComponent(cookieValues.txtUserName) ;
	}
	var footer = findRelated(form,"wizardFooter","className");
	createTiddlyButton(w.footer,this.buttonLogin,this.buttonLoginToolTip,function() {
		if (w.formElem["username"].value==""){
			displayMessage(me.msgNoUsername);
			return false;
		}
		if (w.formElem["password"].value==""){
			displayMessage(me.msgNoPassword);
			return false;
		}
		config.macros.ccLogin.doLogin(w.formElem["username"].value, w.formElem["password"].value, this, place);
	});
	
	
	createTiddlyButton(w.footElem,this.buttonLogin,this.buttonLoginToolTip,function() {
		config.macros.ccLogin.doLogin(w.formElem["username"].value, w.formElem["password"].value, this, place);
	},null, null, null,  {tabindex:'3'});

	if(config.macros.register!==undefined){		
		var li_register = createTiddlyElement(w.footElem, "li");
		createTiddlyButton(li_register,config.macros.register.buttonRegister,config.macros.register.buttonRegisterToolTip,function() {
				config.macros.register.displayRegister(place, w, this);
		},"nobox", null, null,  {tabindex:4});
	}
	var li_forgotten = createTiddlyElement(w.footElem, "li");
	createTiddlyButton(li_forgotten,this.buttonForgottenPassword,this.buttonForgottenPasswordToolTip,function() {
		config.macros.ccLogin.displayForgottenPassword(this, place);
	},"nobox", null, null,  {tabindex:5});

};

config.macros.ccLogin.doLogin=function(username, password, item, place){
	var w = new Wizard(item);
	var me = config.macros.ccLogin;
	var userParams = {};
	userParams.place = place;
	var adaptor = new config.adaptors[config.defaultCustomFields['server.type']];
	var context = {};
	context.reload = w.getValue("reload");
	context.host = window.url;
	context.username = username;
	context.password = password;
	adaptor.login(context,userParams,config.macros.ccLogin.loginCallback)
	var html = me.stepDoLoginIntroText; 
	w.addStep(me.stepDoLoginTitle,html);
	w.setButtons([
		{caption: this.buttonCancel, tooltip: this.buttonCancelToolTip, onClick: function() {config.macros.ccLogin.refresh(place);}
	}]);
}

config.macros.ccLogin.loginCallback=function(context,userParams){

	if(!context.status)
	{
		config.macros.ccLogin.refresh(userParams.place, config.macros.ccLogin.msgLoginFailed);
	}else{
		if(context.reload=="false"){
				window.loggedIn = true;
				var $ = jQuery;
				story.refreshTiddler(story.findContainingTiddler(userParams.place).id.replace("tiddler", ""), null, true);			
		}else{
							window.location.reload();	
		}
	}	 
};

config.macros.ccLogin.displayForgottenPassword=function(item, place){	
	var w = new Wizard(item);
	var me = config.macros.ccLogin;
	w.addStep(me.stepForgotPasswordTitle,me.stepForgotPasswordIntroText);
	w.setButtons([
		{caption: this.buttonCancel, tooltip: this.buttonCancelToolTip, onClick: function() {me.refresh(place);}}
	]);
};

//config.macros.ccLogin.sendForgottenPassword=function(item, place){	
//	var w = new Wizard(item);
//	var me = config.macros.ccLogin;
//}

config.macros.toolbar.isCommandEnabled=function(command,tiddler){	
	var title=tiddler.title;
	if (workspace_delete=="D"){
		// REMOVE OPTION TO DELETE TIDDLERS 
		if (command.text=='delete')
			return false;
	}
	if (workspace_udate=="D"){
		// REMOVE EDIT LINK FROM TIDDLERS 
		if (command.text=='edit')
			return false;
	}
	var ro=tiddler.isReadOnly();
	var shadow=store.isShadowTiddler(title) && !store.tiddlerExists(title);
	return (!ro || (ro && !command.hideReadOnly)) && !(shadow && command.hideShadow);
};

// Returns output var with output.txtUsername and output.sessionToken
function findToken(cookieStash){
	var output={};
	if (!cookieStash)
		return false;	
	//  THIS IS VERY HACKY AND SHOULD BE REFACTORED WHEN TESTS ARE IN PLACE
	var cookies=cookieStash.split('path=/');
	for(var c=0; c < cookies.length ; c++){
		var cl =cookies[c].split(";");
		for(var e=0; e < cl.length; e++){ 
			var p=cl[e].indexOf("=");
			if(p!=-1){
				var name=cl[e].substr(0,p).trim();
				var value=cl[e].substr(p+1).trim();       
				if (name=='txtUserName'){
					output.txtUserName=value;
				}
				if (name=='sessionToken'){
					output.sessionToken=value;
				}
			}
		}
	}	
	return output;
};

function cookieString(str){	
	var cookies = str.split(";");
	var output = {};
	for(var c=0; c < cookies.length; c++){
		var p = cookies[c].indexOf("=");
		if(p != -1) {
			var name = cookies[c].substr(0,p).trim();
			var value = cookies[c].substr(p+1).trim();
			if (name=='txtUserName'){
				output.txtUserName=value;
			}
			if (name=='sessionToken'){
				output.sessionToken=value;
			}
		}
	}
	return output;
}


//}}}
// ccLoginStatus //

//{{{


config.macros.ccLoginStatus={};
	
config.macros.ccLoginStatus.handler=function(place,macroName,params,wikifier,paramString,tiddler){
	var loginDiv=createTiddlyElement(place,"div",null,"loginDiv",null);
	this.refresh(loginDiv);
};
	
config.macros.ccLoginStatus.refresh=function(place,errorMsg){
       var me = config.macros.ccLoginStatus;
       var loginDivRef=document.getElementById ("LoginDiv");
       removeChildren(loginDivRef);
       var wrapper=createTiddlyElement(place,"div");
       var str = (workspace == "" ? me.textDefaultWorkspaceLoggedIn :(me.textViewingWorkspace+workspace))+"\r\n\r\n";
       if (isLoggedIn()){
			name = cookieString(document.cookie).txtUserName;
			str += me.textLoggedInAs+decodeURIComponent(name)+".\r\n\r\n";
			if (workspacePermission.owner==1){
				str += me.textAdmin;
			}
       }else{
               str += me.textNotLoggedIn;
       }
       wikify(str,wrapper);
};
//}}}

// ccOptions //
//{{{
config.macros.ccOptions={};		
config.macros.ccOptions.handler=function(place,macroName,params,wikifier,paramString,tiddler){
	var me = config.macros.ccOptions;
	if(workspacePermission.owner==1)
		wikify("[["+me.linkManageUsers+"|Manage Users]]<br />[["+me.linkPermissions+"|Permissions]]<br />[["+me.linkStats+"|Statistics]]<br />", place);
	if (isLoggedIn())
		wikify("[["+me.linkFiles+"|files]]<br />", place);
		if (isLoggedIn()){
			if (workspacePermission.canCreateWorkspace==1)
				wikify("[["+me.linkCreate+"|CreateWorkspace]]<br />", place);
			// append url function required 
			wikify("[["+me.linkPassword+"|Password]]<br />", place);
			if (window.fullUrl.indexOf("?") >0)
				wikify("[["+me.linkOffline+"|"+fullUrl+"&standalone=1]]<br />", place);
			else 
				wikify("[["+me.linkOffline+"|"+fullUrl+"?standalone=1]]<br />", place);	
		}
};

//}}}
// ccRegister //

//{{{
config.macros.register={};	
	
config.macros.register.handler=function(place,macroName,params,wikifier,paramString,tiddler){
	//config.macros.login.refresh(place);
};

config.macros.register.displayRegister=function(place, w, item){
	var me = config.macros.register;
	var w = new Wizard(item);
	w.addStep(me.stepRegisterTitle, me.stepRegisterHtml);
	w.formElem["reg_username"].onkeyup=function() {me.isUsernameAvailable(w);};
	w.setButtons([
		{caption: me.buttonRegister, tooltip: me.buttonRegisterToolTip, onClick:function() { me.doRegister(place, w)}},
		{caption: me.buttonCancel, tooltip: me.buttonCancelToolTip, onClick: function() { config.macros.ccLogin.refresh(place)}}
	]);
	var h1 = createTiddlyElement(null, "h1", null, null, "hahahaha");
	//	w.footElem.appendChild(h1, w.footElem);
	w.footElem.firstChild.parentNode.appendChild(h1, w.footElem);
	//w.footElem.firstChild.insertBefore(h1, w.footElem);
}

config.macros.register.setStatus=function(w, element, text){
	var label_var = w.getElement(element);
	removeChildren(label_var.previousSibling);
	var label = document.createTextNode(text);
	label_var.previousSibling.insertBefore(label,null);
}

config.macros.register.doRegister=function(place, w){
	var me = config.macros.register;
	if(w.formElem["reg_username"].value==''){
		me.setStatus(w, "username_error", me.msgNoUsername);
	}else {
		me.setStatus(w, "username_error", "");
	}
	if(me.emailValid(w.formElem["reg_mail"].value)){
		me.setStatus(w, "mail_error", me.msgEmailOk);
	}else{
		me.setStatus(w, "mail_error", "invalid email address");
		return false;
	}
	if(w.formElem["reg_password1"].value==''){
		me.setStatus(w, "pass1_error", me.msgNoPassword);
		return false;
	}else{
		me.setStatus(w, "pass1_error", "");
	}
	if(w.formElem["reg_password2"].value==''){
		me.setStatus(w, "pass2_error", me.msgNoPassword);
		return false;
	}
	if(w.formElem["reg_password1"].value != w.formElem["reg_password2"].value ){
		me.setStatus(w, "pass1_error", me.msgDifferentPasswords);
		me.setStatus(w, "pass2_error", me.msgDifferentPasswords);
		return false;
	}
 	var params ={};
	params.p = Crypto.hexSha1Str(w.formElem['reg_password1'].value);
	params.u = w.formElem['reg_username'].value;
	params.place = place;
	params.w = w;
	var loginResp=doHttp('POST',url+'/handle/register.php',"username="+w.formElem['reg_username'].value+"&reg_mail="+w.formElem['reg_mail'].value+"&password="+Crypto.hexSha1Str(w.formElem['reg_password1'].value)+"&password2="+Crypto.hexSha1Str(w.formElem['reg_password2'].value),null,null,null,config.macros.register.registerCallback,params);
	w.addStep(me.step2Title, me.msgCreatingAccount);
	w.setButtons([
		{caption: me.buttonCancel, tooltip: me.buttonCancelToolTip, onClick: function() {config.macros.ccLogin.refresh(place);}
	}]);
}

config.macros.register.emailValid=function(str){
	if((str.indexOf(".") > 0) && (str.indexOf("@") > 0))
		return true;
	else
		return false;
};

config.macros.register.usernameValid=function(str){
	if((str.indexOf("_") > 0) && (str.indexOf("@") > 0))
		return false;
	else
		return true;
};

config.macros.register.registerCallback=function(status,params,responseText,uri,xhr){
	var userParams = {};
	userParams.place = params.place;
	if (xhr.status==304){
		params.w.addStep(config.macros.register.errorRegisterTitle, config.macros.register.errorRegister);
		return false;
	}	
	var adaptor = new config.adaptors[config.defaultCustomFields['server.type']];
	var context = {};
	context.host = window.url;
	context.username = params.u;
	context.password = params.p;
	adaptor.login(context,userParams,config.macros.ccLogin.loginCallback);
	return true;
}

config.macros.register.isUsernameAvailable=function(w){
	var params = {};
	params.w = w;
	doHttp('POST',url+'/handle/register.php',"username="+w.formElem["reg_username"].value+"&free=1",null,null,null,config.macros.register.isUsernameAvailabeCallback,params);
	return false;
};

config.macros.register.isUsernameAvailabeCallback=function(status,params,responseText,uri,xhr){
	var me = config.macros.register;
	var resp = (responseText > 0) ? me.msgUsernameTaken : me.msgUsernameAvailable;
	config.macros.register.setStatus(params.w, "username_error", resp);
};
//}}}

// ccStats //

//{{{
	
config.macros.ccStats={};	
	
config.macros.ccStats.handler = function(place,macroName,params,wikifier,paramString,tiddler){
	var params;
	params.place = place;
	doHttp('POST',url+'/handle/workspaceAdmin.php','action=LISTWORKSPACES',null,null,null,config.macros.ccStats.listWorkspaces,params);
}

config.macros.ccStats.simpleEncode = function(valueArray,maxValue){
	var simpleEncoding = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
	var chartData = ['s:'];
	  for (var i = 0; i < valueArray.length; i++){
	    var currentValue = valueArray[i];
	    if (!isNaN(currentValue) && currentValue >= 0){
	    	chartData.push(simpleEncoding.charAt(Math.round((simpleEncoding.length-1) * currentValue / maxValue)));
	    }else{
	      chartData.push('_');
	    }
	  }
	return chartData.join('');
}

config.macros.ccStats.max = function(array){
	return Math.max.apply(Math, array);
}

config.macros.ccStats.dataCallback = function(status,params,responseText,uri,xhr){
	me = config.macros.ccStats;
	if(xhr.status==401){
		createTiddlyElement(params.container, "h4", null, null, me.errorPermissionDenied.format([params.title], [workspace]));
		return false;
	}
	var res = eval("[" + responseText + "]");
	var d=[];
	var l="";
	for(var c=0; c<res.length; c++){
		d[c]= res[c].hits;
		l+=res[c].date+"|";
	}
	var maxValue = config.macros.ccStats.max(d);
 	params.gData = config.macros.ccStats.simpleEncode(d,maxValue);
	params.XLabel = l.substring(0, l.length -1);
	params.YLabel = "0|"+maxValue+"|";
	var image = 'http://chart.apis.google.com/chart?cht=lc&chs=100x75&chd='+params.gData+'&chxt=x,y&chxl=0:||1:|';
	var div = createTiddlyElement(params.container, "div", null, "div_button");
	setStylesheet(".div_button:hover{opacity:0.7; cursor: pointer} .div_button{ width:100%; padding:5px;color:#555;background-color:white;} ", "DivButton");
	div.onclick = function(){
		var full = "http://chart.apis.google.com/chart?cht=lc&chs=800x375&chd="+params.gData+"&chxt=x,y&chxl=1:|"+params.YLabel+"0:|"+params.XLabel+"&chf=c,lg,90,EEEEEE,0.5,ffffff,20|bg,s,FFFFFF&&chg=10.0,10.0&";
		setStylesheet(
		"#errorBox .button{padding:0.5em 1em; border:1px solid #222; background-color:#ccc; color:black; margin-right:1em;}\n"+
		"html > body > #backstageCloak{height:"+window.innerHeight*2+"px;}"+
		"#errorBox{border:1px solid #ccc;background-color: #fff; color:#111;padding:1em 2em; z-index:9999;}",'errorBoxStyles');
		var box = document.getElementById('errorBox') || createTiddlyElement(document.body,'div','errorBox');
		box.innerHTML =  "<a style='float:right' href='javascript:onclick=ccTiddlyAdaptor.hideError()'>"+ccTiddlyAdaptor.errorClose+"</a><h3>"+params.title+"</h3><br />";
		box.style.position = 'absolute';
		box.style.height= "460px";
		box.style.width= "800px";
		var img = createTiddlyElement(box, "img");
		img.src = full;
		ccTiddlyAdaptor.center(box);
		ccTiddlyAdaptor.showCloak();
	}
	var img = createTiddlyElement(div, "h2", null, null, params.title);
	var img = createTiddlyElement(div, "img");
	img.src = image;
	var span = createTiddlyElement(div, "div", null, "graph_label", params.desc);
	setStylesheet(".graph_label{  position:relative; width:300px; top:-80px; left:130px;}");
}

config.macros.ccStats.switchWorkspace = function(params){
	removeChildren(params.container);
	config.macros.ccStats.refresh(params);	
}

config.macros.ccStats.refresh = function(params){
	var me = config.macros.ccStats;
	var select = params.w.formElem.workspaces;
	if(select[select.selectedIndex].value!="")
		workspace = select[select.selectedIndex].value;
	params ={ container: params.container, url: window.url+"/handle/stats.php?graph=minute&workspace="+workspace,title:me.graph20MinsTitle, desc:me.graph20MinsDesc};
	doHttp('GET',params.url,null, null, null, null, config.macros.ccStats.dataCallback,params);
	params ={ container:params.container, url:  window.url+"/handle/stats.php?graph=hour&workspace="+workspace,title:me.graph24HourTitle, desc:me.graph24HourDesc};
	doHttp('GET',params.url,null, null, null, null, config.macros.ccStats.dataCallback,params);
	params ={ container: params.container, url:  window.url+"/handle/stats.php?graph=day&workspace="+workspace,title:me.graph7DaysTitle, desc:me.graph7DaysDesc};
	doHttp('GET',params.url,null, null, null, null, config.macros.ccStats.dataCallback,params);
	params ={ container: params.container, url:  window.url+"/handle/stats.php?graph=month&workspace="+workspace,title:me.graph5MonthsTitle, desc:me.graph5MonthsDesc};
	doHttp('GET',params.url,null, null, null, null, config.macros.ccStats.dataCallback,params);	
}

config.macros.ccStats.listWorkspaces = function(status,params,responseText,uri,xhr){
	params.container=createTiddlyElement(null, "div", "container");
	var me = config.macros.ccStats;
	var w = new Wizard();
	w.createWizard(params.place,me.stepTitle);
	w.addStep(null, "<select name='workspaces'></select><input name='stats_hol' type='hidden'></input>");
	var s = w.formElem.workspaces;	
	s.onchange = function(){config.macros.ccStats.switchWorkspace(params) ;};
	var workspaces = eval('[ '+responseText+' ]');
	for(var d=0; d < workspaces.length; d++){
		var i = createTiddlyElement(s,"option",null,null,workspaces[d]);
		i.value = workspaces[d];
		if (workspace == workspaces[d]){
			i.selected = true;
		}
	}
	params.w = w; 
	w.formElem.stats_hol.parentNode.appendChild(params.container);
	config.macros.ccStats.refresh(params);
}
//}}}





config.backstageTasks.push("about");
merge(config.tasks,{about:{text: config.macros.ccAbout.buttonBackstageText,tooltip: config.macros.ccAbout.buttonBackstageTooltip,content: '<<ccAbout>>'}});

if (isLoggedIn()){
	config.backstageTasks.push("logout");
	merge(config.tasks,{logout:{text: config.macros.ccLogin.buttonLogout,tooltip: config.macros.ccLogin.buttonLogoutToolTip,content: '<<ccLogin>>'}});

//	config.backstageTasks.push("create");
//	merge(config.tasks,{create: {text: config.macros.ccCreateWorkspace.buttonCreateText, tooltip: config.macros.ccCreateWorkspace.buttonCreateTooltip, content:'<<ccCreateWorkspace>>'}});

}else{
	config.backstageTasks.push("login");
	merge(config.tasks,{login:{text: config.macros.ccLogin.buttonlogin,tooltip: config.macros.ccLogin.buttonLoginToolTip,content: '\r\n\r\n<<tiddler Login>>'}});	
}

// Allows users to change the default tiddlers for anonymous users by setting the AnonDefaultTiddlers tiddler.

// also requires overide of restart. 

Story.prototype.displayDefaultTiddlers = function(){
 	var tiddlers="";
	if(isLoggedIn()){        
		var url = window.location;        
		url = url.toString();        
		var bits = url.split('#');        
		if(bits.length == 1){            
			tiddlers = store.filterTiddlers(store.getTiddlerText("DefaultTiddlers"));            
			story.displayTiddlers(null, tiddlers);
		}
	}else{         
		tiddlers=store.filterTiddlers(store.getTiddlerText("AnonDefaultTiddlers"));        
		story.displayTiddlers(null, tiddlers);   
	}    
};

// Import Override - ensures imported tiddlers have cctiddly server type. 
config.macros.importTiddlers.onGetTiddler = function(context,wizard)
{
	
	if(!context.status)
		displayMessage("Error in importTiddlers.onGetTiddler: " + context.statusText);
	var tiddler = context.tiddler;
	if(store.tiddlerExists(tiddler.title)) {
		var t = store.getTiddler(tiddler.title);
		tiddler.fields = t.fields;
	}
	store.suspendNotifications();
	tiddler.fields['server.type'] = 'cctiddly';
	tiddler.fields['server.host'] = window.url;
	tiddler.fields['workspace']= window.workspace;
	store.saveTiddler(tiddler.title, tiddler.title, tiddler.text, tiddler.modifier, tiddler.modified, tiddler.tags, tiddler.fields, false, tiddler.created);// local 
//	config.extensions.ServerSideSavingPlugin.saveTiddler(tiddler); // remote save. 
	if(!wizard.getValue("sync")) {
		store.setValue(tiddler.title,'server',null);
	}
	store.resumeNotifications();
	if(!context.isSynchronous)
		store.notify(tiddler.title,true);
	var remainingImports = wizard.getValue("remainingImports")-1;
	wizard.setValue("remainingImports",remainingImports);
	if(remainingImports == 0) {
		if(context.isSynchronous) {
			store.notifyAll();
			refreshDisplay();
		}
		wizard.setButtons([
				{caption: config.macros.importTiddlers.doneLabel, tooltip: config.macros.importTiddlers.donePrompt, onClick: config.macros.importTiddlers.onClose}
			],config.macros.importTiddlers.statusDoneImport);
		autoSaveChanges();
	}
};
/*
// Displays the default tiddlers alongside the login box when users are not logged in.
window.restart = function(){
	story.displayDefaultTiddlers();
	invokeParamifier(params,"onstart");
	window.scrollTo(0,0); 
	});
};
*/
/*!
 * jQuery JavaScript Library v1.4a1
 * http://jquery.com/
 *
 * Copyright (c) 2009 John Resig
 * Dual licensed under the MIT and GPL licenses.
 * http://docs.jquery.com/License
 *
 * Date: Fri Dec 4 12:51:47 2009 -0500
 */
(function(window, undefined){

// Define a local copy of jQuery
var jQuery = function( selector, context ) {
		// The jQuery object is actually just the init constructor 'enhanced'
		return arguments.length === 0 ?
			rootjQuery :
			new jQuery.fn.init( selector, context );
	},

	// Map over jQuery in case of overwrite
	_jQuery = window.jQuery,

	// Map over the $ in case of overwrite
	_$ = window.$,

	// Use the correct document accordingly with window argument (sandbox)
	document = window.document,

	// A central reference to the root jQuery(document)
	rootjQuery,

	// A simple way to check for HTML strings or ID strings
	// (both of which we optimize for)
	quickExpr = /^[^<]*(<[\w\W]+>)[^>]*$|^#([\w-]+)$/,

	// Is it a simple selector
	isSimple = /^.[^:#\[\.,]*$/,

	// Check if a string has a non-whitespace character in it
	rnotwhite = /\S/,

	// Used for trimming whitespace
	rtrim = /(\s|\u00A0)+|(\s|\u00A0)+$/g,

	// Match a standalone tag
	rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>)?$/,

	// Keep a UserAgent string for use with jQuery.browser
	userAgent = navigator.userAgent.toLowerCase(),

	// Save a reference to some core methods
	toString = Object.prototype.toString,
	hasOwnProperty = Object.prototype.hasOwnProperty,
	push = Array.prototype.push,
	slice = Array.prototype.slice,
	indexOf = Array.prototype.indexOf;

jQuery.fn = jQuery.prototype = {
	init: function( selector, context ) {
		var match, elem, ret, doc;

		// Handle $(""), $(null), or $(undefined)
		if ( !selector ) {
			return this;
		}

		// Handle $(DOMElement)
		if ( selector.nodeType ) {
			this.context = this[0] = selector;
			this.length = 1;
			return this;
		}

		// Handle HTML strings
		if ( typeof selector === "string" ) {
			// Are we dealing with HTML string or an ID?
			match = quickExpr.exec( selector );

			// Verify a match, and that no context was specified for #id
			if ( match && (match[1] || !context) ) {

				// HANDLE: $(html) -> $(array)
				if ( match[1] ) {
					doc = (context ? context.ownerDocument || context : document);

					// If a single string is passed in and it's a single tag
					// just do a createElement and skip the rest
					ret = rsingleTag.exec( selector );

					if ( ret ) {
						selector = [ doc.createElement( ret[1] ) ];

					} else {
						ret = buildFragment( [ match[1] ], [ doc ] );
						selector = (ret.cacheable ? ret.fragment.cloneNode(true) : ret.fragment).childNodes;
					}

				// HANDLE: $("#id")
				} else {
					elem = document.getElementById( match[2] );

					if ( elem ) {
						// Handle the case where IE and Opera return items
						// by name instead of ID
						if ( elem.id !== match[2] ) {
							return rootjQuery.find( selector );
						}

						// Otherwise, we inject the element directly into the jQuery object
						this.length = 1;
						this[0] = elem;
					}

					this.context = document;
					this.selector = selector;
					return this;
				}

			// HANDLE: $("TAG")
			} else if ( !context && /^\w+$/.test( selector ) ) {
				this.selector = selector;
				this.context = document;
				selector = document.getElementsByTagName( selector );

			// HANDLE: $(expr, $(...))
			} else if ( !context || context.jquery ) {
				return (context || rootjQuery).find( selector );

			// HANDLE: $(expr, context)
			// (which is just equivalent to: $(context).find(expr)
			} else {
				return jQuery( context ).find( selector );
			}

		// HANDLE: $(function)
		// Shortcut for document ready
		} else if ( jQuery.isFunction( selector ) ) {
			return rootjQuery.ready( selector );
		}

		if (selector.selector !== undefined) {
			this.selector = selector.selector;
			this.context = selector.context;
		}

		return jQuery.isArray( selector ) ?
			this.setArray( selector ) :
			jQuery.makeArray( selector, this );
	},

	// Start with an empty selector
	selector: "",

	// The current version of jQuery being used
	jquery: "1.4a1",

	// The default length of a jQuery object is 0
	length: 0,

	// The number of elements contained in the matched element set
	size: function() {
		return this.length;
	},

	toArray: function(){
		return slice.call( this, 0 );
	},

	// Get the Nth element in the matched element set OR
	// Get the whole matched element set as a clean array
	get: function( num ) {
		return num == null ?

			// Return a 'clean' array
			this.toArray() :

			// Return just the object
			( num < 0 ? this.slice(num)[ 0 ] : this[ num ] );
	},

	// Take an array of elements and push it onto the stack
	// (returning the new matched element set)
	pushStack: function( elems, name, selector ) {
		// Build a new jQuery matched element set
		var ret = jQuery( elems || null );

		// Add the old object onto the stack (as a reference)
		ret.prevObject = this;

		ret.context = this.context;

		if ( name === "find" ) {
			ret.selector = this.selector + (this.selector ? " " : "") + selector;
		} else if ( name ) {
			ret.selector = this.selector + "." + name + "(" + selector + ")";
		}

		// Return the newly-formed element set
		return ret;
	},

	// Force the current matched set of elements to become
	// the specified array of elements (destroying the stack in the process)
	// You should use pushStack() in order to do this, but maintain the stack
	setArray: function( elems ) {
		// Resetting the length to 0, then using the native Array push
		// is a super-fast way to populate an object with array-like properties
		this.length = 0;
		push.apply( this, elems );

		return this;
	},

	// Execute a callback for every element in the matched set.
	// (You can seed the arguments with an array of args, but this is
	// only used internally.)
	each: function( callback, args ) {
		return jQuery.each( this, callback, args );
	},

	// Determine the position of an element within
	// the matched set of elements
	index: function( elem ) {
		if ( !elem || typeof elem === "string" ) {
			return jQuery.inArray( this[0],
				// If it receives a string, the selector is used
				// If it receives nothing, the siblings are used
				elem ? jQuery( elem ) : this.parent().children() );
		}
		// Locate the position of the desired element
		return jQuery.inArray(
			// If it receives a jQuery object, the first element is used
			elem.jquery ? elem[0] : elem, this );
	},

	is: function( selector ) {
		return !!selector && jQuery.filter( selector, this ).length > 0;
	},

	// For internal use only.
	// Behaves like an Array's method, not like a jQuery method.
	push: push,
	sort: [].sort,
	splice: [].splice
};

// Give the init function the jQuery prototype for later instantiation
jQuery.fn.init.prototype = jQuery.fn;

jQuery.extend = jQuery.fn.extend = function() {
	// copy reference to target object
	var target = arguments[0] || {}, i = 1, length = arguments.length, deep = false, options, name, src, copy;

	// Handle a deep copy situation
	if ( typeof target === "boolean" ) {
		deep = target;
		target = arguments[1] || {};
		// skip the boolean and the target
		i = 2;
	}

	// Handle case when target is a string or something (possible in deep copy)
	if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
		target = {};
	}

	// extend jQuery itself if only one argument is passed
	if ( length === i ) {
		target = this;
		--i;
	}

	for ( ; i < length; i++ ) {
		// Only deal with non-null/undefined values
		if ( (options = arguments[ i ]) != null ) {
			// Extend the base object
			for ( name in options ) {
				src = target[ name ];
				copy = options[ name ];

				// Prevent never-ending loop
				if ( target === copy ) {
					continue;
				}

				// Recurse if we're merging object literal values
				if ( deep && copy && jQuery.isObjectLiteral(copy) ) {
					// Don't extend not object literals
					var clone = src && jQuery.isObjectLiteral(src) ? src : {};

					// Never move original objects, clone them
					target[ name ] = jQuery.extend( deep, clone, copy );

				// Don't bring in undefined values
				} else if ( copy !== undefined ) {
					target[ name ] = copy;
				}
			}
		}
	}

	// Return the modified object
	return target;
};

jQuery.extend({
	noConflict: function( deep ) {
		window.$ = _$;

		if ( deep ) {
			window.jQuery = _jQuery;
		}

		return jQuery;
	},

	// See test/unit/core.js for details concerning isFunction.
	// Since version 1.3, DOM methods and functions like alert
	// aren't supported. They return false on IE (#2968).
	isFunction: function( obj ) {
		return toString.call(obj) === "[object Function]";
	},

	isArray: function( obj ) {
		return toString.call(obj) === "[object Array]";
	},

	isObjectLiteral: function( obj ) {
		if ( toString.call(obj) !== "[object Object]" || typeof obj.nodeType === "number" ) {
			return false;
		}
		
		// not own constructor property must be Object
		if ( obj.constructor
		  && !hasOwnProperty.call(obj, "constructor")
		  && !hasOwnProperty.call(obj.constructor.prototype, "isPrototypeOf") ) {
			return false;
		}
		
		//own properties are iterated firstly,
		//so to speed up, we can test last one if it is own or not
	
		var key;
		for ( key in obj ) {}
		
		return key === undefined || hasOwnProperty.call( obj, key );
	},

	isEmptyObject: function( obj ) {
		for ( var name in obj ) {
			return false;
		}
		return true;
	},

	// check if an element is in a (or is an) XML document
	isXMLDoc: function( elem ) {
		// documentElement is verified for cases where it doesn't yet exist
		// (such as loading iframes in IE - #4833)
		var documentElement = (elem ? elem.ownerDocument || elem : 0).documentElement;
		return documentElement ? documentElement.nodeName !== "HTML" : false;
	},

	// Evalulates a script in a global context
	globalEval: function( data ) {
		if ( data && rnotwhite.test(data) ) {
			// Inspired by code by Andrea Giammarchi
			// http://webreflection.blogspot.com/2007/08/global-scope-evaluation-and-dom.html
			var head = document.getElementsByTagName("head")[0] || document.documentElement,
				script = document.createElement("script");

			script.type = "text/javascript";

			if ( jQuery.support.scriptEval ) {
				script.appendChild( document.createTextNode( data ) );
			} else {
				script.text = data;
			}

			// Use insertBefore instead of appendChild  to circumvent an IE6 bug.
			// This arises when a base node is used (#2709).
			head.insertBefore( script, head.firstChild );
			head.removeChild( script );
		}
	},

	nodeName: function( elem, name ) {
		return elem.nodeName && elem.nodeName.toUpperCase() === name.toUpperCase();
	},

	// args is for internal usage only
	each: function( object, callback, args ) {
		var name, i = 0,
			length = object.length,
			isObj = length === undefined || jQuery.isFunction(object);

		if ( args ) {
			if ( isObj ) {
				for ( name in object ) {
					if ( callback.apply( object[ name ], args ) === false ) {
						break;
					}
				}
			} else {
				for ( ; i < length; ) {
					if ( callback.apply( object[ i++ ], args ) === false ) {
						break;
					}
				}
			}

		// A special, fast, case for the most common use of each
		} else {
			if ( isObj ) {
				for ( name in object ) {
					if ( callback.call( object[ name ], name, object[ name ] ) === false ) {
						break;
					}
				}
			} else {
				for ( var value = object[0];
					i < length && callback.call( value, i, value ) !== false; value = object[++i] ) {}
			}
		}

		return object;
	},

	trim: function( text ) {
		return (text || "").replace( rtrim, "" );
	},

	// results is for internal usage only
	makeArray: function( array, results ) {
		var ret = results || [];

		if ( array != null ) {
			// The window, strings (and functions) also have 'length'
			if ( array.length == null || typeof array === "string" || jQuery.isFunction(array) || array.setInterval ) {
				push.call( ret, array );
			} else {
				jQuery.merge( ret, array );
			}
		}

		return ret;
	},

	inArray: function( elem, array ) {
		if ( array.indexOf ) {
			return array.indexOf( elem );
		}

		for ( var i = 0, length = array.length; i < length; i++ ) {
			if ( array[ i ] === elem ) {
				return i;
			}
		}

		return -1;
	},

	merge: function( first, second ) {
		var pos, i = second.length;

		// We have to get length this way when IE & Opera overwrite the length
		// expando of getElementsByTagName
		if ( i && i.nodeType ) {
			for ( i = 0; second[i]; ++i ) {}
		}
		
		pos = i + first.length;
		
		// Correct length for non Arrays
		first.length = pos;
		
		while ( i ) {
			first[ --pos ] = second[ --i ];
		}

		return first;
	},

	grep: function( elems, callback, inv ) {
		var ret = [];

		// Go through the array, only saving the items
		// that pass the validator function
		for ( var i = 0, length = elems.length; i < length; i++ ) {
			if ( !inv !== !callback( elems[ i ], i ) ) {
				ret.push( elems[ i ] );
			}
		}

		return ret;
	},

	// arg is for internal usage only
	map: function( elems, callback, arg ) {
		var ret = [], value;

		// Go through the array, translating each of the items to their
		// new value (or values).
		for ( var i = 0, length = elems.length; i < length; i++ ) {
			value = callback( elems[ i ], i, arg );

			if ( value != null ) {
				ret[ ret.length ] = value;
			}
		}

		return ret.concat.apply( [], ret );
	},

	// Use of jQuery.browser is deprecated.
	// It's included for backwards compatibility and plugins,
	// although they should work to migrate away.
	browser: {
		version: (/.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/.exec(userAgent) || [0,'0'])[1],
		safari: /webkit/.test( userAgent ),
		opera: /opera/.test( userAgent ),
		msie: /msie/.test( userAgent ) && !/opera/.test( userAgent ),
		mozilla: /mozilla/.test( userAgent ) && !/(compatible|webkit)/.test( userAgent )
	}
});

if ( indexOf ) {
	jQuery.inArray = function( elem, array ) {
		return indexOf.call( array, elem );
	};
}

// All jQuery objects should point back to these
rootjQuery = jQuery(document);

function evalScript( i, elem ) {
	if ( elem.src ) {
		jQuery.ajax({
			url: elem.src,
			async: false,
			dataType: "script"
		});
	} else {
		jQuery.globalEval( elem.text || elem.textContent || elem.innerHTML || "" );
	}

	if ( elem.parentNode ) {
		elem.parentNode.removeChild( elem );
	}
}

// Mutifunctional method to get and set values to a collection
// The value/s can be optionally by executed if its a function
function access( elems, key, value, exec, fn ) {
	var l = elems.length;
	
	// Setting many attributes
	if ( typeof key === "object" ) {
			for (var k in key) {
				access(elems, k, key[k], exec, fn);
			}
		return elems;
	}
	
	// Setting one attribute
	if (value !== undefined) {
		// Optionally, function values get executed if exec is true
		exec = exec && jQuery.isFunction(value);
		
		for (var i = 0; i < l; i++) {
			var elem = elems[i],
				val = exec ? value.call(elem, i) : value;
			fn(elem, key, val);
		}
		return elems;
	}
	
	// Getting an attribute
	return l ? fn(elems[0], key) : null;
}

function now() {
	return (new Date).getTime();
}
var expando = "jQuery" + now(), uuid = 0, windowData = {};
var emptyObject = {};

jQuery.extend({
	cache: {},
	
	expando:expando,

	data: function( elem, name, data ) {
		elem = elem == window ?
			windowData :
			elem;

		var id = elem[ expando ], cache = jQuery.cache, thisCache;

		// Handle the case where there's no name immediately
		if ( !name && !id ) {
			return null;
		}

		// Compute a unique ID for the element
		if ( !id ) { 
			id = ++uuid;
		}

		// Avoid generating a new cache unless none exists and we
		// want to manipulate it.
		if ( cache[ id ] ) {
			thisCache = cache[ id ];
		} else if ( typeof data === "undefined" ) {
			thisCache = emptyObject;
		} else {
			thisCache = cache[ id ] = {};
		}
		
		// Prevent overriding the named cache with undefined values
		if ( data !== undefined ) {
			elem[ expando ] = id;
			thisCache[ name ] = data;
		}
		
		return name ? thisCache[ name ] : thisCache;
	},

	removeData: function( elem, name ) {
		elem = elem == window ?
			windowData :
			elem;

		var id = elem[ expando ], cache = jQuery.cache, thisCache = cache[ id ];

		// If we want to remove a specific section of the element's data
		if ( name ) {
			if ( thisCache ) {
				// Remove the section of cache data
				delete thisCache[ name ];

				// If we've removed all the data, remove the element's cache
				if ( jQuery.isEmptyObject(thisCache) ) {
					jQuery.removeData( elem );
				}
			}

		// Otherwise, we want to remove all of the element's data
		} else {
			// Clean up the element expando
			try {
				delete elem[ expando ];
			} catch( e ) {
				// IE has trouble directly removing the expando
				// but it's ok with using removeAttribute
				if ( elem.removeAttribute ) {
					elem.removeAttribute( expando );
				}
			}

			// Completely remove the data cache
			delete cache[ id ];
		}
	},
	
	queue: function( elem, type, data ) {
		if ( !elem ) { return; }

		type = (type || "fx") + "queue";
		var q = jQuery.data( elem, type );

		// Speed up dequeue by getting out quickly if this is just a lookup
		if ( !data ) { return q || []; }

		if ( !q || jQuery.isArray(data) ) {
			q = jQuery.data( elem, type, jQuery.makeArray(data) );
		} else {
			q.push( data );
		}
		return q;
	},

	dequeue: function( elem, type ){
		type = type || "fx";

		var queue = jQuery.queue( elem, type ), fn = queue.shift();

		// If the fx queue is dequeued, always remove the progress sentinel
		if ( fn === "inprogress" ) { fn = queue.shift(); }

		if ( fn ) {
			// Add a progress sentinel to prevent the fx queue from being
			// automatically dequeued
			if ( type == "fx" ) { queue.unshift("inprogress"); }

			fn.call(elem, function() { jQuery.dequeue(elem, type); });
		}
	}
});

jQuery.fn.extend({
	data: function( key, value ){
		if ( typeof key === "undefined" && this.length ) {
			return jQuery.data( this[0] );
		}

		var parts = key.split(".");
		parts[1] = parts[1] ? "." + parts[1] : "";

		if ( value === undefined ) {
			var data = this.triggerHandler("getData" + parts[1] + "!", [parts[0]]);

			if ( data === undefined && this.length ) {
				data = jQuery.data( this[0], key );
			}
			return data === undefined && parts[1] ?
				this.data( parts[0] ) :
				data;
		} else {
			return this.trigger("setData" + parts[1] + "!", [parts[0], value]).each(function(){
				jQuery.data( this, key, value );
			});
		}
	},

	removeData: function( key ){
		return this.each(function(){
			jQuery.removeData( this, key );
		});
	},
	queue: function(type, data){
		if ( typeof type !== "string" ) {
			data = type;
			type = "fx";
		}

		if ( data === undefined ) {
			return jQuery.queue( this[0], type );
		}
		return this.each(function(i, elem){
			var queue = jQuery.queue( this, type, data );

			if ( type == "fx" && queue[0] !== "inprogress" ) {
				jQuery.dequeue( this, type );
			}
		});
	},
	dequeue: function(type){
		return this.each(function(){
			jQuery.dequeue( this, type );
		});
	},

	// Based off of the plugin by Clint Helfers, with permission.
	// http://blindsignals.com/index.php/2009/07/jquery-delay/
	delay: function( time, type ) {
		time = jQuery.fx ? jQuery.fx.speeds[time] || time : time;
		type = type || "fx";

		return this.queue( type, function() {
			var elem = this;
			setTimeout(function() {
				jQuery.dequeue( elem, type );
			}, time );
		});
	},

	clearQueue: function(type){
		return this.queue( type || "fx", [] );
	}
});
/*
 * A number of helper functions used for managing events.
 * Many of the ideas behind this code originated from
 * Dean Edwards' addEvent library.
 */
jQuery.event = {

	// Bind an event to an element
	// Original by Dean Edwards
	add: function( elem, types, handler, data ) {
		if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
			return;
		}

		// For whatever reason, IE has trouble passing the window object
		// around, causing it to be cloned in the process
		if ( elem.setInterval && ( elem !== window && !elem.frameElement ) ) {
			elem = window;
		}

		// Make sure that the function being executed has a unique ID
		if ( !handler.guid ) {
			handler.guid = this.guid++;
		}

		// if data is passed, bind to handler
		if ( data !== undefined ) {
			// Create temporary function pointer to original handler
			var fn = handler;

			// Create unique handler function, wrapped around original handler
			handler = this.proxy( fn );

			// Store data in unique handler
			handler.data = data;
		}

		// Init the element's event structure
		var events = jQuery.data( elem, "events" ) || jQuery.data( elem, "events", {} ),
			handle = jQuery.data( elem, "handle" ) || jQuery.data( elem, "handle", function() {
				// Handle the second event of a trigger and when
				// an event is called after a page has unloaded
				return typeof jQuery !== "undefined" && !jQuery.event.triggered ?
					jQuery.event.handle.apply( arguments.callee.elem, arguments ) :
					undefined;
			});
		// Add elem as a property of the handle function
		// This is to prevent a memory leak with non-native
		// event in IE.
		handle.elem = elem;

		// Handle multiple events separated by a space
		// jQuery(...).bind("mouseover mouseout", fn);
		types = types.split( /\s+/ );
		var type, i=0;
		while ( (type = types[ i++ ]) ) {
			// Namespaced event handlers
			var namespaces = type.split(".");
			type = namespaces.shift();
			handler.type = namespaces.slice(0).sort().join(".");

			// Get the current list of functions bound to this event
			var handlers = events[ type ],
				special = this.special[ type ] || {};

			

			// Init the event handler queue
			if ( !handlers ) {
				handlers = events[ type ] = {};

				// Check for a special event handler
				// Only use addEventListener/attachEvent if the special
				// events handler returns false
				if ( !special.setup || special.setup.call( elem, data, namespaces, handler) === false ) {
					// Bind the global event handler to the element
					if ( elem.addEventListener ) {
						elem.addEventListener( type, handle, false );
					} else if ( elem.attachEvent ) {
						elem.attachEvent( "on" + type, handle );
					}
				}
			}
			
			if ( special.add ) { 
				var modifiedHandler = special.add.call( elem, handler, data, namespaces, handlers ); 
				if ( modifiedHandler && jQuery.isFunction( modifiedHandler ) ) { 
					modifiedHandler.guid = modifiedHandler.guid || handler.guid; 
					handler = modifiedHandler; 
				} 
			} 
			
			// Add the function to the element's handler list
			handlers[ handler.guid ] = handler;

			// Keep track of which events have been used, for global triggering
			this.global[ type ] = true;
		}

		// Nullify elem to prevent memory leaks in IE
		elem = null;
	},

	guid: 1,
	global: {},

	// Detach an event or set of events from an element
	remove: function( elem, types, handler ) {
		// don't do events on text and comment nodes
		if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
			return;
		}

		var events = jQuery.data( elem, "events" ), ret, type, fn;

		if ( events ) {
			// Unbind all events for the element
			if ( types === undefined || (typeof types === "string" && types.charAt(0) === ".") ) {
				for ( type in events ) {
					this.remove( elem, type + (types || "") );
				}
			} else {
				// types is actually an event object here
				if ( types.type ) {
					handler = types.handler;
					types = types.type;
				}

				// Handle multiple events seperated by a space
				// jQuery(...).unbind("mouseover mouseout", fn);
				types = types.split(/\s+/);
				var i = 0;
				while ( (type = types[ i++ ]) ) {
					// Namespaced event handlers
					var namespaces = type.split(".");
					type = namespaces.shift();
					var all = !namespaces.length,
						cleaned = jQuery.map( namespaces.slice(0).sort() , function(nm){ return nm.replace(/[^\w\s\.\|`]/g, function(ch){return "\\"+ch  }) }),
						namespace = new RegExp("(^|\\.)" + cleaned.join("\\.(?:.*\\.)?") + "(\\.|$)"),
						special = this.special[ type ] || {};

					if ( events[ type ] ) {
						// remove the given handler for the given type
						if ( handler ) {
							fn = events[ type ][ handler.guid ];
							delete events[ type ][ handler.guid ];

						// remove all handlers for the given type
						} else {
							for ( var handle in events[ type ] ) {
								// Handle the removal of namespaced events
								if ( all || namespace.test( events[ type ][ handle ].type ) ) {
									delete events[ type ][ handle ];
								}
							}
						}

						if ( special.remove ) {
							special.remove.call( elem, namespaces, fn);
						}

						// remove generic event handler if no more handlers exist
						for ( ret in events[ type ] ) {
							break;
						}
						if ( !ret ) {
							if ( !special.teardown || special.teardown.call( elem, namespaces ) === false ) {
								if ( elem.removeEventListener ) {
									elem.removeEventListener( type, jQuery.data( elem, "handle" ), false );
								} else if ( elem.detachEvent ) {
									elem.detachEvent( "on" + type, jQuery.data( elem, "handle" ) );
								}
							}
							ret = null;
							delete events[ type ];
						}
					}
				}
			}

			// Remove the expando if it's no longer used
			for ( ret in events ) {
				break;
			}
			if ( !ret ) {
				var handle = jQuery.data( elem, "handle" );
				if ( handle ) {
					handle.elem = null;
				}
				jQuery.removeData( elem, "events" );
				jQuery.removeData( elem, "handle" );
			}
		}
	},

	// bubbling is internal
	trigger: function( event, data, elem /*, bubbling */ ) {
		// Event object or event type
		var type = event.type || event,
			bubbling = arguments[3];

		if ( !bubbling ) {
			event = typeof event === "object" ?
				// jQuery.Event object
				event[expando] ? event :
				// Object literal
				jQuery.extend( jQuery.Event(type), event ) :
				// Just the event type (string)
				jQuery.Event(type);

			if ( type.indexOf("!") >= 0 ) {
				event.type = type = type.slice(0, -1);
				event.exclusive = true;
			}

			// Handle a global trigger
			if ( !elem ) {
				// Don't bubble custom events when global (to avoid too much overhead)
				event.stopPropagation();
				// Only trigger if we've ever bound an event for it
				if ( this.global[ type ] ) {
					jQuery.each( jQuery.cache, function() {
						if ( this.events && this.events[type] ) {
							jQuery.event.trigger( event, data, this.handle.elem );
						}
					});
				}
			}

			// Handle triggering a single element

			// don't do events on text and comment nodes
			if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 ) {
				return undefined;
			}

			// Clean up in case it is reused
			event.result = undefined;
			event.target = elem;

			// Clone the incoming data, if any
			data = jQuery.makeArray( data );
			data.unshift( event );
		}

		event.currentTarget = elem;

		// Trigger the event, it is assumed that "handle" is a function
		var handle = jQuery.data( elem, "handle" );
		if ( handle ) {
			handle.apply( elem, data );
		}

		var nativeFn, nativeHandler;
		try {
			nativeFn = elem[ type ];
			nativeHandler = elem[ "on" + type ];
		// prevent IE from throwing an error for some elements with some event types, see #3533
		} catch (e) {}
		// Handle triggering native .onfoo handlers (and on links since we don't call .click() for links)
		if ( (!nativeFn || (jQuery.nodeName(elem, 'a') && type === "click")) && nativeHandler && nativeHandler.apply( elem, data ) === false ) {
			event.result = false;
		}

		// Trigger the native events (except for clicks on links)
		if ( !bubbling && nativeFn && !event.isDefaultPrevented() && !(jQuery.nodeName(elem, 'a') && type === "click") ) {
			this.triggered = true;
			try {
				nativeFn();
			// prevent IE from throwing an error for some hidden elements
			} catch (e) {}
		}

		this.triggered = false;

		if ( !event.isPropagationStopped() ) {
			var parent = elem.parentNode || elem.ownerDocument;
			if ( parent ) {
				jQuery.event.trigger( event, data, parent, true );
			}
		}
	},

	handle: function( event ) {
		// returned undefined or false
		var all, handlers;

		event = arguments[0] = jQuery.event.fix( event || window.event );
		event.currentTarget = this;

		// Namespaced event handlers
		var namespaces = event.type.split(".");
		event.type = namespaces.shift();

		// Cache this now, all = true means, any handler
		all = !namespaces.length && !event.exclusive;

		var namespace = new RegExp("(^|\\.)" + namespaces.slice(0).sort().join("\\.(?:.*\\.)?") + "(\\.|$)");

		handlers = ( jQuery.data(this, "events") || {} )[ event.type ];

		for ( var j in handlers ) {
			var handler = handlers[ j ];

			// Filter the functions by class
			if ( all || namespace.test(handler.type) ) {
				// Pass in a reference to the handler function itself
				// So that we can later remove it
				event.handler = handler;
				event.data = handler.data;

				var ret = handler.apply( this, arguments );

				if ( ret !== undefined ) {
					event.result = ret;
					if ( ret === false ) {
						event.preventDefault();
						event.stopPropagation();
					}
				}

				if ( event.isImmediatePropagationStopped() ) {
					break;
				}

			}
		}
	},

	props: "altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),

	fix: function( event ) {
		if ( event[ expando ] ) {
			return event;
		}

		// store a copy of the original event object
		// and "clone" to set read-only properties
		var originalEvent = event;
		event = jQuery.Event( originalEvent );

		for ( var i = this.props.length, prop; i; ) {
			prop = this.props[ --i ];
			event[ prop ] = originalEvent[ prop ];
		}

		// Fix target property, if necessary
		if ( !event.target ) {
			event.target = event.srcElement || document; // Fixes #1925 where srcElement might not be defined either
		}

		// check if target is a textnode (safari)
		if ( event.target.nodeType === 3 ) {
			event.target = event.target.parentNode;
		}

		// Add relatedTarget, if necessary
		if ( !event.relatedTarget && event.fromElement ) {
			event.relatedTarget = event.fromElement === event.target ? event.toElement : event.fromElement;
		}

		// Calculate pageX/Y if missing and clientX/Y available
		if ( event.pageX == null && event.clientX != null ) {
			var doc = document.documentElement, body = document.body;
			event.pageX = event.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc && doc.clientLeft || body && body.clientLeft || 0);
			event.pageY = event.clientY + (doc && doc.scrollTop  || body && body.scrollTop  || 0) - (doc && doc.clientTop  || body && body.clientTop  || 0);
		}

		// Add which for key events
		if ( !event.which && ((event.charCode || event.charCode === 0) ? event.charCode : event.keyCode) ) {
			event.which = event.charCode || event.keyCode;
		}

		// Add metaKey to non-Mac browsers (use ctrl for PC's and Meta for Macs)
		if ( !event.metaKey && event.ctrlKey ) {
			event.metaKey = event.ctrlKey;
		}

		// Add which for click: 1 == left; 2 == middle; 3 == right
		// Note: button is not normalized, so don't use it
		if ( !event.which && event.button !== undefined ) {
			event.which = (event.button & 1 ? 1 : ( event.button & 2 ? 3 : ( event.button & 4 ? 2 : 0 ) ));
		}

		return event;
	},

	proxy: function( fn, proxy, thisObject ) {
		if ( proxy !== undefined && !jQuery.isFunction( proxy ) ) {
			thisObject = proxy;
			proxy = undefined;
		}
		// FIXME: Should proxy be redefined to be applied with thisObject if defined?
		proxy = proxy || function() { return fn.apply( thisObject !== undefined ? thisObject : this, arguments ); };
		// Set the guid of unique handler to the same of original handler, so it can be removed
		proxy.guid = fn.guid = fn.guid || proxy.guid || this.guid++;
		// So proxy can be declared as an argument
		return proxy;
	},

	special: {
		ready: {
			// Make sure the ready event is setup
			setup: bindReady,
			teardown: function() {}
		},

		live: {
			add: function( proxy, data, namespaces, live ) {
				jQuery.extend( proxy, data || {} );

				proxy.guid += data.selector + data.live; 
				jQuery.event.add( this, data.live, liveHandler, data ); 
				
			},

			remove: function( namespaces ) {
				if ( namespaces.length ) {
					var remove = 0, name = new RegExp("(^|\\.)" + namespaces[0] + "(\\.|$)");

					jQuery.each( (jQuery.data(this, "events").live || {}), function() {
						if ( name.test(this.type) ) {
							remove++;
						}
					});

					if ( remove < 1 ) {
						jQuery.event.remove( this, namespaces[0], liveHandler );
					}
				}
			},
			special: {}
		}
	}
};

jQuery.Event = function( src ){
	// Allow instantiation without the 'new' keyword
	if ( !this.preventDefault ) {
		return new jQuery.Event( src );
	}

	// Event object
	if ( src && src.type ) {
		this.originalEvent = src;
		this.type = src.type;
	// Event type
	} else {
		this.type = src;
	}

	// timeStamp is buggy for some events on Firefox(#3843)
	// So we won't rely on the native value
	this.timeStamp = now();

	// Mark it as fixed
	this[ expando ] = true;
};

function returnFalse() {
	return false;
}
function returnTrue() {
	return true;
}

// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding
// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
jQuery.Event.prototype = {
	preventDefault: function() {
		this.isDefaultPrevented = returnTrue;

		var e = this.originalEvent;
		if ( !e ) {
			return;
		}
		
		// if preventDefault exists run it on the original event
		if ( e.preventDefault ) {
			e.preventDefault();
		}
		// otherwise set the returnValue property of the original event to false (IE)
		e.returnValue = false;
	},
	stopPropagation: function() {
		this.isPropagationStopped = returnTrue;

		var e = this.originalEvent;
		if ( !e ) {
			return;
		}
		// if stopPropagation exists run it on the original event
		if ( e.stopPropagation ) {
			e.stopPropagation();
		}
		// otherwise set the cancelBubble property of the original event to true (IE)
		e.cancelBubble = true;
	},
	stopImmediatePropagation: function(){
		this.isImmediatePropagationStopped = returnTrue;
		this.stopPropagation();
	},
	isDefaultPrevented: returnFalse,
	isPropagationStopped: returnFalse,
	isImmediatePropagationStopped: returnFalse
};
// Checks if an event happened on an element within another element
// Used in jQuery.event.special.mouseenter and mouseleave handlers
var withinElement = function( event ) {
	// Check if mouse(over|out) are still within the same parent element
	var parent = event.relatedTarget;
	// Traverse up the tree
	while ( parent && parent != this ) {
		// Firefox sometimes assigns relatedTarget a XUL element
		// which we cannot access the parentNode property of
		try { parent = parent.parentNode; }
		// assuming we've left the element since we most likely mousedover a xul element
		catch(e) { break; }
	}

	if ( parent != this ) {
		// set the correct event type
		event.type = event.data;
		// handle event if we actually just moused on to a non sub-element
		jQuery.event.handle.apply( this, arguments );
	}

},

// In case of event delegation, we only need to rename the event.type,
// liveHandler will take care of the rest.
delegate = function( event ) {
	event.type = event.data;
	jQuery.event.handle.apply( this, arguments );
};

// Create mouseenter and mouseleave events
jQuery.each({
	mouseover: "mouseenter",
	mouseout: "mouseleave"
}, function( orig, fix ) {
	jQuery.event.special[ fix ] = {
		setup: function(data){
			jQuery.event.add( this, orig, data && data.selector ? delegate : withinElement, fix );
		},
		teardown: function(data){
			jQuery.event.remove( this, orig, data && data.selector ? delegate : withinElement );
		}
	};
});

// submit delegation
jQuery.event.special.submit = {
	setup: function( data, namespaces, fn ) {
		if ( !jQuery.support.submitBubbles && this.nodeName.toLowerCase() !== "form" ) {
			jQuery.event.add(this, "click.specialSubmit." + fn.guid, function( e ) {
				var elem = e.target, type = elem.type;

				if ( (type === "submit" || type === "image") && jQuery( elem ).closest("form").length ) {
					return trigger( "submit", this, arguments );
				}
			});
	 
			jQuery.event.add(this, "keypress.specialSubmit." + fn.guid, function( e ) {
				var elem = e.target, type = elem.type;

				if ( (type === "text" || type === "password") && jQuery( elem ).closest("form").length && e.keyCode === 13 ) {
					return trigger( "submit", this, arguments );
				}
			});
		}

		return false;
	},

	remove: function( namespaces, fn ) {
		jQuery.event.remove( this, "click.specialSubmit" + (fn ? "."+fn.guid : "") );
		jQuery.event.remove( this, "keypress.specialSubmit" + (fn ? "."+fn.guid : "") );
	}
};

// change delegation, happens here so we have bind.
jQuery.event.special.change = {
	filters: {
		click: function( e ) { 
			var elem = e.target;

			if ( elem.nodeName.toLowerCase() === "input" && elem.type === "checkbox" ) {
				return trigger( "change", this, arguments );
			}

			return changeFilters.keyup.call( this, e );
		}, 
		keyup: function( e ) { 
			var elem = e.target, data, index = elem.selectedIndex + "";

			if ( elem.nodeName.toLowerCase() === "select" ) {
				data = jQuery.data( elem, "_change_data" );
				jQuery.data( elem, "_change_data", index );

				if ( (elem.type === "select-multiple" || data != null) && data !== index ) {
					return trigger( "change", this, arguments );
				}
			}
		},
		beforeactivate: function( e ) {
			var elem = e.target;

			if ( elem.nodeName.toLowerCase() === "input" && elem.type === "radio" && !elem.checked ) {
				return trigger( "change", this, arguments );
			}
		},
		blur: function( e ) {
			var elem = e.target, nodeName = elem.nodeName.toLowerCase();

			if ( (nodeName === "textarea" || (nodeName === "input" && (elem.type === "text" || elem.type === "password")))
				&& jQuery.data(elem, "_change_data") !== elem.value ) {

				return trigger( "change", this, arguments );
			}
		},
		focus: function( e ) {
			var elem = e.target, nodeName = elem.nodeName.toLowerCase();

			if ( nodeName === "textarea" || (nodeName === "input" && (elem.type === "text" || elem.type === "password" ) ) ) {
				jQuery.data( elem, "_change_data", elem.value );
			}
		}
	},
	setup: function( data, namespaces, fn ) {
		// return false if we bubble
		if ( !jQuery.support.changeBubbles ) {
			for ( var type in changeFilters ) {
				jQuery.event.add( this, type + ".specialChange." + fn.guid, changeFilters[type] );
			}
		}
		
		// always want to listen for change for trigger
		return false;
	},
	remove: function( namespaces, fn ) {
		if ( !jQuery.support.changeBubbles ) {
			for ( var type in changeFilters ) {
				jQuery.event.remove( this, type + ".specialChange" + (fn ? "."+fn.guid : ""), changeFilters[type] );
			}
		}
	}
};

var changeFilters = jQuery.event.special.change.filters;

function trigger( type, elem, args ) {
	args[0].type = type;
	return jQuery.event.handle.apply( elem, args );
}

// Create "bubbling" focus and blur events
jQuery.each({
	focus: "focusin",
	blur: "focusout"
}, function( orig, fix ){
	var event = jQuery.event,
		handle = event.handle;
	
	function ieHandler() { 
		arguments[0].type = orig;
		return handle.apply(this, arguments);
	}

	event.special[orig] = {
		setup:function() {
			if ( this.addEventListener ) {
				this.addEventListener( orig, handle, true );
			} else {
				event.add( this, fix, ieHandler );
			}
		}, 
		teardown:function() { 
			if ( this.removeEventListener ) {
				this.removeEventListener( orig, handle, true );
			} else {
				event.remove( this, fix, ieHandler );
			}
		}
	};
});

jQuery.fn.extend({
	// TODO: make bind(), unbind() and one() DRY!
	bind: function( type, data, fn, thisObject ) {
		// Handle object literals
		if ( typeof type === "object" ) {
			for ( var key in type ) {
				this.bind(key, data, type[key], fn);
			}
			return this;
		}
		
		if ( jQuery.isFunction( data ) ) {
			thisObject = fn;
			fn = data;
			data = undefined;
		}
		fn = thisObject === undefined ? fn : jQuery.event.proxy( fn, thisObject );
		return type === "unload" ? this.one(type, data, fn, thisObject) : this.each(function() {
			jQuery.event.add( this, type, fn, data );
		});
	},

	one: function( type, data, fn, thisObject ) {
		// Handle object literals
		if ( typeof type === "object" ) {
			for ( var key in type ) {
				this.one(key, data, type[key], fn);
			}
			return this;
		}
		
		if ( jQuery.isFunction( data ) ) {
			thisObject = fn;
			fn = data;
			data = undefined;
		}
		fn = thisObject === undefined ? fn : jQuery.event.proxy( fn, thisObject );
		var one = jQuery.event.proxy( fn, function( event ) {
			jQuery( this ).unbind( event, one );
			return fn.apply( this, arguments );
		});
		return this.each(function() {
			jQuery.event.add( this, type, one, data );
		});
	},

	unbind: function( type, fn ) {
		// Handle object literals
		if ( typeof type === "object" && !type.preventDefault ) {
			for ( var key in type ) {
				this.unbind(key, type[key]);
			}
			return this;
		}
		
		return this.each(function() {
			jQuery.event.remove( this, type, fn );
		});
	},

	trigger: function( type, data ) {
		return this.each(function() {
			jQuery.event.trigger( type, data, this );
		});
	},

	triggerHandler: function( type, data ) {
		if ( this[0] ) {
			var event = jQuery.Event( type );
			event.preventDefault();
			event.stopPropagation();
			jQuery.event.trigger( event, data, this[0] );
			return event.result;
		}
	},

	toggle: function( fn ) {
		// Save reference to arguments for access in closure
		var args = arguments, i = 1;

		// link all the functions, so any of them can unbind this click handler
		while( i < args.length ) {
			jQuery.event.proxy( fn, args[ i++ ] );
		}

		return this.click( jQuery.event.proxy( fn, function( event ) {
			// Figure out which function to execute
			var lastToggle = ( jQuery.data( this, 'lastToggle' + fn.guid ) || 0 ) % i;
			jQuery.data( this, 'lastToggle' + fn.guid, lastToggle + 1 );

			// Make sure that clicks stop
			event.preventDefault();

			// and execute the function
			return args[ lastToggle ].apply( this, arguments ) || false;
		}));
	},

	hover: function( fnOver, fnOut ) {
		return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
	},

	ready: function( fn ) {
		// Attach the listeners
		bindReady();

		// If the DOM is already ready
		if ( jQuery.isReady ) {
			// Execute the function immediately
			fn.call( document, jQuery );

		// Otherwise, remember the function for later
		} else {
			// Add the function to the wait list
			jQuery.readyList.push( fn );
		}

		return this;
	},

	live: function( type, data, fn, thisObject ) {
		if ( jQuery.isFunction( data ) ) {
			if ( fn !== undefined ) {
				thisObject = fn;
			}
			fn = data;
			data = undefined;
		}
		jQuery( this.context ).bind( liveConvert( type, this.selector ), {
			data: data, selector: this.selector, live: type
		}, fn, thisObject );
		return this;
	},

	die: function( type, fn ) {
		jQuery( this.context ).unbind( liveConvert( type, this.selector ), fn ? { guid: fn.guid + this.selector + type } : null );
		return this;
	}
});

function liveHandler( event ) {
	var stop = true, elems = [], selectors = [], args = arguments,
		related, match, fn, elem, j, i, data,
		live = jQuery.extend({}, jQuery.data( this, "events" ).live);

	for ( j in live ) {
		fn = live[j];
		if ( fn.live === event.type ||
				fn.altLive && jQuery.inArray(event.type, fn.altLive) > -1 ) {

			data = fn.data;
			if ( !(data.beforeFilter && data.beforeFilter[event.type] && 
					!data.beforeFilter[event.type](event)) ) {
				selectors.push( fn.selector );
			}
		} else {
			delete live[j];
		}
	}

	match = jQuery( event.target ).closest( selectors, event.currentTarget );

	for ( i = 0, l = match.length; i < l; i++ ) {
		for ( j in live ) {
			fn = live[j];
			elem = match[i].elem;
			related = null;

			if ( match[i].selector === fn.selector ) {
				// Those two events require additional checking
				if ( fn.live === "mouseenter" || fn.live === "mouseleave" ) {
					related = jQuery( event.relatedTarget ).closest( fn.selector )[0];
				}

				if ( !related || related !== elem ) {
					elems.push({ elem: elem, fn: fn });
				}
			}
		}
	}

	for ( i = 0, l = elems.length; i < l; i++ ) {
		match = elems[i];
		event.currentTarget = match.elem;
		event.data = match.fn.data;
		if ( match.fn.apply( match.elem, args ) === false ) {
			stop = false;
			break;
		}
	}

	return stop;
}

function liveConvert( type, selector ) {
	return ["live", type, selector//.replace(/[^\w\s\.]/g, function(ch){ return "\\"+ch})
								  .replace(/\./g, "`")
								  .replace(/ /g, "|")].join(".");
}

jQuery.extend({
	isReady: false,
	readyList: [],
	// Handle when the DOM is ready
	ready: function() {
		// Make sure that the DOM is not already loaded
		if ( !jQuery.isReady ) {
			if ( !document.body ) {
				return setTimeout( jQuery.ready, 13 );
			}

			// Remember that the DOM is ready
			jQuery.isReady = true;

			// If there are functions bound, to execute
			if ( jQuery.readyList ) {
				// Execute all of them
				var fn, i = 0;
				while ( (fn = jQuery.readyList[ i++ ]) ) {
					fn.call( document, jQuery );
				}

				// Reset the list of functions
				jQuery.readyList = null;
			}

			// Trigger any bound ready events
			jQuery( document ).triggerHandler( "ready" );
		}
	}
});

var readyBound = false;

function bindReady() {
	if ( readyBound ) { return; }
	readyBound = true;

	// Catch cases where $(document).ready() is called after the
	// browser event has already occurred.
	if ( document.readyState === "complete" ) {
		return jQuery.ready();
	}

	// Mozilla, Opera and webkit nightlies currently support this event
	if ( document.addEventListener ) {
		// Use the handy event callback
		document.addEventListener( "DOMContentLoaded", function() {
			document.removeEventListener( "DOMContentLoaded", arguments.callee, false );
			jQuery.ready();
		}, false );

	// If IE event model is used
	} else if ( document.attachEvent ) {
		// ensure firing before onload,
		// maybe late but safe also for iframes
		document.attachEvent("onreadystatechange", function() {
			// Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
			if ( document.readyState === "complete" ) {
				document.detachEvent( "onreadystatechange", arguments.callee );
				jQuery.ready();
			}
		});

		// If IE and not a frame
		// continually check to see if the document is ready
		var toplevel = false;

		try {
			toplevel = window.frameElement == null;
		} catch(e){}

		if ( document.documentElement.doScroll && toplevel ) {
			(function() {
				if ( jQuery.isReady ) {
					return;
				}

				try {
					// If IE is used, use the trick by Diego Perini
					// http://javascript.nwbox.com/IEContentLoaded/
					document.documentElement.doScroll("left");
				} catch( error ) {
					setTimeout( arguments.callee, 0 );
					return;
				}

				// and execute any waiting functions
				jQuery.ready();
			})();
		}
	}

	// A fallback to window.onload, that will always work
	jQuery.event.add( window, "load", jQuery.ready );
}

jQuery.each( ("blur focus load resize scroll unload click dblclick " +
	"mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
	"change select submit keydown keypress keyup error").split(" "), function( i, name ) {

	// Handle event binding
	jQuery.fn[ name ] = function( fn ) {
		return fn ? this.bind( name, fn ) : this.trigger( name );
	};
});

// Prevent memory leaks in IE
// Window isn't included so as not to unbind existing unload events
// More info:
//  - http://isaacschlueter.com/2006/10/msie-memory-leaks/
/*@cc_on
jQuery( window ).bind( 'unload', function() {
	for ( var id in jQuery.cache ) {
		// Skip the window
		if ( id != 1 && jQuery.cache[ id ].handle ) {
			jQuery.event.remove( jQuery.cache[ id ].handle.elem );
		}
	}
});
@*/
(function(){

	jQuery.support = {};

	var root = document.documentElement,
		script = document.createElement("script"),
		div = document.createElement("div"),
		id = "script" + now();

	div.style.display = "none";
	div.innerHTML = '   <link/><table></table><a href="/a" style="color:red;float:left;opacity:.55;">a</a><select><option>text</option></select>';

	var all = div.getElementsByTagName("*"),
		a = div.getElementsByTagName("a")[0];

	// Can't get basic test support
	if ( !all || !all.length || !a ) {
		return;
	}

	jQuery.support = {
		// IE strips leading whitespace when .innerHTML is used
		leadingWhitespace: div.firstChild.nodeType == 3,

		// Make sure that tbody elements aren't automatically inserted
		// IE will insert them into empty tables
		tbody: !div.getElementsByTagName("tbody").length,

		// Make sure that link elements get serialized correctly by innerHTML
		// This requires a wrapper element in IE
		htmlSerialize: !!div.getElementsByTagName("link").length,

		// Get the style information from getAttribute
		// (IE uses .cssText insted)
		style: /red/.test( a.getAttribute("style") ),

		// Make sure that URLs aren't manipulated
		// (IE normalizes it by default)
		hrefNormalized: a.getAttribute("href") === "/a",

		// Make sure that element opacity exists
		// (IE uses filter instead)
		opacity: a.style.opacity === "0.55",

		// Verify style float existence
		// (IE uses styleFloat instead of cssFloat)
		cssFloat: !!a.style.cssFloat,

		// Will be defined later
		scriptEval: false,
		noCloneEvent: true,
		boxModel: null
	};

	script.type = "text/javascript";
	try {
		script.appendChild( document.createTextNode( "window." + id + "=1;" ) );
	} catch(e){}

	root.insertBefore( script, root.firstChild );

	// Make sure that the execution of code works by injecting a script
	// tag with appendChild/createTextNode
	// (IE doesn't support this, fails, and uses .text instead)
	if ( window[ id ] ) {
		jQuery.support.scriptEval = true;
		delete window[ id ];
	}

	root.removeChild( script );

	if ( div.attachEvent && div.fireEvent ) {
		div.attachEvent("onclick", function click(){
			// Cloning a node shouldn't copy over any
			// bound event handlers (IE does this)
			jQuery.support.noCloneEvent = false;
			div.detachEvent("onclick", click);
		});
		div.cloneNode(true).fireEvent("onclick");
	}

	// Figure out if the W3C box model works as expected
	// document.body must exist before we can do this
	jQuery(function(){
		var div = document.createElement("div");
		div.style.width = div.style.paddingLeft = "1px";

		document.body.appendChild( div );
		jQuery.boxModel = jQuery.support.boxModel = div.offsetWidth === 2;
		document.body.removeChild( div ).style.display = 'none';
		div = null;
	});

	// Technique from Juriy Zaytsev
	// http://thinkweb2.com/projects/prototype/detecting-event-support-without-browser-sniffing/
	var eventSupported = function( eventName ) { 
		var el = document.createElement("div"); 
		eventName = "on" + eventName; 

		var isSupported = (eventName in el); 
		if ( !isSupported ) { 
			el.setAttribute(eventName, "return;"); 
			isSupported = typeof el[eventName] === "function"; 
		} 
		el = null; 

		return isSupported; 
	};
	
	jQuery.support.submitBubbles = eventSupported("submit");
	jQuery.support.changeBubbles = eventSupported("change");

	// release memory in IE
	root = script = div = all = a = null;
})();

jQuery.props = {
	"for": "htmlFor",
	"class": "className",
	readonly: "readOnly",
	maxlength: "maxLength",
	cellspacing: "cellSpacing",
	rowspan: "rowSpan",
	colspan: "colSpan",
	tabindex: "tabIndex",
	usemap: "useMap",
	frameborder: "frameBorder"
};
/*!
 * Sizzle CSS Selector Engine - v1.0
 *  Copyright 2009, The Dojo Foundation
 *  Released under the MIT, BSD, and GPL Licenses.
 *  More information: http://sizzlejs.com/
 */
(function(){

var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,
	done = 0,
	toString = Object.prototype.toString,
	hasDuplicate = false,
	baseHasDuplicate = true;

// Here we check if the JavaScript engine is using some sort of
// optimization where it does not always call our comparision
// function. If that is the case, discard the hasDuplicate value.
//   Thus far that includes Google Chrome.
[0, 0].sort(function(){
	baseHasDuplicate = false;
	return 0;
});

var Sizzle = function(selector, context, results, seed) {
	results = results || [];
	var origContext = context = context || document;

	if ( context.nodeType !== 1 && context.nodeType !== 9 ) {
		return [];
	}
	
	if ( !selector || typeof selector !== "string" ) {
		return results;
	}

	var parts = [], m, set, checkSet, extra, prune = true, contextXML = isXML(context),
		soFar = selector;
	
	// Reset the position of the chunker regexp (start from head)
	while ( (chunker.exec(""), m = chunker.exec(soFar)) !== null ) {
		soFar = m[3];
		
		parts.push( m[1] );
		
		if ( m[2] ) {
			extra = m[3];
			break;
		}
	}

	if ( parts.length > 1 && origPOS.exec( selector ) ) {
		if ( parts.length === 2 && Expr.relative[ parts[0] ] ) {
			set = posProcess( parts[0] + parts[1], context );
		} else {
			set = Expr.relative[ parts[0] ] ?
				[ context ] :
				Sizzle( parts.shift(), context );

			while ( parts.length ) {
				selector = parts.shift();

				if ( Expr.relative[ selector ] )
					selector += parts.shift();

				set = posProcess( selector, set );
			}
		}
	} else {
		// Take a shortcut and set the context if the root selector is an ID
		// (but not if it'll be faster if the inner selector is an ID)
		if ( !seed && parts.length > 1 && context.nodeType === 9 && !contextXML &&
				Expr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1]) ) {
			var ret = Sizzle.find( parts.shift(), context, contextXML );
			context = ret.expr ? Sizzle.filter( ret.expr, ret.set )[0] : ret.set[0];
		}

		if ( context ) {
			var ret = seed ?
				{ expr: parts.pop(), set: makeArray(seed) } :
				Sizzle.find( parts.pop(), parts.length === 1 && (parts[0] === "~" || parts[0] === "+") && context.parentNode ? context.parentNode : context, contextXML );
			set = ret.expr ? Sizzle.filter( ret.expr, ret.set ) : ret.set;

			if ( parts.length > 0 ) {
				checkSet = makeArray(set);
			} else {
				prune = false;
			}

			while ( parts.length ) {
				var cur = parts.pop(), pop = cur;

				if ( !Expr.relative[ cur ] ) {
					cur = "";
				} else {
					pop = parts.pop();
				}

				if ( pop == null ) {
					pop = context;
				}

				Expr.relative[ cur ]( checkSet, pop, contextXML );
			}
		} else {
			checkSet = parts = [];
		}
	}

	if ( !checkSet ) {
		checkSet = set;
	}

	if ( !checkSet ) {
		throw "Syntax error, unrecognized expression: " + (cur || selector);
	}

	if ( toString.call(checkSet) === "[object Array]" ) {
		if ( !prune ) {
			results.push.apply( results, checkSet );
		} else if ( context && context.nodeType === 1 ) {
			for ( var i = 0; checkSet[i] != null; i++ ) {
				if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && contains(context, checkSet[i])) ) {
					results.push( set[i] );
				}
			}
		} else {
			for ( var i = 0; checkSet[i] != null; i++ ) {
				if ( checkSet[i] && checkSet[i].nodeType === 1 ) {
					results.push( set[i] );
				}
			}
		}
	} else {
		makeArray( checkSet, results );
	}

	if ( extra ) {
		Sizzle( extra, origContext, results, seed );
		Sizzle.uniqueSort( results );
	}

	return results;
};

Sizzle.uniqueSort = function(results){
	if ( sortOrder ) {
		hasDuplicate = baseHasDuplicate;
		results.sort(sortOrder);

		if ( hasDuplicate ) {
			for ( var i = 1; i < results.length; i++ ) {
				if ( results[i] === results[i-1] ) {
					results.splice(i--, 1);
				}
			}
		}
	}

	return results;
};

Sizzle.matches = function(expr, set){
	return Sizzle(expr, null, null, set);
};

Sizzle.find = function(expr, context, isXML){
	var set, match;

	if ( !expr ) {
		return [];
	}

	for ( var i = 0, l = Expr.order.length; i < l; i++ ) {
		var type = Expr.order[i], match;
		
		if ( (match = Expr.leftMatch[ type ].exec( expr )) ) {
			var left = match[1];
			match.splice(1,1);

			if ( left.substr( left.length - 1 ) !== "\\" ) {
				match[1] = (match[1] || "").replace(/\\/g, "");
				set = Expr.find[ type ]( match, context, isXML );
				if ( set != null ) {
					expr = expr.replace( Expr.match[ type ], "" );
					break;
				}
			}
		}
	}

	if ( !set ) {
		set = context.getElementsByTagName("*");
	}

	return {set: set, expr: expr};
};

Sizzle.filter = function(expr, set, inplace, not){
	var old = expr, result = [], curLoop = set, match, anyFound,
		isXMLFilter = set && set[0] && isXML(set[0]);

	while ( expr && set.length ) {
		for ( var type in Expr.filter ) {
			if ( (match = Expr.match[ type ].exec( expr )) != null ) {
				var filter = Expr.filter[ type ], found, item;
				anyFound = false;

				if ( curLoop == result ) {
					result = [];
				}

				if ( Expr.preFilter[ type ] ) {
					match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter );

					if ( !match ) {
						anyFound = found = true;
					} else if ( match === true ) {
						continue;
					}
				}

				if ( match ) {
					for ( var i = 0; (item = curLoop[i]) != null; i++ ) {
						if ( item ) {
							found = filter( item, match, i, curLoop );
							var pass = not ^ !!found;

							if ( inplace && found != null ) {
								if ( pass ) {
									anyFound = true;
								} else {
									curLoop[i] = false;
								}
							} else if ( pass ) {
								result.push( item );
								anyFound = true;
							}
						}
					}
				}

				if ( found !== undefined ) {
					if ( !inplace ) {
						curLoop = result;
					}

					expr = expr.replace( Expr.match[ type ], "" );

					if ( !anyFound ) {
						return [];
					}

					break;
				}
			}
		}

		// Improper expression
		if ( expr == old ) {
			if ( anyFound == null ) {
				throw "Syntax error, unrecognized expression: " + expr;
			} else {
				break;
			}
		}

		old = expr;
	}

	return curLoop;
};

var Expr = Sizzle.selectors = {
	order: [ "ID", "NAME", "TAG" ],
	match: {
		ID: /#((?:[\w\u00c0-\uFFFF-]|\\.)+)/,
		CLASS: /\.((?:[\w\u00c0-\uFFFF-]|\\.)+)/,
		NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF-]|\\.)+)['"]*\]/,
		ATTR: /\[\s*((?:[\w\u00c0-\uFFFF-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/,
		TAG: /^((?:[\w\u00c0-\uFFFF\*-]|\\.)+)/,
		CHILD: /:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/,
		POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/,
		PSEUDO: /:((?:[\w\u00c0-\uFFFF-]|\\.)+)(?:\((['"]*)((?:\([^\)]+\)|[^\2\(\)]*)+)\2\))?/
	},
	leftMatch: {},
	attrMap: {
		"class": "className",
		"for": "htmlFor"
	},
	attrHandle: {
		href: function(elem){
			return elem.getAttribute("href");
		}
	},
	relative: {
		"+": function(checkSet, part, isXML){
			var isPartStr = typeof part === "string",
				isTag = isPartStr && !/\W/.test(part),
				isPartStrNotTag = isPartStr && !isTag;

			if ( isTag && !isXML ) {
				part = part.toUpperCase();
			}

			for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) {
				if ( (elem = checkSet[i]) ) {
					while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {}

					checkSet[i] = isPartStrNotTag || elem && elem.nodeName === part ?
						elem || false :
						elem === part;
				}
			}

			if ( isPartStrNotTag ) {
				Sizzle.filter( part, checkSet, true );
			}
		},
		">": function(checkSet, part, isXML){
			var isPartStr = typeof part === "string";

			if ( isPartStr && !/\W/.test(part) ) {
				part = isXML ? part : part.toUpperCase();

				for ( var i = 0, l = checkSet.length; i < l; i++ ) {
					var elem = checkSet[i];
					if ( elem ) {
						var parent = elem.parentNode;
						checkSet[i] = parent.nodeName === part ? parent : false;
					}
				}
			} else {
				for ( var i = 0, l = checkSet.length; i < l; i++ ) {
					var elem = checkSet[i];
					if ( elem ) {
						checkSet[i] = isPartStr ?
							elem.parentNode :
							elem.parentNode === part;
					}
				}

				if ( isPartStr ) {
					Sizzle.filter( part, checkSet, true );
				}
			}
		},
		"": function(checkSet, part, isXML){
			var doneName = done++, checkFn = dirCheck;

			if ( !/\W/.test(part) ) {
				var nodeCheck = part = isXML ? part : part.toUpperCase();
				checkFn = dirNodeCheck;
			}

			checkFn("parentNode", part, doneName, checkSet, nodeCheck, isXML);
		},
		"~": function(checkSet, part, isXML){
			var doneName = done++, checkFn = dirCheck;

			if ( typeof part === "string" && !/\W/.test(part) ) {
				var nodeCheck = part = isXML ? part : part.toUpperCase();
				checkFn = dirNodeCheck;
			}

			checkFn("previousSibling", part, doneName, checkSet, nodeCheck, isXML);
		}
	},
	find: {
		ID: function(match, context, isXML){
			if ( typeof context.getElementById !== "undefined" && !isXML ) {
				var m = context.getElementById(match[1]);
				return m ? [m] : [];
			}
		},
		NAME: function(match, context, isXML){
			if ( typeof context.getElementsByName !== "undefined" ) {
				var ret = [], results = context.getElementsByName(match[1]);

				for ( var i = 0, l = results.length; i < l; i++ ) {
					if ( results[i].getAttribute("name") === match[1] ) {
						ret.push( results[i] );
					}
				}

				return ret.length === 0 ? null : ret;
			}
		},
		TAG: function(match, context){
			return context.getElementsByTagName(match[1]);
		}
	},
	preFilter: {
		CLASS: function(match, curLoop, inplace, result, not, isXML){
			match = " " + match[1].replace(/\\/g, "") + " ";

			if ( isXML ) {
				return match;
			}

			for ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) {
				if ( elem ) {
					if ( not ^ (elem.className && (" " + elem.className + " ").indexOf(match) >= 0) ) {
						if ( !inplace )
							result.push( elem );
					} else if ( inplace ) {
						curLoop[i] = false;
					}
				}
			}

			return false;
		},
		ID: function(match){
			return match[1].replace(/\\/g, "");
		},
		TAG: function(match, curLoop){
			for ( var i = 0; curLoop[i] === false; i++ ){}
			return curLoop[i] && isXML(curLoop[i]) ? match[1] : match[1].toUpperCase();
		},
		CHILD: function(match){
			if ( match[1] == "nth" ) {
				// parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6'
				var test = /(-?)(\d*)n((?:\+|-)?\d*)/.exec(
					match[2] == "even" && "2n" || match[2] == "odd" && "2n+1" ||
					!/\D/.test( match[2] ) && "0n+" + match[2] || match[2]);

				// calculate the numbers (first)n+(last) including if they are negative
				match[2] = (test[1] + (test[2] || 1)) - 0;
				match[3] = test[3] - 0;
			}

			// TODO: Move to normal caching system
			match[0] = done++;

			return match;
		},
		ATTR: function(match, curLoop, inplace, result, not, isXML){
			var name = match[1].replace(/\\/g, "");
			
			if ( !isXML && Expr.attrMap[name] ) {
				match[1] = Expr.attrMap[name];
			}

			if ( match[2] === "~=" ) {
				match[4] = " " + match[4] + " ";
			}

			return match;
		},
		PSEUDO: function(match, curLoop, inplace, result, not){
			if ( match[1] === "not" ) {
				// If we're dealing with a complex expression, or a simple one
				if ( ( chunker.exec(match[3]) || "" ).length > 1 || /^\w/.test(match[3]) ) {
					match[3] = Sizzle(match[3], null, null, curLoop);
				} else {
					var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not);
					if ( !inplace ) {
						result.push.apply( result, ret );
					}
					return false;
				}
			} else if ( Expr.match.POS.test( match[0] ) || Expr.match.CHILD.test( match[0] ) ) {
				return true;
			}
			
			return match;
		},
		POS: function(match){
			match.unshift( true );
			return match;
		}
	},
	filters: {
		enabled: function(elem){
			return elem.disabled === false && elem.type !== "hidden";
		},
		disabled: function(elem){
			return elem.disabled === true;
		},
		checked: function(elem){
			return elem.checked === true;
		},
		selected: function(elem){
			// Accessing this property makes selected-by-default
			// options in Safari work properly
			elem.parentNode.selectedIndex;
			return elem.selected === true;
		},
		parent: function(elem){
			return !!elem.firstChild;
		},
		empty: function(elem){
			return !elem.firstChild;
		},
		has: function(elem, i, match){
			return !!Sizzle( match[3], elem ).length;
		},
		header: function(elem){
			return /h\d/i.test( elem.nodeName );
		},
		text: function(elem){
			return "text" === elem.type;
		},
		radio: function(elem){
			return "radio" === elem.type;
		},
		checkbox: function(elem){
			return "checkbox" === elem.type;
		},
		file: function(elem){
			return "file" === elem.type;
		},
		password: function(elem){
			return "password" === elem.type;
		},
		submit: function(elem){
			return "submit" === elem.type;
		},
		image: function(elem){
			return "image" === elem.type;
		},
		reset: function(elem){
			return "reset" === elem.type;
		},
		button: function(elem){
			return "button" === elem.type || elem.nodeName.toUpperCase() === "BUTTON";
		},
		input: function(elem){
			return /input|select|textarea|button/i.test(elem.nodeName);
		}
	},
	setFilters: {
		first: function(elem, i){
			return i === 0;
		},
		last: function(elem, i, match, array){
			return i === array.length - 1;
		},
		even: function(elem, i){
			return i % 2 === 0;
		},
		odd: function(elem, i){
			return i % 2 === 1;
		},
		lt: function(elem, i, match){
			return i < match[3] - 0;
		},
		gt: function(elem, i, match){
			return i > match[3] - 0;
		},
		nth: function(elem, i, match){
			return match[3] - 0 == i;
		},
		eq: function(elem, i, match){
			return match[3] - 0 == i;
		}
	},
	filter: {
		PSEUDO: function(elem, match, i, array){
			var name = match[1], filter = Expr.filters[ name ];

			if ( filter ) {
				return filter( elem, i, match, array );
			} else if ( name === "contains" ) {
				return (elem.textContent || elem.innerText || "").indexOf(match[3]) >= 0;
			} else if ( name === "not" ) {
				var not = match[3];

				for ( var i = 0, l = not.length; i < l; i++ ) {
					if ( not[i] === elem ) {
						return false;
					}
				}

				return true;
			}
		},
		CHILD: function(elem, match){
			var type = match[1], node = elem;
			switch (type) {
				case 'only':
				case 'first':
					while ( (node = node.previousSibling) )  {
						if ( node.nodeType === 1 ) return false;
					}
					if ( type == 'first') return true;
					node = elem;
				case 'last':
					while ( (node = node.nextSibling) )  {
						if ( node.nodeType === 1 ) return false;
					}
					return true;
				case 'nth':
					var first = match[2], last = match[3];

					if ( first == 1 && last == 0 ) {
						return true;
					}
					
					var doneName = match[0],
						parent = elem.parentNode;
	
					if ( parent && (parent.sizcache !== doneName || !elem.nodeIndex) ) {
						var count = 0;
						for ( node = parent.firstChild; node; node = node.nextSibling ) {
							if ( node.nodeType === 1 ) {
								node.nodeIndex = ++count;
							}
						} 
						parent.sizcache = doneName;
					}
					
					var diff = elem.nodeIndex - last;
					if ( first == 0 ) {
						return diff == 0;
					} else {
						return ( diff % first == 0 && diff / first >= 0 );
					}
			}
		},
		ID: function(elem, match){
			return elem.nodeType === 1 && elem.getAttribute("id") === match;
		},
		TAG: function(elem, match){
			return (match === "*" && elem.nodeType === 1) || elem.nodeName === match;
		},
		CLASS: function(elem, match){
			return (" " + (elem.className || elem.getAttribute("class")) + " ")
				.indexOf( match ) > -1;
		},
		ATTR: function(elem, match){
			var name = match[1],
				result = Expr.attrHandle[ name ] ?
					Expr.attrHandle[ name ]( elem ) :
					elem[ name ] != null ?
						elem[ name ] :
						elem.getAttribute( name ),
				value = result + "",
				type = match[2],
				check = match[4];

			return result == null ?
				type === "!=" :
				type === "=" ?
				value === check :
				type === "*=" ?
				value.indexOf(check) >= 0 :
				type === "~=" ?
				(" " + value + " ").indexOf(check) >= 0 :
				!check ?
				value && result !== false :
				type === "!=" ?
				value != check :
				type === "^=" ?
				value.indexOf(check) === 0 :
				type === "$=" ?
				value.substr(value.length - check.length) === check :
				type === "|=" ?
				value === check || value.substr(0, check.length + 1) === check + "-" :
				false;
		},
		POS: function(elem, match, i, array){
			var name = match[2], filter = Expr.setFilters[ name ];

			if ( filter ) {
				return filter( elem, i, match, array );
			}
		}
	}
};

var origPOS = Expr.match.POS;

for ( var type in Expr.match ) {
	Expr.match[ type ] = new RegExp( Expr.match[ type ].source + /(?![^\[]*\])(?![^\(]*\))/.source );
	Expr.leftMatch[ type ] = new RegExp( /(^(?:.|\r|\n)*?)/.source + Expr.match[ type ].source );
}

var makeArray = function(array, results) {
	array = Array.prototype.slice.call( array, 0 );

	if ( results ) {
		results.push.apply( results, array );
		return results;
	}
	
	return array;
};

// Perform a simple check to determine if the browser is capable of
// converting a NodeList to an array using builtin methods.
try {
	Array.prototype.slice.call( document.documentElement.childNodes, 0 );

// Provide a fallback method if it does not work
} catch(e){
	makeArray = function(array, results) {
		var ret = results || [];

		if ( toString.call(array) === "[object Array]" ) {
			Array.prototype.push.apply( ret, array );
		} else {
			if ( typeof array.length === "number" ) {
				for ( var i = 0, l = array.length; i < l; i++ ) {
					ret.push( array[i] );
				}
			} else {
				for ( var i = 0; array[i]; i++ ) {
					ret.push( array[i] );
				}
			}
		}

		return ret;
	};
}

var sortOrder;

if ( document.documentElement.compareDocumentPosition ) {
	sortOrder = function( a, b ) {
		if ( !a.compareDocumentPosition || !b.compareDocumentPosition ) {
			if ( a == b ) {
				hasDuplicate = true;
			}
			return a.compareDocumentPosition ? -1 : 1;
		}

		var ret = a.compareDocumentPosition(b) & 4 ? -1 : a === b ? 0 : 1;
		if ( ret === 0 ) {
			hasDuplicate = true;
		}
		return ret;
	};
} else if ( "sourceIndex" in document.documentElement ) {
	sortOrder = function( a, b ) {
		if ( !a.sourceIndex || !b.sourceIndex ) {
			if ( a == b ) {
				hasDuplicate = true;
			}
			return a.sourceIndex ? -1 : 1;
		}

		var ret = a.sourceIndex - b.sourceIndex;
		if ( ret === 0 ) {
			hasDuplicate = true;
		}
		return ret;
	};
} else if ( document.createRange ) {
	sortOrder = function( a, b ) {
		if ( !a.ownerDocument || !b.ownerDocument ) {
			if ( a == b ) {
				hasDuplicate = true;
			}
			return a.ownerDocument ? -1 : 1;
		}

		var aRange = a.ownerDocument.createRange(), bRange = b.ownerDocument.createRange();
		aRange.setStart(a, 0);
		aRange.setEnd(a, 0);
		bRange.setStart(b, 0);
		bRange.setEnd(b, 0);
		var ret = aRange.compareBoundaryPoints(Range.START_TO_END, bRange);
		if ( ret === 0 ) {
			hasDuplicate = true;
		}
		return ret;
	};
}

// Check to see if the browser returns elements by name when
// querying by getElementById (and provide a workaround)
(function(){
	// We're going to inject a fake input element with a specified name
	var form = document.createElement("div"),
		id = "script" + (new Date).getTime();
	form.innerHTML = "<a name='" + id + "'/>";

	// Inject it into the root element, check its status, and remove it quickly
	var root = document.documentElement;
	root.insertBefore( form, root.firstChild );

	// The workaround has to do additional checks after a getElementById
	// Which slows things down for other browsers (hence the branching)
	if ( document.getElementById( id ) ) {
		Expr.find.ID = function(match, context, isXML){
			if ( typeof context.getElementById !== "undefined" && !isXML ) {
				var m = context.getElementById(match[1]);
				return m ? m.id === match[1] || typeof m.getAttributeNode !== "undefined" && m.getAttributeNode("id").nodeValue === match[1] ? [m] : undefined : [];
			}
		};

		Expr.filter.ID = function(elem, match){
			var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id");
			return elem.nodeType === 1 && node && node.nodeValue === match;
		};
	}

	root.removeChild( form );
	root = form = null; // release memory in IE
})();

(function(){
	// Check to see if the browser returns only elements
	// when doing getElementsByTagName("*")

	// Create a fake element
	var div = document.createElement("div");
	div.appendChild( document.createComment("") );

	// Make sure no comments are found
	if ( div.getElementsByTagName("*").length > 0 ) {
		Expr.find.TAG = function(match, context){
			var results = context.getElementsByTagName(match[1]);

			// Filter out possible comments
			if ( match[1] === "*" ) {
				var tmp = [];

				for ( var i = 0; results[i]; i++ ) {
					if ( results[i].nodeType === 1 ) {
						tmp.push( results[i] );
					}
				}

				results = tmp;
			}

			return results;
		};
	}

	// Check to see if an attribute returns normalized href attributes
	div.innerHTML = "<a href='#'></a>";
	if ( div.firstChild && typeof div.firstChild.getAttribute !== "undefined" &&
			div.firstChild.getAttribute("href") !== "#" ) {
		Expr.attrHandle.href = function(elem){
			return elem.getAttribute("href", 2);
		};
	}

	div = null; // release memory in IE
})();

if ( document.querySelectorAll ) (function(){
	var oldSizzle = Sizzle, div = document.createElement("div");
	div.innerHTML = "<p class='TEST'></p>";

	// Safari can't handle uppercase or unicode characters when
	// in quirks mode.
	if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) {
		return;
	}
	
	Sizzle = function(query, context, extra, seed){
		context = context || document;

		// Only use querySelectorAll on non-XML documents
		// (ID selectors don't work in non-HTML documents)
		if ( !seed && context.nodeType === 9 && !isXML(context) ) {
			try {
				return makeArray( context.querySelectorAll(query), extra );
			} catch(e){}
		}
		
		return oldSizzle(query, context, extra, seed);
	};

	for ( var prop in oldSizzle ) {
		Sizzle[ prop ] = oldSizzle[ prop ];
	}

	div = null; // release memory in IE
})();

if ( document.getElementsByClassName && document.documentElement.getElementsByClassName ) (function(){
	var div = document.createElement("div");
	div.innerHTML = "<div class='test e'></div><div class='test'></div>";

	// Opera can't find a second classname (in 9.6)
	if ( div.getElementsByClassName("e").length === 0 )
		return;

	// Safari caches class attributes, doesn't catch changes (in 3.2)
	div.lastChild.className = "e";

	if ( div.getElementsByClassName("e").length === 1 )
		return;

	Expr.order.splice(1, 0, "CLASS");
	Expr.find.CLASS = function(match, context, isXML) {
		if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) {
			return context.getElementsByClassName(match[1]);
		}
	};

	div = null; // release memory in IE
})();

function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
	var sibDir = dir == "previousSibling" && !isXML;
	for ( var i = 0, l = checkSet.length; i < l; i++ ) {
		var elem = checkSet[i];
		if ( elem ) {
			if ( sibDir && elem.nodeType === 1 ){
				elem.sizcache = doneName;
				elem.sizset = i;
			}
			elem = elem[dir];
			var match = false;

			while ( elem ) {
				if ( elem.sizcache === doneName ) {
					match = checkSet[elem.sizset];
					break;
				}

				if ( elem.nodeType === 1 && !isXML ){
					elem.sizcache = doneName;
					elem.sizset = i;
				}

				if ( elem.nodeName === cur ) {
					match = elem;
					break;
				}

				elem = elem[dir];
			}

			checkSet[i] = match;
		}
	}
}

function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
	var sibDir = dir == "previousSibling" && !isXML;
	for ( var i = 0, l = checkSet.length; i < l; i++ ) {
		var elem = checkSet[i];
		if ( elem ) {
			if ( sibDir && elem.nodeType === 1 ) {
				elem.sizcache = doneName;
				elem.sizset = i;
			}
			elem = elem[dir];
			var match = false;

			while ( elem ) {
				if ( elem.sizcache === doneName ) {
					match = checkSet[elem.sizset];
					break;
				}

				if ( elem.nodeType === 1 ) {
					if ( !isXML ) {
						elem.sizcache = doneName;
						elem.sizset = i;
					}
					if ( typeof cur !== "string" ) {
						if ( elem === cur ) {
							match = true;
							break;
						}

					} else if ( Sizzle.filter( cur, [elem] ).length > 0 ) {
						match = elem;
						break;
					}
				}

				elem = elem[dir];
			}

			checkSet[i] = match;
		}
	}
}

var contains = document.compareDocumentPosition ?  function(a, b){
	return a.compareDocumentPosition(b) & 16;
} : function(a, b){
	return a !== b && (a.contains ? a.contains(b) : true);
};

var isXML = function(elem){
	return elem.nodeType === 9 && elem.documentElement.nodeName !== "HTML" ||
		!!elem.ownerDocument && elem.ownerDocument.documentElement.nodeName !== "HTML";
};

var posProcess = function(selector, context){
	var tmpSet = [], later = "", match,
		root = context.nodeType ? [context] : context;

	// Position selectors must be done after the filter
	// And so must :not(positional) so we move all PSEUDOs to the end
	while ( (match = Expr.match.PSEUDO.exec( selector )) ) {
		later += match[0];
		selector = selector.replace( Expr.match.PSEUDO, "" );
	}

	selector = Expr.relative[selector] ? selector + "*" : selector;

	for ( var i = 0, l = root.length; i < l; i++ ) {
		Sizzle( selector, root[i], tmpSet );
	}

	return Sizzle.filter( later, tmpSet );
};

// EXPOSE
jQuery.find = Sizzle;
jQuery.expr = Sizzle.selectors;
jQuery.expr[":"] = jQuery.expr.filters;
jQuery.unique = Sizzle.uniqueSort;

return;

window.Sizzle = Sizzle;

})();
var runtil = /Until$/,
	rparentsprev = /^(?:parents|prevUntil|prevAll)/,
	// Note: This RegExp should be improved, or likely pulled from Sizzle
	rmultiselector = /,/,
	slice = Array.prototype.slice;

// Implement the identical functionality for filter and not
var winnow = function( elements, qualifier, keep ) {
	if ( jQuery.isFunction( qualifier ) ) {
		return jQuery.grep(elements, function(elem, i) {
			return !!qualifier.call( elem, i ) === keep;
		});

	} else if ( qualifier.nodeType ) {
		return jQuery.grep(elements, function(elem, i) {
			return (elem === qualifier) === keep;
		});

	} else if ( typeof qualifier === "string" ) {
		var filtered = jQuery.grep(elements, function(elem) {
			return elem.nodeType === 1;
		});

		if ( isSimple.test( qualifier ) ) {
			return jQuery.filter(qualifier, filtered, !keep);
		} else {
			qualifier = jQuery.filter( qualifier, elements );
		}
	}

	return jQuery.grep(elements, function(elem, i) {
		return (jQuery.inArray( elem, qualifier ) >= 0) === keep;
	});
};

jQuery.fn.extend({
	find: function( selector ) {
		var ret = this.pushStack( "", "find", selector ), length = 0;

		for ( var i = 0, l = this.length; i < l; i++ ) {
			length = ret.length;
			jQuery.find( selector, this[i], ret );

			if ( i > 0 ) {
				// Make sure that the results are unique
				for ( var n = length; n < ret.length; n++ ) {
					for ( var r = 0; r < length; r++ ) {
						if ( ret[r] === ret[n] ) {
							ret.splice(n--, 1);
							break;
						}
					}
				}
			}
		}

		return ret;
	},

	not: function( selector ) {
		return this.pushStack( winnow(this, selector, false), "not", selector);
	},

	filter: function( selector ) {
		return this.pushStack( winnow(this, selector, true), "filter", selector );
	},

	closest: function( selectors, context ) {
		if ( jQuery.isArray( selectors ) ) {
			var ret = [], cur = this[0], match, matches = {}, selector;

			if ( cur && selectors.length ) {
				for ( var i = 0, l = selectors.length; i < l; i++ ) {
					selector = selectors[i];

					if ( !matches[selector] ) {
						matches[selector] = jQuery.expr.match.POS.test( selector ) ? 
							jQuery( selector, context || this.context ) :
							selector;
					}
				}

				while ( cur && cur.ownerDocument && cur !== context ) {
					for ( selector in matches ) {
						match = matches[selector];

						if ( match.jquery ? match.index(cur) > -1 : jQuery(cur).is(match) ) {
							ret.push({ selector: selector, elem: cur });
							delete matches[selector];
						}
					}
					cur = cur.parentNode;
				}
			}

			return ret;
		}

		var pos = jQuery.expr.match.POS.test( selectors ) ? 
			jQuery( selectors, context || this.context ) : null;

		return this.map(function(i, cur){
			while ( cur && cur.ownerDocument && cur !== context ) {
				if ( pos ? pos.index(cur) > -1 : jQuery(cur).is(selectors) ) {
					return cur;
				}
				cur = cur.parentNode;
			}
			return null;
		});
	},

	add: function( selector, context ) {
		var set = typeof selector === "string" ?
				jQuery( selector, context || this.context ) :
				jQuery.makeArray( selector ),
			all = jQuery.merge( this.get(), set );

		return this.pushStack( set[0] && (set[0].setInterval || set[0].nodeType === 9 || (set[0].parentNode && set[0].parentNode.nodeType !== 11)) ?
			jQuery.unique( all ) :
			all );
	},

	eq: function( i ) {
		return i === -1 ?
			this.slice( i ) :
			this.slice( i, +i + 1 );
	},

	first: function() {
		return this.eq( 0 );
	},

	last: function() {
		return this.eq( -1 );
	},

	slice: function() {
		return this.pushStack( slice.apply( this, arguments ),
			"slice", slice.call(arguments).join(",") );
	},

	map: function( callback ) {
		return this.pushStack( jQuery.map(this, function(elem, i){
			return callback.call( elem, i, elem );
		}));
	},

	andSelf: function() {
		return this.add( this.prevObject );
	},

	end: function() {
		return this.prevObject || jQuery(null);
	}
});

jQuery.each({
	parent: function(elem){return elem.parentNode;},
	parents: function(elem){return jQuery.dir(elem,"parentNode");},
	parentsUntil: function(elem,i,until){return jQuery.dir(elem,"parentNode",until);},
	next: function(elem){return jQuery.nth(elem,2,"nextSibling");},
	prev: function(elem){return jQuery.nth(elem,2,"previousSibling");},
	nextAll: function(elem){return jQuery.dir(elem,"nextSibling");},
	prevAll: function(elem){return jQuery.dir(elem,"previousSibling");},
	nextUntil: function(elem,i,until){return jQuery.dir(elem,"nextSibling",until);},
	prevUntil: function(elem,i,until){return jQuery.dir(elem,"previousSibling",until);},
	siblings: function(elem){return jQuery.sibling(elem.parentNode.firstChild,elem);},
	children: function(elem){return jQuery.sibling(elem.firstChild);},
	contents: function(elem){return jQuery.nodeName(elem,"iframe")?elem.contentDocument||elem.contentWindow.document:jQuery.makeArray(elem.childNodes);}
}, function(name, fn){
	jQuery.fn[ name ] = function( until, selector ) {
		var ret = jQuery.map( this, fn, until );
		
		if ( !runtil.test( name ) ) {
			selector = until;
		}

		if ( selector && typeof selector === "string" ) {
			ret = jQuery.filter( selector, ret );
		}

		ret = this.length > 1 ? jQuery.unique( ret ) : ret;

		if ( (this.length > 1 || rmultiselector.test( selector )) && rparentsprev.test( name ) ) {
			ret = ret.reverse();
		}

		return this.pushStack( ret, name, slice.call(arguments).join(",") );
	};
});

jQuery.extend({
	filter: function( expr, elems, not ) {
		if ( not ) {
			expr = ":not(" + expr + ")";
		}

		return jQuery.find.matches(expr, elems);
	},
	
	dir: function( elem, dir, until ) {
		var matched = [], cur = elem[dir];
		while ( cur && cur.nodeType !== 9 && (until === undefined || !jQuery( cur ).is( until )) ) {
			if ( cur.nodeType === 1 ) {
				matched.push( cur );
			}
			cur = cur[dir];
		}
		return matched;
	},

	nth: function( cur, result, dir, elem ) {
		result = result || 1;
		var num = 0;

		for ( ; cur; cur = cur[dir] ) {
			if ( cur.nodeType === 1 && ++num === result ) {
				break;
			}
		}

		return cur;
	},

	sibling: function( n, elem ) {
		var r = [];

		for ( ; n; n = n.nextSibling ) {
			if ( n.nodeType === 1 && n !== elem ) {
				r.push( n );
			}
		}

		return r;
	}
});
jQuery.fn.extend({
	attr: function( name, value ) {
		return access(this, name, value, true, jQuery.attr);
	},

	addClass: function( value ) {
		if ( value && typeof value === "string" ) {
			var classNames = (value || "").split(/\s+/);

			for ( var i = 0, l = this.length; i < l; i++ ) {
				var elem = this[i];

				if ( elem.nodeType === 1 ) {
					if ( !elem.className ) {
						elem.className = value;
					} else {
						var className = " " + elem.className + " ";
						for ( var c = 0, cl = classNames.length; c < cl; c++ ) {
							if ( className.indexOf( " " + classNames[c] + " " ) < 0 ) {
								elem.className += " " + classNames[c];
							}
						}
					}
				}
			}
		}

		return this;
	},

	removeClass: function( value ) {
		if ( (value && typeof value === "string") || value === undefined ) {
			var classNames = (value || "").split(/\s+/);

			for ( var i = 0, l = this.length; i < l; i++ ) {
				var elem = this[i];

				if ( elem.nodeType === 1 && elem.className ) {
					if ( value ) {
					var className = " " + elem.className + " ";
						for ( var c = 0, cl = classNames.length; c < cl; c++ ) {
							className = className.replace(" " + classNames[c] + " ", " ");
						}
						elem.className = className.substring(1, className.length - 1);
					} else {
						elem.className = "";
					}
				}
			}
		}

		return this;
	},

	hasClass: function( selector ) {
		var className = " " + selector + " ";
		for ( var i = 0, l = this.length; i < l; i++ ) {
			if ( (" " + this[i].className + " ").indexOf( className ) > -1 ) {
				return true;
			}
		}

		return false;
	},

	val: function( value ) {
		if ( value === undefined ) {
			var elem = this[0];

			if ( elem ) {
				if( jQuery.nodeName( elem, 'option' ) ) {
					return (elem.attributes.value || {}).specified ? elem.value : elem.text;
				}
				// We need to handle select boxes special
				if ( jQuery.nodeName( elem, "select" ) ) {
					var index = elem.selectedIndex,
						values = [],
						options = elem.options,
						one = elem.type == "select-one";

					// Nothing was selected
					if ( index < 0 ) {
						return null;
					}
					// Loop through all the selected options
					for ( var i = one ? index : 0, max = one ? index + 1 : options.length; i < max; i++ ) {
						var option = options[ i ];

						if ( option.selected ) {
							// Get the specifc value for the option
							value = jQuery(option).val();

							// We don't need an array for one selects
							if ( one ) {
								return value;
							}
							// Multi-Selects return an array
							values.push( value );
						}
					}

					return values;
				}

				// Everything else, we just grab the value
				return (elem.value || "").replace(/\r/g, "");

			}

			return undefined;
		}

		// Typecast once if the value is a number
		if ( typeof value === "number" ) {
			value += '';
		}	
		var val = value;

		return this.each(function(){
			if(jQuery.isFunction(value)) {
				val = value.call(this);
				// Typecast each time if the value is a Function and the appended
				// value is therefore different each time.
				if( typeof val === "number" ) {
					val += ''; 
				}
			}
			
			if ( this.nodeType != 1 ) {
				return;
			}
			if ( jQuery.isArray(val) && /radio|checkbox/.test( this.type ) ) {
				this.checked = jQuery.inArray(this.value || this.name, val) >= 0;
			}
			else if ( jQuery.nodeName( this, "select" ) ) {
				var values = jQuery.makeArray(val);

				jQuery( "option", this ).each(function(){
					this.selected = jQuery.inArray( this.value || this.text, values ) >= 0;
				});

				if ( !values.length ) {
					this.selectedIndex = -1;
				}
			} else {
				this.value = val;
			}
		});
	}
});

jQuery.each({
	removeAttr: function( name ) {
		jQuery.attr( this, name, "" );
		if (this.nodeType == 1) {
			this.removeAttribute( name );
		}
	},

	toggleClass: function( classNames, state ) {
		var type = typeof classNames;
		if ( type === "string" ) {
			// toggle individual class names
			var isBool = typeof state === "boolean", className, i = 0,
				classNames = classNames.split( /\s+/ );
			while ( (className = classNames[ i++ ]) ) {
				// check each className given, space seperated list
				state = isBool ? state : !jQuery(this).hasClass( className );
				jQuery(this)[ state ? "addClass" : "removeClass" ]( className );
			}
		} else if ( type === "undefined" || type === "boolean" ) {
			if ( this.className ) {
				// store className if set
				jQuery.data( this, "__className__", this.className );
			}
			// toggle whole className
			this.className = this.className || classNames === false ? "" : jQuery.data( this, "__className__" ) || "";
		}
	}
}, function(name, fn){
	jQuery.fn[ name ] = function(){
		return this.each( fn, arguments );
	};
});

jQuery.extend({
	attr: function( elem, name, value ) {
		// don't set attributes on text and comment nodes
		if (!elem || elem.nodeType == 3 || elem.nodeType == 8) {
			return undefined;
		}
		if ( name in jQuery.fn && name !== "attr" ) {
			return jQuery(elem)[name](value);
		}
		
		var notxml = elem.nodeType !== 1 || !jQuery.isXMLDoc( elem ),
			// Whether we are setting (or getting)
			set = value !== undefined;

		// Try to normalize/fix the name
		name = notxml && jQuery.props[ name ] || name;

		// Only do all the following if this is a node (faster for style)
		if ( elem.nodeType === 1 ) {

			// These attributes require special treatment
			var special = /href|src|style/.test( name );

			// Safari mis-reports the default selected property of a hidden option
			// Accessing the parent's selectedIndex property fixes it
			if ( name == "selected" && elem.parentNode ) {
				elem.parentNode.selectedIndex;
			}
			// If applicable, access the attribute via the DOM 0 way
			if ( name in elem && notxml && !special ) {
				if ( set ) {
					// We can't allow the type property to be changed (since it causes problems in IE)
					if ( name == "type" && /(button|input)/i.test(elem.nodeName) && elem.parentNode ) {
						throw "type property can't be changed";
					}
					elem[ name ] = value;
				}

				// browsers index elements by id/name on forms, give priority to attributes.
				if( jQuery.nodeName( elem, "form" ) && elem.getAttributeNode(name) ) {
					return elem.getAttributeNode( name ).nodeValue;
				}
				// elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set
				// http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/
				if ( name == "tabIndex" ) {
					var attributeNode = elem.getAttributeNode( "tabIndex" );
					return attributeNode && attributeNode.specified
						? attributeNode.value
						: /(button|input|object|select|textarea)/i.test(elem.nodeName)
							? 0
							: /^(a|area)$/i.test(elem.nodeName) && elem.href
								? 0
								: undefined;
				}

				return elem[ name ];
			}

			if ( !jQuery.support.style && notxml && name == "style" ) {
				if ( set ) {
					elem.style.cssText = "" + value;
				}
				return elem.style.cssText;
			}

			if ( set ) {
				// convert the value to a string (all browsers do this but IE) see #1070
				elem.setAttribute( name, "" + value );
			}
			var attr = !jQuery.support.hrefNormalized && notxml && special
					// Some attributes require a special call on IE
					? elem.getAttribute( name, 2 )
					: elem.getAttribute( name );

			// Non-existent attributes return null, we normalize to undefined
			return attr === null ? undefined : attr;
		}

		// elem is actually elem.style ... set the style
		// Using attr for specific style information is now deprecated. Use style insead.
		return jQuery.style(elem, name, value);
	}
});
var rinlinejQuery = / jQuery\d+="(?:\d+|null)"/g,
	rleadingWhitespace = /^\s+/,
	rxhtmlTag = /(<([\w:]+)[^>]*?)\/>/g,
	rselfClosing = /^(?:abbr|br|col|img|input|link|meta|param|hr|area|embed)$/i,
	rtagName = /<([\w:]+)/,
	rtbody = /<tbody/i,
	rhtml = /<|&\w+;/,
	fcloseTag = function(all, front, tag){
		return rselfClosing.test(tag) ?
			all :
			front + "></" + tag + ">";
	},
	wrapMap = {
		option: [ 1, "<select multiple='multiple'>", "</select>" ],
		legend: [ 1, "<fieldset>", "</fieldset>" ],
		thead: [ 1, "<table>", "</table>" ],
		tr: [ 2, "<table><tbody>", "</tbody></table>" ],
		td: [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ],
		col: [ 2, "<table><tbody></tbody><colgroup>", "</colgroup></table>" ],
		_default: [ 0, "", "" ]
	};

wrapMap.optgroup = wrapMap.option;
wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
wrapMap.th = wrapMap.td;

// IE can't serialize <link> and <script> tags normally
if ( !jQuery.support.htmlSerialize ) {
	wrapMap._default = [ 1, "div<div>", "</div>" ];
}

jQuery.fn.extend({
	text: function( text ) {
		if ( typeof text !== "object" && text !== undefined ) {
			return this.empty().append( (this[0] && this[0].ownerDocument || document).createTextNode( text ) );
		}

		var ret = "";

		jQuery.each( this, function() {
			// Get the text from text nodes and CDATA nodes
			if ( this.nodeType === 3 || this.nodeType === 4 ) {
				ret += this.nodeValue;

			// Traverse everything else, except comment nodes
			} else if ( this.nodeType !== 8 ) {
				ret += jQuery.fn.text.call( this.childNodes );
			}
		});

		return ret;
	},

	wrapAll: function( html ) {
		if ( jQuery.isFunction( html ) ) {
			return this.each(function() {
				jQuery(this).wrapAll( html.apply(this, arguments) );
			});
		}

		if ( this[0] ) {
			// The elements to wrap the target around
			var wrap = jQuery( html, this[0].ownerDocument ).eq(0).clone();

			if ( this[0].parentNode ) {
				wrap.insertBefore( this[0] );
			}

			wrap.map(function(){
				var elem = this;

				while ( elem.firstChild && elem.firstChild.nodeType === 1 ) {
					elem = elem.firstChild;
				}

				return elem;
			}).append(this);
		}

		return this;
	},

	wrapInner: function( html ) {
		return this.each(function(){
			jQuery( this ).contents().wrapAll( html );
		});
	},

	wrap: function( html ) {
		return this.each(function(){
			jQuery( this ).wrapAll( html );
		});
	},

	unwrap: function() {
		return this.parent().each(function(){
			if ( !jQuery.nodeName( this, "body" ) ) {
				jQuery( this ).replaceWith( this.childNodes );
			}
		}).end();
	},
	
	append: function() {
		return this.domManip(arguments, true, function(elem){
			if ( this.nodeType === 1 ) {
				this.appendChild( elem );
			}
		});
	},

	prepend: function() {
		return this.domManip(arguments, true, function(elem){
			if ( this.nodeType === 1 ) {
				this.insertBefore( elem, this.firstChild );
			}
		});
	},

	before: function() {
		if ( this[0] && this[0].parentNode ) {
			return this.domManip(arguments, false, function(elem){
				this.parentNode.insertBefore( elem, this );
			});
		} else if ( arguments.length ) {
			var set = jQuery(arguments[0]);
			set.push.apply( set, this.toArray() );
			return this.pushStack( set, "before", arguments );
		}
	},

	after: function() {
		if ( this[0] && this[0].parentNode ) {
			return this.domManip(arguments, false, function(elem){
				this.parentNode.insertBefore( elem, this.nextSibling );
			});
		} else if ( arguments.length ) {
			var set = this.pushStack( this, "after", arguments );
			set.push.apply( set, jQuery(arguments[0]).toArray() );
			return set;
		}
	},

	clone: function( events ) {
		// Do the clone
		var ret = this.map(function(){
			if ( !jQuery.support.noCloneEvent && !jQuery.isXMLDoc(this) ) {
				// IE copies events bound via attachEvent when
				// using cloneNode. Calling detachEvent on the
				// clone will also remove the events from the orignal
				// In order to get around this, we use innerHTML.
				// Unfortunately, this means some modifications to
				// attributes in IE that are actually only stored
				// as properties will not be copied (such as the
				// the name attribute on an input).
				var html = this.outerHTML, ownerDocument = this.ownerDocument;
				if ( !html ) {
					var div = ownerDocument.createElement("div");
					div.appendChild( this.cloneNode(true) );
					html = div.innerHTML;
				}

				return jQuery.clean([html.replace(rinlinejQuery, "")
					.replace(rleadingWhitespace, "")], ownerDocument)[0];
			} else {
				return this.cloneNode(true);
			}
		});

		// Copy the events from the original to the clone
		if ( events === true ) {
			cloneCopyEvent( this, ret );
			cloneCopyEvent( this.find("*"), ret.find("*") );
		}

		// Return the cloned set
		return ret;
	},

	html: function( value ) {
		if ( value === undefined ) {
			return this[0] ?
				this[0].innerHTML.replace(rinlinejQuery, "") :
				null;

		// See if we can take a shortcut and just use innerHTML
		} else if ( typeof value === "string" && !/<script/i.test( value ) &&
			(jQuery.support.leadingWhitespace || !rleadingWhitespace.test( value )) &&
			!wrapMap[ (rtagName.exec( value ) || ["", ""])[1].toLowerCase() ] ) {

			try {
				for ( var i = 0, l = this.length; i < l; i++ ) {
					// Remove element nodes and prevent memory leaks
					if ( this[i].nodeType === 1 ) {
						cleanData( this[i].getElementsByTagName("*") );
						this[i].innerHTML = value;
					}
				}

			// If using innerHTML throws an exception, use the fallback method
			} catch(e) {
				this.empty().append( value );
			}

		} else {
			this.empty().append( value );
		}

		return this;
	},

	replaceWith: function( value ) {
		if ( this[0] && this[0].parentNode ) {
			return this.after( value ).remove();
		} else {
			return this.pushStack( jQuery(jQuery.isFunction(value) ? value() : value), "replaceWith", value );
		}
	},

	detach: function( selector ) {
		return this.remove( selector, true );
	},

	domManip: function( args, table, callback ) {
		var results, first, value = args[0], scripts = [];

		if ( jQuery.isFunction(value) ) {
			return this.each(function() {
				args[0] = value.call(this);
				return jQuery(this).domManip( args, table, callback );
			});
		}

		if ( this[0] ) {
			// If we're in a fragment, just use that instead of building a new one
			if ( args[0] && args[0].parentNode && args[0].parentNode.nodeType === 11 ) {
				results = { fragment: args[0].parentNode };
			} else {
				results = buildFragment( args, this, scripts );
			}

			first = results.fragment.firstChild;

			if ( first ) {
				table = table && jQuery.nodeName( first, "tr" );

				for ( var i = 0, l = this.length; i < l; i++ ) {
					callback.call(
						table ?
							root(this[i], first) :
							this[i],
						results.cacheable || this.length > 1 || i > 0 ?
							results.fragment.cloneNode(true) :
							results.fragment
					);
				}
			}

			if ( scripts ) {
				jQuery.each( scripts, evalScript );
			}
		}

		return this;

		function root( elem, cur ) {
			return jQuery.nodeName(elem, "table") ?
				(elem.getElementsByTagName("tbody")[0] ||
				elem.appendChild(elem.ownerDocument.createElement("tbody"))) :
				elem;
		}
	}
});

function cloneCopyEvent(orig, ret) {
	var i = 0;

	ret.each(function(){
		if ( this.nodeName !== orig[i].nodeName ) {
			return;
		}

		var events = jQuery.data( orig[i], "events" );

		for ( var type in events ) {
			for ( var handler in events[ type ] ) {
				jQuery.event.add( this, type, events[ type ][ handler ], events[ type ][ handler ].data );
			}
		}
	});
}

function buildFragment(args, nodes, scripts){
	var fragment, cacheable, cached, cacheresults, doc;

	if ( args.length === 1 && typeof args[0] === "string" && args[0].length < 512 && args[0].indexOf("<option") < 0 ) {
		cacheable = true;
		cacheresults = jQuery.fragments[ args[0] ];
		if ( cacheresults ) {
			if ( cacheresults !== 1 ) {
				fragment = cacheresults;
			}
			cached = true;
		}
	}

	if ( !fragment ) {
		doc = (nodes && nodes[0] ? nodes[0].ownerDocument || nodes[0] : document);
		fragment = doc.createDocumentFragment();
		jQuery.clean( args, doc, fragment, scripts );
	}

	if ( cacheable ) {
		jQuery.fragments[ args[0] ] = cacheresults ? fragment : 1;
	}

	return { fragment: fragment, cacheable: cacheable };
}

jQuery.fragments = {};

jQuery.each({
	appendTo: "append",
	prependTo: "prepend",
	insertBefore: "before",
	insertAfter: "after",
	replaceAll: "replaceWith"
}, function(name, original){
	jQuery.fn[ name ] = function( selector ) {
		var ret = [], insert = jQuery( selector );

		for ( var i = 0, l = insert.length; i < l; i++ ) {
			var elems = (i > 0 ? this.clone(true) : this).get();
			jQuery.fn[ original ].apply( jQuery(insert[i]), elems );
			ret = ret.concat( elems );
		}
		return this.pushStack( ret, name, insert.selector );
	};
});

jQuery.each({
	// keepData is for internal use only--do not document
	remove: function( selector, keepData ) {
		if ( !selector || jQuery.filter( selector, [ this ] ).length ) {
			if ( !keepData && this.nodeType === 1 ) {
				cleanData( this.getElementsByTagName("*") );
				cleanData( [ this ] );
			}

			if ( this.parentNode ) {
				 this.parentNode.removeChild( this );
			}
		}
	},

	empty: function() {
		// Remove element nodes and prevent memory leaks
		if ( this.nodeType === 1 ) {
			cleanData( this.getElementsByTagName("*") );
		}

		// Remove any remaining nodes
		while ( this.firstChild ) {
			this.removeChild( this.firstChild );
		}
	}
}, function(name, fn){
	jQuery.fn[ name ] = function(){
		return this.each( fn, arguments );
	};
});

jQuery.extend({
	clean: function( elems, context, fragment, scripts ) {
		context = context || document;

		// !context.createElement fails in IE with an error but returns typeof 'object'
		if ( typeof context.createElement === "undefined" ) {
			context = context.ownerDocument || context[0] && context[0].ownerDocument || document;
		}

		var ret = [], div = context.createElement("div");

		jQuery.each(elems, function(i, elem){
			if ( typeof elem === "number" ) {
				elem += '';
			}

			if ( !elem ) { return; }

			// Convert html string into DOM nodes
			if ( typeof elem === "string" && !rhtml.test( elem ) ) {
				elem = context.createTextNode( elem );

			} else if ( typeof elem === "string" ) {
				// Fix "XHTML"-style tags in all browsers
				elem = elem.replace(rxhtmlTag, fcloseTag);

				// Trim whitespace, otherwise indexOf won't work as expected
				var tag = (rtagName.exec( elem ) || ["", ""])[1].toLowerCase(),
					wrap = wrapMap[ tag ] || wrapMap._default,
					depth = wrap[0];

				// Go to html and back, then peel off extra wrappers
				div.innerHTML = wrap[1] + elem + wrap[2];

				// Move to the right depth
				while ( depth-- ) {
					div = div.lastChild;
				}

				// Remove IE's autoinserted <tbody> from table fragments
				if ( !jQuery.support.tbody ) {

					// String was a <table>, *may* have spurious <tbody>
					var hasBody = rtbody.test(elem),
						tbody = tag === "table" && !hasBody ?
							div.firstChild && div.firstChild.childNodes :

							// String was a bare <thead> or <tfoot>
							wrap[1] == "<table>" && !hasBody ?
								div.childNodes :
								[];

					for ( var j = tbody.length - 1; j >= 0 ; --j ) {
						if ( jQuery.nodeName( tbody[ j ], "tbody" ) && !tbody[ j ].childNodes.length ) {
							tbody[ j ].parentNode.removeChild( tbody[ j ] );
						}
					}

				}

				// IE completely kills leading whitespace when innerHTML is used
				if ( !jQuery.support.leadingWhitespace && rleadingWhitespace.test( elem ) ) {
					div.insertBefore( context.createTextNode( rleadingWhitespace.exec(elem)[0] ), div.firstChild );
				}

				elem = jQuery.makeArray( div.childNodes );
			}

			if ( elem.nodeType ) {
				ret.push( elem );
			} else {
				ret = jQuery.merge( ret, elem );
			}

		});

		if ( fragment ) {
			for ( var i = 0; ret[i]; i++ ) {
				if ( scripts && jQuery.nodeName( ret[i], "script" ) && (!ret[i].type || ret[i].type.toLowerCase() === "text/javascript") ) {
					scripts.push( ret[i].parentNode ? ret[i].parentNode.removeChild( ret[i] ) : ret[i] );
				} else {
					if ( ret[i].nodeType === 1 ) {
						ret.splice.apply( ret, [i + 1, 0].concat(jQuery.makeArray(ret[i].getElementsByTagName("script"))) );
					}
					fragment.appendChild( ret[i] );
				}
			}
		}

		return ret;
	}
});

function cleanData( elems ) {
	for ( var i = 0, elem, id; (elem = elems[i]) != null; i++ ) {
		if ( (id = elem[expando]) ) {
			delete jQuery.cache[ id ];
		}
	}
}
// exclude the following css properties to add px
var rexclude = /z-?index|font-?weight|opacity|zoom|line-?height/i,
	ralpha = /alpha\([^)]*\)/,
	ropacity = /opacity=([^)]*)/,
	rfloat = /float/i,
	rdashAlpha = /-([a-z])/ig,
	rupper = /([A-Z])/g,
	rnumpx = /^\d+(?:px)?$/i,
	rnum = /^\d/,

	// cache check for defaultView.getComputedStyle
	getComputedStyle = document.defaultView && document.defaultView.getComputedStyle,
	// normalize float css property
	styleFloat = jQuery.support.cssFloat ? "cssFloat" : "styleFloat",
	fcamelCase = function(all, letter){
		return letter.toUpperCase();
	};

jQuery.fn.css = function( name, value ) {
	return access( this, name, value, true, function( elem, name, value ) {
		if (value === undefined) {
			return jQuery.css( elem, name );
		}
		
		if ( typeof value === "number" && !rexclude.test(name) ) {
			value += "px";
		}

		jQuery.style( elem, name, value );
	});
};

jQuery.extend({
	style: function( elem, name, value ) {
		// don't set styles on text and comment nodes
		if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 ) {
			return undefined;
		}

		// ignore negative width and height values #1599
		if ( (name === "width" || name === "height") && parseFloat(value) < 0 ) {
			value = undefined;
		}

		var style = elem.style || elem, set = value !== undefined;

		// IE uses filters for opacity
		if ( !jQuery.support.opacity && name === "opacity" ) {
			if ( set ) {
				// IE has trouble with opacity if it does not have layout
				// Force it by setting the zoom level
				style.zoom = 1;

				// Set the alpha filter to set the opacity
				var opacity = parseInt( value, 10 ) + '' === "NaN" ? "" : "alpha(opacity=" + value * 100 + ")";
				filter = style.filter || jQuery.curCSS( elem, 'filter' ) || ""
				style.filter = ralpha.test(filter) ? filter.replace(ralpha, opacity) : opacity;
			}

			return style.filter && style.filter.indexOf("opacity=") >= 0 ?
				(parseFloat( ropacity.exec(style.filter)[1] ) / 100) + '':
				"";
		}

		// Make sure we're using the right name for getting the float value
		if ( rfloat.test( name ) ) {
			name = styleFloat;
		}

		name = name.replace(rdashAlpha, fcamelCase);

		if ( set ) {
			style[ name ] = value;
		}

		return style[ name ];
	},

	css: function( elem, name, force, extra ) {
		if ( name === "width" || name === "height" ) {
			var val, props = { position: "absolute", visibility: "hidden", display:"block" }, which = name === "width" ? [ "Left", "Right" ] : [ "Top", "Bottom" ];

			function getWH() {
				val = name === "width" ? elem.offsetWidth : elem.offsetHeight;

				if ( extra === "border" ) { return; }

				jQuery.each( which, function() {
					if ( !extra ) {
						val -= parseFloat(jQuery.curCSS( elem, "padding" + this, true)) || 0;
					}

					if ( extra === "margin" ) {
						val += parseFloat(jQuery.curCSS( elem, "margin" + this, true)) || 0;
					} else {
						val -= parseFloat(jQuery.curCSS( elem, "border" + this + "Width", true)) || 0;
					}
				});
			}

			if ( elem.offsetWidth !== 0 ) {
				getWH();
			} else {
				jQuery.swap( elem, props, getWH );
			}

			return Math.max(0, Math.round(val));
		}

		return jQuery.curCSS( elem, name, force );
	},

	curCSS: function( elem, name, force ) {
		var ret, style = elem.style, filter;

		// IE uses filters for opacity
		if ( !jQuery.support.opacity && name === "opacity" && elem.currentStyle ) {
			ret = ropacity.test(elem.currentStyle.filter || "") ?
				(parseFloat(RegExp.$1) / 100) + "" :
				"";

			return ret === "" ?
				"1" :
				ret;
		}

		// Make sure we're using the right name for getting the float value
		if ( rfloat.test( name ) ) {
			name = styleFloat;
		}

		if ( !force && style && style[ name ] ) {
			ret = style[ name ];

		} else if ( getComputedStyle ) {

			// Only "float" is needed here
			if ( rfloat.test( name ) ) {
				name = "float";
			}

			name = name.replace( rupper, "-$1" ).toLowerCase();

			var computedStyle = elem.ownerDocument.defaultView.getComputedStyle( elem, null );

			if ( computedStyle ) {
				ret = computedStyle.getPropertyValue( name );
			}

			// We should always get a number back from opacity
			if ( name === "opacity" && ret === "" ) {
				ret = "1";
			}

		} else if ( elem.currentStyle ) {
			var camelCase = name.replace(rdashAlpha, fcamelCase);

			ret = elem.currentStyle[ name ] || elem.currentStyle[ camelCase ];

			// From the awesome hack by Dean Edwards
			// http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291

			// If we're not dealing with a regular pixel number
			// but a number that has a weird ending, we need to convert it to pixels
			if ( !rnumpx.test( ret ) && rnum.test( ret ) ) {
				// Remember the original values
				var left = style.left, rsLeft = elem.runtimeStyle.left;

				// Put in the new values to get a computed value out
				elem.runtimeStyle.left = elem.currentStyle.left;
				style.left = camelCase === "fontSize" ? "1em" : (ret || 0);
				ret = style.pixelLeft + "px";

				// Revert the changed values
				style.left = left;
				elem.runtimeStyle.left = rsLeft;
			}
		}

		return ret;
	},

	// A method for quickly swapping in/out CSS properties to get correct calculations
	swap: function( elem, options, callback ) {
		var old = {};

		// Remember the old values, and insert the new ones
		for ( var name in options ) {
			old[ name ] = elem.style[ name ];
			elem.style[ name ] = options[ name ];
		}

		callback.call( elem );

		// Revert the old values
		for ( var name in options ) {
			elem.style[ name ] = old[ name ];
		}
	}
});

if ( jQuery.expr && jQuery.expr.filters ) {
	jQuery.expr.filters.hidden = function(elem){
		var width = elem.offsetWidth, height = elem.offsetHeight,
			 force = /^tr$/i.test( elem.nodeName ); // ticket #4512

		return width === 0 && height === 0 && !force ?
			true :
				width !== 0 && height !== 0 && !force ?
					false :
						jQuery.curCSS(elem, "display") === "none";
	};

	jQuery.expr.filters.visible = function(elem){
		return !jQuery.expr.filters.hidden(elem);
	};
}
var jsc = now(),
	rscript = /<script(.|\s)*?\/script>/g,
	rselectTextarea = /select|textarea/i,
	rinput = /text|hidden|password|search/i,
	jsre = /=\?(&|$)/,
	rquery = /\?/,
	rts = /(\?|&)_=.*?(&|$)/,
	rurl = /^(\w+:)?\/\/([^\/?#]+)/,
	r20 = /%20/g;

jQuery.fn.extend({
	// Keep a copy of the old load
	_load: jQuery.fn.load,

	load: function( url, params, callback ) {
		if ( typeof url !== "string" ) {
			return this._load( url );

		// Don't do a request if no elements are being requested
		} else if ( !this.length ) {
			return this;
		}

		var off = url.indexOf(" ");
		if ( off >= 0 ) {
			var selector = url.slice(off, url.length);
			url = url.slice(0, off);
		}

		// Default to a GET request
		var type = "GET";

		// If the second parameter was provided
		if ( params ) {
			// If it's a function
			if ( jQuery.isFunction( params ) ) {
				// We assume that it's the callback
				callback = params;
				params = null;

			// Otherwise, build a param string
			} else if ( typeof params === "object" ) {
				params = jQuery.param( params );
				type = "POST";
			}
		}

		// Request the remote document
		jQuery.ajax({
			url: url,
			type: type,
			dataType: "html",
			data: params,
			context:this,
			complete: function(res, status){
				// If successful, inject the HTML into all the matched elements
				if ( status === "success" || status === "notmodified" ) {
					// See if a selector was specified
					this.html( selector ?
						// Create a dummy div to hold the results
						jQuery("<div />")
							// inject the contents of the document in, removing the scripts
							// to avoid any 'Permission Denied' errors in IE
							.append(res.responseText.replace(rscript, ""))

							// Locate the specified elements
							.find(selector) :

						// If not, just inject the full result
						res.responseText );
				}

				if ( callback ) {
					this.each( callback, [res.responseText, status, res] );
				}
			}
		});

		return this;
	},

	serialize: function() {
		return jQuery.param(this.serializeArray());
	},
	serializeArray: function() {
		return this.map(function(){
			return this.elements ? jQuery.makeArray(this.elements) : this;
		})
		.filter(function(){
			return this.name && !this.disabled &&
				(this.checked || rselectTextarea.test(this.nodeName) ||
					rinput.test(this.type));
		})
		.map(function(i, elem){
			var val = jQuery(this).val();

			return val == null ?
				null :
				jQuery.isArray(val) ?
					jQuery.map( val, function(val, i){
						return {name: elem.name, value: val};
					}) :
					{name: elem.name, value: val};
		}).get();
	}
});

// Attach a bunch of functions for handling common AJAX events
jQuery.each( "ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "), function(i,o){
	jQuery.fn[o] = function(f){
		return this.bind(o, f);
	};
});

jQuery.extend({

	get: function( url, data, callback, type ) {
		// shift arguments if data argument was omited
		if ( jQuery.isFunction( data ) ) {
			type = type || callback;
			callback = data;
			data = null;
		}

		return jQuery.ajax({
			type: "GET",
			url: url,
			data: data,
			success: callback,
			dataType: type
		});
	},

	getScript: function( url, callback ) {
		return jQuery.get(url, null, callback, "script");
	},

	getJSON: function( url, data, callback ) {
		return jQuery.get(url, data, callback, "json");
	},

	post: function( url, data, callback, type ) {
		// shift arguments if data argument was omited
		if ( jQuery.isFunction( data ) ) {
			type = type || callback;
			callback = data;
			data = {};
		}

		return jQuery.ajax({
			type: "POST",
			url: url,
			data: data,
			success: callback,
			dataType: type
		});
	},

	ajaxSetup: function( settings ) {
		jQuery.extend( jQuery.ajaxSettings, settings );
	},

	ajaxSettings: {
		url: location.href,
		global: true,
		type: "GET",
		contentType: "application/x-www-form-urlencoded",
		processData: true,
		async: true,
		/*
		timeout: 0,
		data: null,
		username: null,
		password: null,
		*/
		// Create the request object; Microsoft failed to properly
		// implement the XMLHttpRequest in IE7, so we use the ActiveXObject when it is available
		// This function can be overriden by calling jQuery.ajaxSetup
		xhr: function(){
			return window.ActiveXObject ?
				new ActiveXObject("Microsoft.XMLHTTP") :
				new XMLHttpRequest();
		},
		accepts: {
			xml: "application/xml, text/xml",
			html: "text/html",
			script: "text/javascript, application/javascript",
			json: "application/json, text/javascript",
			text: "text/plain",
			_default: "*/*"
		}
	},

	// Last-Modified header cache for next request
	lastModified: {},
	etag: {},

	ajax: function( s ) {
		// Extend the settings, but re-extend 's' so that it can be
		// checked again later (in the test suite, specifically)
		s = jQuery.extend(true, {}, jQuery.ajaxSettings, s);
		
		var jsonp, status, data,
			callbackContext = s.context || window,
			type = s.type.toUpperCase();

		// convert data if not already a string
		if ( s.data && s.processData && typeof s.data !== "string" ) {
			s.data = jQuery.param(s.data);
		}

		// Handle JSONP Parameter Callbacks
		if ( s.dataType === "jsonp" ) {
			if ( type === "GET" ) {
				if ( !jsre.test( s.url ) ) {
					s.url += (rquery.test( s.url ) ? "&" : "?") + (s.jsonp || "callback") + "=?";
				}
			} else if ( !s.data || !jsre.test(s.data) ) {
				s.data = (s.data ? s.data + "&" : "") + (s.jsonp || "callback") + "=?";
			}
			s.dataType = "json";
		}

		// Build temporary JSONP function
		if ( s.dataType === "json" && (s.data && jsre.test(s.data) || jsre.test(s.url)) ) {
			jsonp = "jsonp" + jsc++;

			// Replace the =? sequence both in the query string and the data
			if ( s.data ) {
				s.data = (s.data + "").replace(jsre, "=" + jsonp + "$1");
			}

			s.url = s.url.replace(jsre, "=" + jsonp + "$1");

			// We need to make sure
			// that a JSONP style response is executed properly
			s.dataType = "script";

			// Handle JSONP-style loading
			window[ jsonp ] = function(tmp){
				data = tmp;
				success();
				complete();
				// Garbage collect
				window[ jsonp ] = undefined;
				try{ delete window[ jsonp ]; } catch(e){}
				if ( head ) {
					head.removeChild( script );
				}
			};
		}

		if ( s.dataType === "script" && s.cache === null ) {
			s.cache = false;
		}

		if ( s.cache === false && type === "GET" ) {
			var ts = now();

			// try replacing _= if it is there
			var ret = s.url.replace(rts, "$1_=" + ts + "$2");

			// if nothing was replaced, add timestamp to the end
			s.url = ret + ((ret === s.url) ? (rquery.test(s.url) ? "&" : "?") + "_=" + ts : "");
		}

		// If data is available, append data to url for get requests
		if ( s.data && type === "GET" ) {
			s.url += (rquery.test(s.url) ? "&" : "?") + s.data;
		}

		// Watch for a new set of requests
		if ( s.global && ! jQuery.active++ ) {
			jQuery.event.trigger( "ajaxStart" );
		}

		// Matches an absolute URL, and saves the domain
		var parts = rurl.exec( s.url ),
			remote = parts && (parts[1] && parts[1] !== location.protocol || parts[2] !== location.host);

		// If we're requesting a remote document
		// and trying to load JSON or Script with a GET
		if ( s.dataType === "script" && type === "GET" && remote ) {
			var head = document.getElementsByTagName("head")[0] || document.documentElement;
			var script = document.createElement("script");
			script.src = s.url;
			if ( s.scriptCharset ) {
				script.charset = s.scriptCharset;
			}

			// Handle Script loading
			if ( !jsonp ) {
				var done = false;

				// Attach handlers for all browsers
				script.onload = script.onreadystatechange = function(){
					if ( !done && (!this.readyState ||
							this.readyState === "loaded" || this.readyState === "complete") ) {
						done = true;
						success();
						complete();

						// Handle memory leak in IE
						script.onload = script.onreadystatechange = null;
						if ( head && script.parentNode ) {
							head.removeChild( script );
						}
					}
				};
			}

			// Use insertBefore instead of appendChild  to circumvent an IE6 bug.
			// This arises when a base node is used (#2709 and #4378).
			head.insertBefore( script, head.firstChild );

			// We handle everything using the script element injection
			return undefined;
		}

		var requestDone = false;

		// Create the request object
		var xhr = s.xhr();

		// Open the socket
		// Passing null username, generates a login popup on Opera (#2865)
		if ( s.username ) {
			xhr.open(type, s.url, s.async, s.username, s.password);
		} else {
			xhr.open(type, s.url, s.async);
		}

		// Need an extra try/catch for cross domain requests in Firefox 3
		try {
			// Set the correct header, if data is being sent
			if ( s.data ) {
				xhr.setRequestHeader("Content-Type", s.contentType);
			}

			// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
			if ( s.ifModified ) {
				if ( jQuery.lastModified[s.url] ) {
					xhr.setRequestHeader("If-Modified-Since", jQuery.lastModified[s.url]);
				}

				if ( jQuery.etag[s.url] ) {
					xhr.setRequestHeader("If-None-Match", jQuery.etag[s.url]);
				}
			}

			// Set header so the called script knows that it's an XMLHttpRequest
			// Only send the header if it's not a remote XHR
			if ( !remote ) {
				xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
			}

			// Set the Accepts header for the server, depending on the dataType
			xhr.setRequestHeader("Accept", s.dataType && s.accepts[ s.dataType ] ?
				s.accepts[ s.dataType ] + ", */*" :
				s.accepts._default );
		} catch(e){}

		// Allow custom headers/mimetypes and early abort
		if ( s.beforeSend && s.beforeSend.call(callbackContext, xhr, s) === false ) {
			// Handle the global AJAX counter
			if ( s.global && ! --jQuery.active ) {
				jQuery.event.trigger( "ajaxStop" );
			}

			// close opended socket
			xhr.abort();
			return false;
		}

		if ( s.global ) {
			trigger("ajaxSend", [xhr, s]);
		}

		// Wait for a response to come back
		var onreadystatechange = function(isTimeout){
			// The request was aborted, clear the interval and decrement jQuery.active
			if ( !xhr || xhr.readyState === 0 ) {
				if ( ival ) {
					// clear poll interval
					clearInterval( ival );
					ival = null;

					// Handle the global AJAX counter
					if ( s.global && ! --jQuery.active ) {
						jQuery.event.trigger( "ajaxStop" );
					}
				}

			// The transfer is complete and the data is available, or the request timed out
			} else if ( !requestDone && xhr && (xhr.readyState === 4 || isTimeout === "timeout") ) {
				requestDone = true;

				// clear poll interval
				if (ival) {
					clearInterval(ival);
					ival = null;
				}

				status = isTimeout === "timeout" ?
					"timeout" :
					!jQuery.httpSuccess( xhr ) ?
						"error" :
						s.ifModified && jQuery.httpNotModified( xhr, s.url ) ?
							"notmodified" :
							"success";

				if ( status === "success" ) {
					// Watch for, and catch, XML document parse errors
					try {
						// process the data (runs the xml through httpData regardless of callback)
						data = jQuery.httpData( xhr, s.dataType, s );
					} catch(e) {
						status = "parsererror";
					}
				}

				// Make sure that the request was successful or notmodified
				if ( status === "success" || status === "notmodified" ) {
					// JSONP handles its own success callback
					if ( !jsonp ) {
						success();
					}
				} else {
					jQuery.handleError(s, xhr, status);
				}

				// Fire the complete handlers
				complete();

				if ( isTimeout ) {
					xhr.abort();
				}

				// Stop memory leaks
				if ( s.async ) {
					xhr = null;
				}
			}
		};

		if ( s.async ) {
			// don't attach the handler to the request, just poll it instead
			var ival = setInterval(onreadystatechange, 13);

			// Timeout checker
			if ( s.timeout > 0 ) {
				setTimeout(function(){
					// Check to see if the request is still happening
					if ( xhr && !requestDone ) {
						onreadystatechange( "timeout" );
					}
				}, s.timeout);
			}
		}

		// Send the data
		try {
			xhr.send( type === "POST" || type === "PUT" ? s.data : null );
		} catch(e) {
			jQuery.handleError(s, xhr, null, e);
			// Fire the complete handlers
			complete();
		}

		// firefox 1.5 doesn't fire statechange for sync requests
		if ( !s.async ) {
			onreadystatechange();
		}

		function success(){
			// If a local callback was specified, fire it and pass it the data
			if ( s.success ) {
				s.success.call( callbackContext, data, status, xhr );
			}

			// Fire the global callback
			if ( s.global ) {
				trigger( "ajaxSuccess", [xhr, s] );
			}
		}

		function complete(){
			// Process result
			if ( s.complete ) {
				s.complete.call( callbackContext, xhr, status);
			}

			// The request was completed
			if ( s.global ) {
				trigger( "ajaxComplete", [xhr, s] );
			}

			// Handle the global AJAX counter
			if ( s.global && ! --jQuery.active ) {
				jQuery.event.trigger( "ajaxStop" );
			}
		}
		
		function trigger(type, args){
			(s.context ? jQuery(s.context) : jQuery.event).trigger(type, args);
		}

		// return XMLHttpRequest to allow aborting the request etc.
		return xhr;
	},

	handleError: function( s, xhr, status, e ) {
		// If a local callback was specified, fire it
		if ( s.error ) {
			s.error.call( s.context || window, xhr, status, e );
		}

		// Fire the global callback
		if ( s.global ) {
			(s.context ? jQuery(s.context) : jQuery.event).trigger( "ajaxError", [xhr, s, e] );
		}
	},

	// Counter for holding the number of active queries
	active: 0,

	// Determines if an XMLHttpRequest was successful or not
	httpSuccess: function( xhr ) {
		try {
			// IE error sometimes returns 1223 when it should be 204 so treat it as success, see #1450
			return !xhr.status && location.protocol === "file:" ||
				// Opera returns 0 when status is 304
				( xhr.status >= 200 && xhr.status < 300 ) ||
				xhr.status === 304 || xhr.status === 1223 || xhr.status === 0;
		} catch(e){}

		return false;
	},

	// Determines if an XMLHttpRequest returns NotModified
	httpNotModified: function( xhr, url ) {
		var lastModified = xhr.getResponseHeader("Last-Modified"),
			etag = xhr.getResponseHeader("Etag");

		if ( lastModified ) {
			jQuery.lastModified[url] = lastModified;
		}

		if ( etag ) {
			jQuery.etag[url] = etag;
		}

		// Opera returns 0 when status is 304
		return xhr.status === 304 || xhr.status === 0;
	},

	httpData: function( xhr, type, s ) {
		var ct = xhr.getResponseHeader("content-type"),
			xml = type === "xml" || !type && ct && ct.indexOf("xml") >= 0,
			data = xml ? xhr.responseXML : xhr.responseText;

		if ( xml && data.documentElement.nodeName === "parsererror" ) {
			throw "parsererror";
		}

		// Allow a pre-filtering function to sanitize the response
		// s is checked to keep backwards compatibility
		if ( s && s.dataFilter ) {
			data = s.dataFilter( data, type );
		}

		// The filter can actually parse the response
		if ( typeof data === "string" ) {

			// If the type is "script", eval it in global context
			if ( type === "script" ) {
				jQuery.globalEval( data );
			}

			// Get the JavaScript object, if JSON is used.
			if ( type === "json" ) {
				if ( typeof JSON === "object" && JSON.parse ) {
					data = JSON.parse( data );
				} else {
					data = (new Function("return " + data))();
				}
			}
		}

		return data;
	},

	// Serialize an array of form elements or a set of
	// key/values into a query string
	param: function( a ) {
		var s = [],
			param_traditional = jQuery.param.traditional;
		
		function add( key, value ){
			// If value is a function, invoke it and return its value
			value = jQuery.isFunction(value) ? value() : value;
			s[ s.length ] = encodeURIComponent(key) + '=' + encodeURIComponent(value);
		}
		
		// If an array was passed in, assume that it is an array
		// of form elements
		if ( jQuery.isArray(a) || a.jquery ) {
			// Serialize the form elements
			jQuery.each( a, function() {
				add( this.name, this.value );
			});
			
		} else {
			// Encode parameters from object, recursively. If
			// jQuery.param.traditional is set, encode the "old" way
			// (the way 1.3.2 or older did it)
			jQuery.each( a, function buildParams( prefix, obj ) {
				
				if ( jQuery.isArray(obj) ) {
					jQuery.each( obj, function(i,v){
						// Due to rails' limited request param syntax, numeric array
						// indices are not supported. To avoid serialization ambiguity
						// issues, serialized arrays can only contain scalar values. php
						// does not have this issue, but we should go with the lowest
						// common denominator
						add( prefix + ( param_traditional ? "" : "[]" ), v );
					});
					
				} else if ( typeof obj == "object" ) {
					if ( param_traditional ) {
						add( prefix, obj );
						
					} else {
						jQuery.each( obj, function(k,v){
							buildParams( prefix ? prefix + "[" + k + "]" : k, v );
						});
					}
				} else {
					add( prefix, obj );
				}
			});
		}
		// Return the resulting serialization
		return s.join("&").replace(r20, "+");
	}

});
var elemdisplay = {},
	timerId,
	fxAttrs = [
		// height animations
		[ "height", "marginTop", "marginBottom", "paddingTop", "paddingBottom" ],
		// width animations
		[ "width", "marginLeft", "marginRight", "paddingLeft", "paddingRight" ],
		// opacity animations
		[ "opacity" ]
	];

function genFx( type, num ){
	var obj = {};
	jQuery.each( fxAttrs.concat.apply([], fxAttrs.slice(0,num)), function(){
		obj[ this ] = type;
	});
	return obj;
}

jQuery.fn.extend({
	show: function( speed, callback ) {
		if ( speed != null ) {
			return this.animate( genFx("show", 3), speed, callback);
		} else {
			for ( var i = 0, l = this.length; i < l; i++ ){
				var old = jQuery.data(this[i], "olddisplay");

				this[i].style.display = old || "";

				if ( jQuery.css(this[i], "display") === "none" ) {
					var nodeName = this[i].nodeName, display;

					if ( elemdisplay[ nodeName ] ) {
						display = elemdisplay[ nodeName ];
					} else {
						var elem = jQuery("<" + nodeName + " />").appendTo("body");

						display = elem.css("display");
						if ( display === "none" ) {
							display = "block";
						}
						elem.remove();

						elemdisplay[ nodeName ] = display;
					}

					jQuery.data(this[i], "olddisplay", display);
				}
			}

			// Set the display of the elements in a second loop
			// to avoid the constant reflow
			for ( var i = 0, l = this.length; i < l; i++ ){
				this[i].style.display = jQuery.data(this[i], "olddisplay") || "";
			}

			return this;
		}
	},

	hide: function( speed, callback ) {
		if ( speed != null ) {
			return this.animate( genFx("hide", 3), speed, callback);
		} else {
			for ( var i = 0, l = this.length; i < l; i++ ){
				var old = jQuery.data(this[i], "olddisplay");
				if ( !old && old !== "none" ){
					jQuery.data(this[i], "olddisplay", jQuery.css(this[i], "display"));
				}
			}

			// Set the display of the elements in a second loop
			// to avoid the constant reflow
			for ( var i = 0, l = this.length; i < l; i++ ){
				this[i].style.display = "none";
			}

			return this;
		}
	},

	// Save the old toggle function
	_toggle: jQuery.fn.toggle,

	toggle: function( fn, fn2 ){
		var bool = typeof fn === "boolean";

		return jQuery.isFunction(fn) && jQuery.isFunction(fn2) ?
			this._toggle.apply( this, arguments ) :
			fn == null || bool ?
				this.each(function(){
					var state = bool ? fn : jQuery(this).is(":hidden");
					jQuery(this)[ state ? "show" : "hide" ]();
				}) :
				this.animate(genFx("toggle", 3), fn, fn2);
	},

	fadeTo: function(speed,to,callback){
		return this.filter(":hidden").css('opacity', 0).show().end()
					.animate({opacity: to}, speed, callback);
	},

	animate: function( prop, speed, easing, callback ) {
		var optall = jQuery.speed(speed, easing, callback);

		return this[ optall.queue === false ? "each" : "queue" ](function(){

			var opt = jQuery.extend({}, optall), p,
				hidden = this.nodeType == 1 && jQuery(this).is(":hidden"),
				self = this;

			for ( p in prop ) {
				var name = p.replace(rdashAlpha, fcamelCase);

				if ( p !== name ) {
					prop[ name ] = prop[ p ];
					delete prop[ p ];
					p = name;
				}

				if ( prop[p] == "hide" && hidden || prop[p] == "show" && !hidden ) {
					return opt.complete.call(this);
				}
				if ( ( p == "height" || p == "width" ) && this.style ) {
					// Store display property
					opt.display = jQuery.css(this, "display");

					// Make sure that nothing sneaks out
					opt.overflow = this.style.overflow;
				}
			}

			if ( opt.overflow != null ) {
				this.style.overflow = "hidden";
			}
			opt.curAnim = jQuery.extend({}, prop);

			jQuery.each( prop, function(name, val){
				var e = new jQuery.fx( self, opt, name );

				if ( /toggle|show|hide/.test(val) ) {
					e[ val == "toggle" ? hidden ? "show" : "hide" : val ]( prop );
				} else {
					var parts = /^([+-]=)?([\d+-.]+)(.*)$/.exec(val),
						start = e.cur(true) || 0;

					if ( parts ) {
						var end = parseFloat(parts[2]),
							unit = parts[3] || "px";

						// We need to compute starting value
						if ( unit != "px" ) {
							self.style[ name ] = (end || 1) + unit;
							start = ((end || 1) / e.cur(true)) * start;
							self.style[ name ] = start + unit;
						}

						// If a +=/-= token was provided, we're doing a relative animation
						if ( parts[1] ) {
							end = ((parts[1] == "-=" ? -1 : 1) * end) + start;
						}
						e.custom( start, end, unit );
					} else {
						e.custom( start, val, "" );
					}
				}
			});

			if ( jQuery.isEmptyObject( prop ) ) {
				return optall.complete.call(this);
			}

			// For JS strict compliance
			return true;
		});
	},

	stop: function(clearQueue, gotoEnd){
		var timers = jQuery.timers;

		if (clearQueue) {
			this.queue([]);
		}
		this.each(function(){
			// go in reverse order so anything added to the queue during the loop is ignored
			for ( var i = timers.length - 1; i >= 0; i-- ) {
				if ( timers[i].elem == this ) {
					if (gotoEnd) {
						// force the next step to be the last
						timers[i](true);
					}
					timers.splice(i, 1);
				}
			}
		});

		// start the next in the queue if the last step wasn't forced
		if (!gotoEnd) {
			this.dequeue();
		}
		return this;
	}

});

// Generate shortcuts for custom animations
jQuery.each({
	slideDown: genFx("show", 1),
	slideUp: genFx("hide", 1),
	slideToggle: genFx("toggle", 1),
	fadeIn: { opacity: "show" },
	fadeOut: { opacity: "hide" }
}, function( name, props ){
	jQuery.fn[ name ] = function( speed, callback ){
		return this.animate( props, speed, callback );
	};
});

jQuery.extend({

	speed: function(speed, easing, fn) {
		var opt = typeof speed === "object" ? speed : {
			complete: fn || !fn && easing ||
				jQuery.isFunction( speed ) && speed,
			duration: speed,
			easing: fn && easing || easing && !jQuery.isFunction(easing) && easing
		};

		opt.duration = jQuery.fx.off ? 0 : typeof opt.duration === "number" ? opt.duration :
			jQuery.fx.speeds[opt.duration] || jQuery.fx.speeds._default;

		// Queueing
		opt.old = opt.complete;
		opt.complete = function(){
			if ( opt.queue !== false ) {
				jQuery(this).dequeue();
			}
			if ( jQuery.isFunction( opt.old ) ) {
				opt.old.call( this );
			}
		};

		return opt;
	},

	easing: {
		linear: function( p, n, firstNum, diff ) {
			return firstNum + diff * p;
		},
		swing: function( p, n, firstNum, diff ) {
			return ((-Math.cos(p*Math.PI)/2) + 0.5) * diff + firstNum;
		}
	},

	timers: [],

	fx: function( elem, options, prop ){
		this.options = options;
		this.elem = elem;
		this.prop = prop;

		if ( !options.orig ) {
			options.orig = {};
		}
	}

});

jQuery.fx.prototype = {

	// Simple function for setting a style value
	update: function(){
		if ( this.options.step ) {
			this.options.step.call( this.elem, this.now, this );
		}
		(jQuery.fx.step[this.prop] || jQuery.fx.step._default)( this );

		// Set display property to block for height/width animations
		if ( ( this.prop == "height" || this.prop == "width" ) && this.elem.style ) {
			this.elem.style.display = "block";
		}
	},

	// Get the current size
	cur: function(force){
		if ( this.elem[this.prop] != null && (!this.elem.style || this.elem.style[this.prop] == null) ) {
			return this.elem[ this.prop ];
		}
		var r = parseFloat(jQuery.css(this.elem, this.prop, force));
		return r && r > -10000 ? r : parseFloat(jQuery.curCSS(this.elem, this.prop)) || 0;
	},

	// Start an animation from one number to another
	custom: function(from, to, unit){
		this.startTime = now();
		this.start = from;
		this.end = to;
		this.unit = unit || this.unit || "px";
		this.now = this.start;
		this.pos = this.state = 0;

		var self = this;
		function t(gotoEnd){
			return self.step(gotoEnd);
		}

		t.elem = this.elem;

		if ( t() && jQuery.timers.push(t) && !timerId ) {
			timerId = setInterval(jQuery.fx.tick, 13);
		}
	},

	// Simple 'show' function
	show: function(){
		// Remember where we started, so that we can go back to it later
		this.options.orig[this.prop] = jQuery.style( this.elem, this.prop );
		this.options.show = true;

		// Begin the animation
		// Make sure that we start at a small width/height to avoid any
		// flash of content
		this.custom(this.prop == "width" || this.prop == "height" ? 1 : 0, this.cur());

		// Start by showing the element
		jQuery(this.elem).show();
	},

	// Simple 'hide' function
	hide: function(){
		// Remember where we started, so that we can go back to it later
		this.options.orig[this.prop] = jQuery.style( this.elem, this.prop );
		this.options.hide = true;

		// Begin the animation
		this.custom(this.cur(), 0);
	},

	// Each step of an animation
	step: function(gotoEnd){
		var t = now();

		if ( gotoEnd || t >= this.options.duration + this.startTime ) {
			this.now = this.end;
			this.pos = this.state = 1;
			this.update();

			this.options.curAnim[ this.prop ] = true;

			var done = true;
			for ( var i in this.options.curAnim ) {
				if ( this.options.curAnim[i] !== true ) {
					done = false;
				}
			}
			if ( done ) {
				if ( this.options.display != null ) {
					// Reset the overflow
					this.elem.style.overflow = this.options.overflow;

					// Reset the display
					this.elem.style.display = this.options.display;
					if ( jQuery.css(this.elem, "display") == "none" ) {
						this.elem.style.display = "block";
					}
				}

				// Hide the element if the "hide" operation was done
				if ( this.options.hide ) {
					jQuery(this.elem).hide();
				}
				// Reset the properties, if the item has been hidden or shown
				if ( this.options.hide || this.options.show ){
					for ( var p in this.options.curAnim ) {
						jQuery.style(this.elem, p, this.options.orig[p]);
					}
				}
				// Execute the complete function
				this.options.complete.call( this.elem );
			}

			return false;
		} else {
			var n = t - this.startTime;
			this.state = n / this.options.duration;

			// Perform the easing function, defaults to swing
			this.pos = jQuery.easing[this.options.easing || (jQuery.easing.swing ? "swing" : "linear")](this.state, n, 0, 1, this.options.duration);
			this.now = this.start + ((this.end - this.start) * this.pos);

			// Perform the next step of the animation
			this.update();
		}

		return true;
	}

};

jQuery.extend( jQuery.fx, {

	tick:function(){
		var timers = jQuery.timers;

		for ( var i = 0; i < timers.length; i++ ) {
			if ( !timers[i]() ) {
				timers.splice(i--, 1);
			}
		}
		if ( !timers.length ) {
			jQuery.fx.stop();
		}
	},
		
	stop:function(){
		clearInterval( timerId );
		timerId = null;
	},
	
	speeds:{
		slow: 600,
 		fast: 200,
 		// Default speed
 		_default: 400
	},

	step: {

		opacity: function(fx){
			jQuery.style(fx.elem, "opacity", fx.now);
		},

		_default: function(fx){
			if ( fx.elem.style && fx.elem.style[ fx.prop ] != null ) {
				fx.elem.style[ fx.prop ] = fx.now + fx.unit;
			} else {
				fx.elem[ fx.prop ] = fx.now;
			}
		}
	}
});

if ( jQuery.expr && jQuery.expr.filters ) {
	jQuery.expr.filters.animated = function(elem){
		return jQuery.grep(jQuery.timers, function(fn){
			return elem === fn.elem;
		}).length;
	};
}
if ( "getBoundingClientRect" in document.documentElement ) {
	jQuery.fn.offset = function( options ) {
		var elem = this[0];
		if ( !elem || !elem.ownerDocument ) { return null; }
		if ( options ) { 
			return this.each(function() {
				jQuery.offset.setOffset( this, options );
			});
		}
		if ( elem === elem.ownerDocument.body ) {
			return jQuery.offset.bodyOffset( elem );
		}

		var box = elem.getBoundingClientRect(), doc = elem.ownerDocument, body = doc.body, docElem = doc.documentElement,
			clientTop = docElem.clientTop || body.clientTop || 0, clientLeft = docElem.clientLeft || body.clientLeft || 0,
			top  = box.top  + (self.pageYOffset || jQuery.support.boxModel && docElem.scrollTop  || body.scrollTop ) - clientTop,
			left = box.left + (self.pageXOffset || jQuery.support.boxModel && docElem.scrollLeft || body.scrollLeft) - clientLeft;
		return { top: top, left: left };
	};
} else {
	jQuery.fn.offset = function( options ) {
		var elem = this[0];
		if ( !elem || !elem.ownerDocument ) { return null; }
		if ( options ) { 
			return this.each(function() {
				jQuery.offset.setOffset( this, options );
			});
		}
		if ( elem === elem.ownerDocument.body ) {
			return jQuery.offset.bodyOffset( elem );
		}

		jQuery.offset.initialize();

		var offsetParent = elem.offsetParent, prevOffsetParent = elem,
			doc = elem.ownerDocument, computedStyle, docElem = doc.documentElement,
			body = doc.body, defaultView = doc.defaultView,
			prevComputedStyle = defaultView ? defaultView.getComputedStyle( elem, null ) : elem.currentStyle,
			top = elem.offsetTop, left = elem.offsetLeft;

		while ( (elem = elem.parentNode) && elem !== body && elem !== docElem ) {
			if ( jQuery.offset.supportsFixedPosition && prevComputedStyle.position === "fixed" ) { break; }

			computedStyle = defaultView ? defaultView.getComputedStyle(elem, null) : elem.currentStyle;
			top  -= elem.scrollTop;
			left -= elem.scrollLeft;

			if ( elem === offsetParent ) {
				top  += elem.offsetTop;
				left += elem.offsetLeft;

				if ( jQuery.offset.doesNotAddBorder && !(jQuery.offset.doesAddBorderForTableAndCells && /^t(able|d|h)$/i.test(elem.nodeName)) ) {
					top  += parseFloat( computedStyle.borderTopWidth  ) || 0;
					left += parseFloat( computedStyle.borderLeftWidth ) || 0;
				}

				prevOffsetParent = offsetParent, offsetParent = elem.offsetParent;
			}

			if ( jQuery.offset.subtractsBorderForOverflowNotVisible && computedStyle.overflow !== "visible" ) {
				top  += parseFloat( computedStyle.borderTopWidth  ) || 0;
				left += parseFloat( computedStyle.borderLeftWidth ) || 0;
			}

			prevComputedStyle = computedStyle;
		}

		if ( prevComputedStyle.position === "relative" || prevComputedStyle.position === "static" ) {
			top  += body.offsetTop;
			left += body.offsetLeft;
		}

		if ( jQuery.offset.supportsFixedPosition && prevComputedStyle.position === "fixed" ) {
			top  += Math.max( docElem.scrollTop, body.scrollTop );
			left += Math.max( docElem.scrollLeft, body.scrollLeft );
		}

		return { top: top, left: left };
	};
}

jQuery.offset = {
	initialize: function() {
		var body = document.body, container = document.createElement('div'), innerDiv, checkDiv, table, td, bodyMarginTop = parseFloat( jQuery.curCSS(body, 'marginTop', true) ) || 0,
			html = '<div style="position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;"><div></div></div><table style="position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;" cellpadding="0" cellspacing="0"><tr><td></td></tr></table>';

		jQuery.extend( container.style, { position: 'absolute', top: 0, left: 0, margin: 0, border: 0, width: '1px', height: '1px', visibility: 'hidden' } );

		container.innerHTML = html;
		body.insertBefore( container, body.firstChild );
		innerDiv = container.firstChild;
		checkDiv = innerDiv.firstChild;
		td = innerDiv.nextSibling.firstChild.firstChild;

		this.doesNotAddBorder = (checkDiv.offsetTop !== 5);
		this.doesAddBorderForTableAndCells = (td.offsetTop === 5);

		checkDiv.style.position = 'fixed', checkDiv.style.top = '20px';
		// safari subtracts parent border width here which is 5px
		this.supportsFixedPosition = (checkDiv.offsetTop === 20 || checkDiv.offsetTop === 15);
		checkDiv.style.position = checkDiv.style.top = '';

		innerDiv.style.overflow = 'hidden', innerDiv.style.position = 'relative';
		this.subtractsBorderForOverflowNotVisible = (checkDiv.offsetTop === -5);

		this.doesNotIncludeMarginInBodyOffset = (body.offsetTop !== bodyMarginTop);

		body.removeChild( container );
		body = container = innerDiv = checkDiv = table = td = null;
		jQuery.offset.initialize = function(){};
	},

	bodyOffset: function( body ) {
		var top = body.offsetTop, left = body.offsetLeft;

		jQuery.offset.initialize();

		if ( jQuery.offset.doesNotIncludeMarginInBodyOffset ) {
			top  += parseFloat( jQuery.curCSS(body, 'marginTop',  true) ) || 0;
			left += parseFloat( jQuery.curCSS(body, 'marginLeft', true) ) || 0;
		}

		return { top: top, left: left };
	},
	
	setOffset: function( elem, options ) {
		// set position first, in-case top/left are set even on static elem
		if ( /static/.test( jQuery.curCSS( elem, 'position' ) ) ) {
			elem.style.position = 'relative';
		}
		var curElem   = jQuery( elem ),
			curOffset = curElem.offset(),
			curTop    = parseInt( jQuery.curCSS( elem, 'top',  true ), 10 ) || 0,
			curLeft   = parseInt( jQuery.curCSS( elem, 'left', true ), 10)  || 0,
			props     = {
				top:  (options.top  - curOffset.top)  + curTop,
				left: (options.left - curOffset.left) + curLeft
			};
		
		if ( 'using' in options ) {
			options.using.call( elem, props );
		} else {
			curElem.css( props );
		}
	}
};


jQuery.fn.extend({
	position: function() {
		if ( !this[0] ) { return null; }

		var elem = this[0],

		// Get *real* offsetParent
		offsetParent = this.offsetParent(),

		// Get correct offsets
		offset       = this.offset(),
		parentOffset = /^body|html$/i.test(offsetParent[0].nodeName) ? { top: 0, left: 0 } : offsetParent.offset();

		// Subtract element margins
		// note: when an element has margin: auto the offsetLeft and marginLeft
		// are the same in Safari causing offset.left to incorrectly be 0
		offset.top  -= parseFloat( jQuery.curCSS(elem, 'marginTop',  true) ) || 0;
		offset.left -= parseFloat( jQuery.curCSS(elem, 'marginLeft', true) ) || 0;

		// Add offsetParent borders
		parentOffset.top  += parseFloat( jQuery.curCSS(offsetParent[0], 'borderTopWidth',  true) ) || 0;
		parentOffset.left += parseFloat( jQuery.curCSS(offsetParent[0], 'borderLeftWidth', true) ) || 0;

		// Subtract the two offsets
		return {
			top:  offset.top  - parentOffset.top,
			left: offset.left - parentOffset.left
		};
	},

	offsetParent: function() {
		return this.map(function(){
			var offsetParent = this.offsetParent || document.body;
			while ( offsetParent && (!/^body|html$/i.test(offsetParent.nodeName) && jQuery.css(offsetParent, 'position') === 'static') ) {
				offsetParent = offsetParent.offsetParent;
			}
			return offsetParent;
		});
	}
});


// Create scrollLeft and scrollTop methods
jQuery.each( ['Left', 'Top'], function(i, name) {
	var method = 'scroll' + name;

	jQuery.fn[ method ] = function(val) {
		var elem = this[0], win;
		
		if ( !elem ) { return null; }

		if ( val !== undefined ) {
			// Set the scroll offset
			return this.each(function() {
				win = getWindow( this );

				win ?
					win.scrollTo(
						!i ? val : jQuery(win).scrollLeft(),
						 i ? val : jQuery(win).scrollTop()
					) :
					this[ method ] = val;
			});
		} else {
			win = getWindow( elem );

			// Return the scroll offset
			return win ? ('pageXOffset' in win) ? win[ i ? 'pageYOffset' : 'pageXOffset' ] :
				jQuery.support.boxModel && win.document.documentElement[ method ] ||
					win.document.body[ method ] :
				elem[ method ];
		}
	};
});

function getWindow( elem ) {
	return ("scrollTo" in elem && elem.document) ?
		elem :
		elem.nodeType === 9 ?
			elem.defaultView || elem.parentWindow :
			false;
}
// Create innerHeight, innerWidth, outerHeight and outerWidth methods
jQuery.each([ "Height", "Width" ], function(i, name){

	var type = name.toLowerCase();

	// innerHeight and innerWidth
	jQuery.fn["inner" + name] = function(){
		return this[0] ?
			jQuery.css( this[0], type, false, "padding" ) :
			null;
	};

	// outerHeight and outerWidth
	jQuery.fn["outer" + name] = function(margin) {
		return this[0] ?
			jQuery.css( this[0], type, false, margin ? "margin" : "border" ) :
			null;
	};

	jQuery.fn[ type ] = function( size ) {
		// Get window width or height
		var elem = this[0];
		if ( !elem ) { return null; }
		return ("scrollTo" in elem && elem.document) ? // does it walk and quack like a window?
			// Everyone else use document.documentElement or document.body depending on Quirks vs Standards mode
			elem.document.compatMode === "CSS1Compat" && elem.document.documentElement[ "client" + name ] ||
			elem.document.body[ "client" + name ] :

			// Get document width or height
			(elem.nodeType === 9) ? // is it a document
				// Either scroll[Width/Height] or offset[Width/Height], whichever is greater
				Math.max(
					elem.documentElement["client" + name],
					elem.body["scroll" + name], elem.documentElement["scroll" + name],
					elem.body["offset" + name], elem.documentElement["offset" + name]
				) :

				// Get or set width or height on the element
				size === undefined ?
					// Get width or height on the element
					jQuery.css( elem, type ) :

					// Set the width or height on the element (default to pixels if value is unitless)
					this.css( type, typeof size === "string" ? size : size + "px" );
	};

});
// Expose jQuery to the global object
window.jQuery = window.$ = jQuery;

})(window);
powerpape

/***
|''Name:''|purpleTheme|
|''Description:''|A theme with lots of white space and a clean and elegant purple presentation|
|''Author:''|Saq Imtiaz and Simon McManus|
|''License:''|[[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]] |
|''Source''|http://svn.tiddlywiki.org/Trunk/association/serversides/cctiddly/Trunk/tiddlers/themes/purpleTheme.tiddler|
|''CodeRepository''|http://svn.tiddlywiki.org/Trunk/association/serversides/cctiddly/Trunk/tiddlers/themes/purpleTheme.tiddler|
|''~CoreVersion:''|2.4.1|
|''~PageTemplate:''|##PageTemplate|
|''~tabs:''|##tabs|
|''~OptionsPanel:''|##OptionsPanel|
|''~SideBarTabs:''|##SideBarTabs|
|''~StyleSheet:''|##StyleSheet|
|''~taskViewTemplate:''|##taskViewTemplate|
|''~taskEditTemplate:''|##taskEditTemplate|
|''~EditTemplate:''|##EditTemplate|.wizzz
|''~ViewTemplate:''|##ViewTemplate|
***/
!PageTemplate
<!--{{{-->
<div id='bodywrapper'>
<span class='siteTitle' refresh='content' tiddler='SiteTitle'></span>
<span class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'></span>
<div id='sidebar'>
<div id='sidebarOptions' refresh='content' force='true' tiddler='purpleTheme##SideBarOptions'></div>
</div>
<div id='displayArea'>
<div id='messageArea'></div>
<div id='tiddlerDisplay'></div>
</div>
<div id='contentFooter'  macro='gradient vert #eee #ccc'></div>
</div>
<!--}}}-->

!EditTemplate
<!--{{{-->
<div class='toolbar' macro='toolbar [[ToolbarCommands::EditToolbar]]'></div>
<div class='editor' macro='edit title'></div>
<div macro='annotations'></div>
<div class='editor' macro='edit text'></div>
<div class='editor' macro='edit tags'></div><div class='editorFooter'><span macro='message views.editor.tagPrompt'></span><span macro='tagChooser'></span></div>
<!--}}}-->

!ViewTemplate
<!--{{{-->
<div class='toolbar' macro='toolbar [[ToolbarCommands::ViewToolbar]]'></div>
<div class='title' macro='view title'></div>
<div class='viewer' macro='view text wikified'></div>
<div class='tagging' macro='tagging'></div>
<div class='tagged' macro='tags'></div>
<div class='tagClear'></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>
<hr />
<!--}}}-->

!tabs
<<tabs txtMainTab "Timeline" "Timeline" TabTimeline "All" "All tiddlers" TabAll "Tags" "All tags" TabTags "More" "More lists" TabMore>>


!SideBarOptions
<<search {{config.options.search}}>><<closeAll>><<newTiddler label:{{config.macros.newTiddler.label}} text:{{config.macros.newTiddler.text}} title:{{config.macros.newTiddler.title}} tag:"">
<<saveChanges>><<slider chkSliderOptionsPanel OptionsPanel  {{config.macros.ccOptions.options}} 'change TiddlyWiki Options'>><<slider 'chkLoginStatus' 'LoginStatus' {{config.macros.ccLoginStatus.status}} 'Login to make changes'>><<slider chkSliderTabs SideBarTabs {{config.theme.contentTitle}} {{config.theme.contentTiddlerTooltip}}>>

!StyleSheet
/***
General
***/
/*{{{*/

body, html{
	background-color: #999999;
	color:#333;
//	background:url(http://www.thefabricdeli.com/assets/images/qud21112-purple.jpg);
//	background:url(http://mr-pc.org/inc/paisleyTileSmall.png);
}

#backstageCloak {
	opacity:0.8; filter:'alpha(opacity:70)';
	background:black;
}
.tiddler .button {
	line-height:4;
	margin:5px;
	padding:8px;
}

body .chkOptionInput {
	width:auto;
	float:right;
}

#contentWrapper .wizard .txtOptionInput {
	width:7em;
}

.wizard  .txtOptionInput{
text-align:right;
	border:1px solid #ccc;
}

#contentWrapper .sliderPanel .tabsetWrapper .tabContents {
	border:0px;
	background-color:white;
}

.header {
	background-color:#eee;
}

#messageArea {
	border:1px solid white;
	background-color:#eee;
}

#messageArea .button {
	background:none;
}

h1 {
	color:black;
}

#contentWrapper {
	position:relative;
	margin: 2.5em auto;
	width:780px;
	line-height: 1.6em;
	border:1px solid #ccc;
	font-size: 11px;
	font-family: Lucida Grande, Tahoma, Arial, Helvetica, sans-serif;
	height:1%;
//	display:table;
	background-color:#eee;
}

.clearAll{
	clear:both;
}

.tagClear{
	clear:none;
}
/*}}}*/

/*{{{*/
.siteTitle {
	font-family: 'Trebuchet MS' sans-serif;
	font-weight: bold;
	position:relative;
	top:20px;
	left :20px;
	font-size: 32px;
	color:Purple;
}

.siteSubtitle {
	padding-top:15px;
	font-size: 1.0em;
	display:block;
	color: #999; margin-top:0.5em !important; margin-top:1em; margin-left:3em;
	padding-top:3em;
}

#displayArea {
	margin-left:1.35em;
	margin-right:16.3em;
	margin-top:0;
	padding-top:1em;
	padding-bottom:10px;
}

#sidebarOptions input {
	border:1px solid #ddd;
}

div.tabset {
	margin-bottom:1px;
}

.tabUnselected {
	background:#ddd none repeat scroll 0%;
	color:#999;
	border:1px solid #ccc;
}

#sidebar {
	position:inherit;
	float:right;
	display:inline;
}

#tiddlerDisplay .tagging, #tiddlerDisplay .tagged {
	background-color:#eee;
	border:none;
	float:none;
}

.sliderPanel .tabsetWrapper .tabContents {
	border-right:none;
	border-color:#999;
	background-color:#999;
}

#sidebarOptions .sliderPanel a {
	padding:3px;
	margin:0px;
	border:2px;
	background-color:#999;
}

.tabsetWrapper {
	position :relative;
}

#sidebar{
	padding-left:0.5em;
	background-color:#eee;
	padding-top:1em;
}

#sidebarOptions a {
	margin:17px;
	display:block;
	margin:0.5em 0em;
	padding:0.3em 0.6em;
}

.popup li a {
	margin:0px;
	padding:0px;
	display:inline;
	color:black;
}

.popup {
	background-color:white;
	border:1px solid purple;
}

.popup li a:hover {
	display:inline;
	margin:0px;
	padding:0px;
	background-color:white;
	color:purple;
}

.popup li {
	margin:0px;
	padding:5px;
	background-color:#eee;
}
.popup li:hover {
	background-color:white;
}

#tiddlerDisplay .toolbar a.button, #sidebarOptions a, .toolbar .popup li a, #mainMenu a, .tiddler .button, #sidebarOptions .sliderPanel input {
	border:1px solid white;
	background-color:white;
	color:purple;
}

#tiddlerDisplay .toolbar a.button:hover, #sidebarOptions a:hover,  #mainMenu a:hover, .tiddler .button, #sidebarOptions .sliderPanel input:hover
{
	border:1px solid #ccc;
}

#sidebarOptions a:hover {
border-right:1px solid white;
}

.tagged ul {
	list-style: none;
}

.tagged li {
	display: inline;
}

.zoomer {
	background:none; color:#ddd;
	border:2px solid #ddd;
}

a:active{
	border:1px solid red;
	background-color:#eee;
	color:[[ColorPalette::smmLight1]]
}

a:hover {
	background-color:#eee;
	color:[[ColorPalette::smmLight1]]
}

#backstageArea,#backstageArea a {
	background:transparent;
	color:white;
}

#mainMenu a {
	padding:8px 15px 8px 15px;
	margin:10px;
	line-height:40px;
	border:1px solid #eee;
}

#contentWrapper #mainMenu{
	position:static;
	width:100%;
	float:left;
	text-align:left;
	padding-top:20px;
}

.editor textarea, .editor input, input, body select {
	border:1px solid #ccc;
	background-color:white;
	color:#999;
	padding:3px;
	margin:3px;
}

#sidebarOptions input {
	width:85%;
	margin-left:-0.1em;}

#sidebarTabs {
	margin:0px;
	padding:0px
}

#sidebarTabs .tabContents {
	color:[[ColorPalette::smmLight1]];
	background:#999;
}

#contentWrapper .tiddler .button {
margin:0.4em;
padding:0.4em 0.8em;
}

#sideBarOptions .searchButton{
	display:none;
}

#sidebar .sliderPanel {
	margin-left:5px;
	border:0px;
	padding:0em;
	border-right:1px solid #eee;
	margin-bottom:0.8em;
}

#sidebarOptions .searchButton {
	display:none;
}

.title {
	color:#C0C0C0;
}

.subtitle, .subtitle a {
	color: #999;
	font-size: 1em;margin:0.2em;
	font-variant: small-caps;
}

* html .viewer pre {
	margin-left: 0em;
}

* html .editor textarea, * html .editor input {
	width: 98%;
}

a,#sidebarOptions .sliderPanel a, #topMenu a, #topMenu .button {
	color:purple;
	background-color:transparent;
}

#sidebarOptions .sliderPanel a:hover, #topMenu a, #topMenu .button:hover {
	color:black;
	background-color:transparent;
	border:0px;
}

 
#topMenu a, #topMenu .button {
	padding: 5px 15px;
	margin:9px;
	border:1px solid #999;
	font-weight:bold;
	line-height:40px;
	top:1em;
	color:[[ColorPalette::smmLight1]];
	background-color:#eee;
}

#topMenu br {
	display:none;
}

#topMenu a:hover, #topMenu .button:hover {
	background-color:#eee;
}

.tagging, .tagged {
	border: 0px dotted [[ColorPalette::smmLight1]];
}

.highlight, .marked {
	background:transparent;
	color:#999;
	border:none;
	text-decoration:underline;
}

.tagging .button:hover, .tagged .button:hover, .tagging .button:active, .tagged .button:active {
	border: none;
	background:transparent;
	text-decoration:underline;
	color:#eee;
}

.viewer th, thead td {
	background: #eee;
	border:none;
	color: #fff;
}

.viewer table {
	border:1px solid #eee;
}

table.twtable {
	border-collapse:seperate;
}

.viewer pre {
	background-color:white;
	border: 1px dotted #999;
}

hr {
	border: dotted 1px #ccc;
}

#sidebarOptions .sliderPanel .tabUnselected {
	background:#eee none repeat scroll 0%;
	border:0px solid #999;
	color:#999;
}

.tabSelected, #sidebarOptions .sliderPanel .tabSelected {
	background:white none repeat scroll 0%;
	border:1px solid #ddd;
	border-bottom:1px solid white;
	color:#999;
}

.tabContents {
	background:#f7f7f7;
	border:0px;
}

.viewer code {
	background:##eee none repeat scroll 0%;
	color:#999;
}

h1,h2,h3,h4,h5 {
	color: #555; 
	border-color:#333; 
	background: transparent; 
	padding-bottom:2px; 
	font-family: Arial, Helvetica, sans-serif;
}

h1 {
	font-size:18px;
}

h2 {
	font-size:16px;
	border-bottom:1px solid #FFF;
}

h3 {
	font-size: 14px;
	border-bottom:1px solid #FFF;
}

.annotation {
	background-color:purple;
	border:1px solid white;
	color:white;
}

#contentFooter {
	background:#999;
	clear: both;
	padding: 0.5em 1em;
}

.button, .wizard .button:hover {
	border:0px;
}

.sliderPanel input  {
	border:1px solid #777;
	background-color:white;
	color:#777;	
}

#contentWrapper .tiddler .button:hover {
	border:1px solid;
}

table, .viewer td, .viewer tr, .twtable td, .twtable tr {
	border:0px solid #666666;
}

body .wizardFooter {
	margin:0px;
	padding-top:0px;
	background:white;
	font-weight:bold;
	padding-left:10em;
}

.wizardStep {
	padding:0px;
	border:none;
	background-color:none;
} 
	
.wizard  th{
	background:white;
	color:#888;
	padding:3px;
	margin:40px;
};

.wizard, listView twtable {
	border:0px; 
};

.wizard {
	color:#292929;
}

.viewer .wizard, body .wizard{
	background:white;
	margin:2em;
	border:1px solid #CCCCCC;
	color:#999;
}

.wizard h1 {
	color:#999;
	padding-top:10px;
	padding-bottom:10px;
}

.wizard h2 {
	color:black;
}

body .wizardStep {
	color:#999;
	border:0px;
	margin:0m;
	background:white;	
}

body select {
	border:0px;
	padding:3px;
	margin:4px;
}

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

#backstagePanel {
	background:none;
	width:60%;
	position:fixed
	padding:0px;
	margin:0px;
	margin-top:-36px;
}

#backstageToolbar a.backstageSelTab {
	background-color:white;
	border:1px solid white;
}

#sidebar .sliderPanel {
	background-color:#eee;
	font-size:1em;
}

.viewer .wizardStep table {
	border:0px;
}

.viewer th, .viewer td, .viewer tr, .viewer caption, .twtable th, .twtable td, .twtable tr, .twtable caption {
	border:0px;
	padding:0px;
	margin:0px;
}

.viewer .sortable td {
	padding:12px;
	margin:21px;
}

.title {
	color:#777;
	padding:0px;
}

.viewer table, table.twtable {
	border-collapse:seperated;
	border:0px;
}

.viewer th, .viewer thead td, .twtable th, .twtable thead td {
	border:0px;
	background-color:white;
	color:black;
}

.twtable th{
	background-color:#eee;
	padding:15px;
	margin:15px;
}

table.sortable td.sortedCol {
	background-color:white;
}
/*}}}*/

[[StyleSheet]]
/***
|''Name:''|smmTheme|
|''Author:''|Saq Imtiaz and Simon McManus|
|''Source''|http://svn.tiddlywiki.org/Trunk/association/serversides/cctiddly/Trunk/tiddlers/themes/smmTheme.tiddler|
|''~CodeRepository:''|http://svn.tiddlywiki.org/Trunk/association/serversides/cctiddly/Trunk/tiddlers/themes/smmTheme.tiddler|
|''License:''|[[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]] |
|''~CoreVersion:''|2.4.1|
|''~PageTemplate:''|##PageTemplate|
|''~tabs:''|##tabs|
|''~OptionsPanel:''|##OptionsPanel|
|''~StyleSheet:''|##StyleSheet|
|''~taskViewTemplate:''|##taskViewTemplate|
|''~taskEditTemplate:''|##taskEditTemplate|
|''~EditTemplate:''|##EditTemplate|
|''~ViewTemplate:''|##ViewTemplate|
***/


!PageTemplate
<!--{{{-->
<div class='header' macro='gradient vert #111 #222'>
<span class='siteTitle' refresh='content' tiddler='SiteTitle'></span>
<span class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'></span><div id='mainMenu' refresh='content' tiddler='MainMenu'></div>
</div>
<div id='bodywrapper'>
<div id='sidebar'>
<div id='sidebarOptions' refresh='content' force='true' tiddler='smmTheme##SideBarOptions'></div>
</div>
<div id='displayArea'>
<div id='messageArea'></div>
<div id='tiddlerDisplay'></div>
</div>
<div id='contentFooter'  macro='gradient vert #222 #111'></div>
</div>
<!--}}}-->

!taskViewTemplate
<!--{{{-->
<div class='toolbar' macro='toolbar closeTiddler closeOthers +editTiddler > fields syncing permalink references jump'></div>
<div class='title' macro='view title'>Task : </div>
<div class='task'>
	<table>
	<tr>
		<td class='taskbody' width=100%><div class='viewer' macro='view text wikified'></div></td>
		<td class='taskControls' valign='top'><div class='taskControls' macro='tiddler TaskTiddlerControls'></td>
	</tr>
	</table>
</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='tagClear'></div>
<!--}}}-->

!taskEditTemplate
<!--{{{-->
<div class="editor">
<div class='toolbar' macro='toolbar[[ToolbarCommands::EditToolbar]]'></div>
<div class='title edit' macro='edit title'></div>
<div class='task'>
	<table>
	<tr>
		<td class='taskbody' width=100% height=100%><div class='viewer edit' macro='edit text wikified'></div></div></td>
		<td class='taskControls' valign=top><div class='taskControls' macro='tiddler TaskTiddlerControls'></td>
	</tr>
	</table>
</div>
<div class='subtitle'>Last edited by: <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='editor' macro='edit tags'></div><div class='editorFooter'><span macro='message views.editor.tagPrompt'></span><span macro='tagChooser'></span></div>
<div class='tagClear'></div>
</div>
<!--}}}-->

!EditTemplate
<!--{{{-->
<div class='toolbar' macro='toolbar [[ToolbarCommands::EditToolbar]]'></div>
<div class='editor' macro='edit title'></div>
<div macro='annotations'></div>
<div class='editor' macro='edit text'></div>
<div class='editor' macro='edit tags'></div><div class='editorFooter'><span macro='message views.editor.tagPrompt'></span><span macro='tagChooser'></span></div>
<!--}}}-->

!ViewTemplate
<!--{{{-->
<div class='toolbar' macro='toolbar [[ToolbarCommands::ViewToolbar]]'></div>
<div class='title' macro='view title'></div>
<div class='viewer' macro='view text wikified'></div>
<div class='subtitle'>Last edited by: <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='tagClear'></div>
<!--}}}-->

!wizardViewTemplate
<!--{{{-->
<div class='toolbar' macro='toolbar closeTiddler closeOthers'></div>
<div class='viewer' macro='view text wikified'></div>
<div class='tagClear'></div>
<!--}}}-->
!OptionsPanel
[[help|Help]] <br />[[settings|AdvancedOptions]]<br /><<ccOptions>>

!tabs
<<tabs txtMainTab "Timeline" "Timeline" TabTimeline "All" "All tiddlers" TabAll "Tags" "All tags" TabTags "More" "More lists" TabMore>>

!SideBarOptions
<<search {{config.options.search}}>><<closeAll>><<newTiddler label:{{config.macros.newTiddler.label}} text:{{config.macros.newTiddler.text}} title:{{config.macros.newTiddler.title}} tag:"">
<<saveChanges>><<slider chkSliderOptionsPanel OptionsPanel  {{config.macros.ccOptions.options}} 'change TiddlyWiki Options'>><<slider 'chkLoginStatus' 'LoginStatus' {{config.macros.ccLoginStatus.status}} 'Login to make changes'>><<slider chkSliderTabs SideBarTabs {{config.theme.contentTiddler}} {{config.theme.contentTiddlerTooltip}}>>


!StyleSheet
/***
General
***/
/*{{{*/
.tiddler .button:hover {
	background-color:#222;
}
.tiddler .button {
	border:1px solid black;
	line-height:2;
	margin:5px;
	padding:8px;
}

#contentWrapper .tiddler .button {
	margin-left:20px;
}
body .chkOptionInput {
	width:auto;
	float:right;
}

#contentWrapper .wizard .txtOptionInput {
	width:7em;
}

body{
	background: #111;
	color:white;
//	 background-image:url(http://friendster.bigoo.ws/content/layout/film-cartoon/film-cartoon_111.jpg);
//	 background-image:url(http://g.editingmyspace.com/shay773/halloweenbackgrounds/BG1.gif);
}

#backstageCloak {
	opacity:0.9; filter:'alpha(opacity:90)';
	background:#222;
}

#messageArea {
	border:0px;
	color:white;
	background-color:#222;
}

#messageArea .button{
	background:none;
}

#mainMenu br {
	display:none;
}

h1 {
	color:white;
}

#contentWrapper{
	position:relative;
	margin: 2.5em auto;
	width:780px;
	line-height: 1.6em;
	border:1px solid #111;
	font-size: 11px;
	font-family: Lucida Grande, Tahoma, Arial, Helvetica, sans-serif;
	height:1%;
	background-color:#222;
}

.clearAll{
	clear:both;
}

.tagClear{
	clear:none;
}
/*}}}*/

/*{{{*/

.siteTitle {
	font-family: 'Trebuchet MS' sans-serif;
	font-weight: bold;
	position:relative;
	top:20px;
	left :20px;
	font-size: 32px;
	color:#eee;
}

.siteSubtitle {
	padding-top:15px;
	font-size: 1.0em;
	display:block; 
	color: #999; margin-top:0.5em !important; margin-top:1em; margin-left:3em;
}

#displayArea {
	margin-left:1.35em;
	margin-right:16.3em;
	margin-top:0;
	padding-top:1em;
	padding-bottom:10px;
}

.tabUnselected {
	background:#222 none repeat scroll 0%;
	color:#999;
}

#sidebar {
	position:inherit;
	float:right;
	display:inline;
}

#tiddlerDisplay .tagging, #tiddlerDisplay .tagged {
	background-color:#222;
	border:none;
	float:none;
}

.sliderPanel .tabsetWrapper .tabContents {
	border-right:none;
	border-color:#999;
	background-color:#111;
}

#sidebarOptions .sliderPanel a{
	padding:3px;
	margin:0px;
	border:2px;
	background-color:#111;
}

.tabsetWrapper {
	position :relative;
}

#sidebar {
	padding-left:0.5em;
	background-color:#222;
	padding-top:1em;
}

#sidebarOptions a {
	margin:17px;
	display:block;
	margin:0.5em 0em;
	padding:0.3em 0.6em;
}

.popup li a {
	padding:12px;
}

#tiddlerDisplay .toolbar a.button, #sidebarOptions a, .toolbar .popup li a, #mainMenu a, #sidebarOptions .sliderPanel input {
	background-color:#111;
	color:#999;
	border:1px solid #111;
}

.wizard  .txtOptionInput {
	text-align:right;
}

a:hover {
	background-color:#222;
	color:#eee
}

#tiddlerDisplay .toolbar a.button:hover, #sidebarOptions a:hover, #mainMenu a:hover, #sidebarOptions .sliderPanel input:hover {
	border:1px dotted #000;
	background-color:#222;
	color:white;
}

#mainMenu a {
	padding:8px 15px 8px 15px;
	margin:10px;
	line-height:40px;
	border:0px solid #eee;
}

#contentWrapper #mainMenu { 
	position:static;
	width:100%;
	float:left;
	text-align:left;
	padding-top:20px;

}
.editor textarea, .editor input,  input, body select {
	border:1px solid #222;
	background-color:#333;
	color:#999;
	padding:3px;
	margin:3px;
}

#sidebarOptions input {
	border:1px solid #999;
	background-color:#00000;
	width:10em;
}

#sidebarTabs {
	margin:0px;
	padding:0px
}

#sidebarTabs .tabContents {
	color:#eee;
	background:#111;
}
.tagged li
{
	display: inline;
}

.tiddler .button {
	color:white;
	padding:0.4em 0.9em 0.4em 0.9em;
	margin:0px 0px 0px 7px;
}

#sideBarOptions .searchButton {
	display:none;
}

#sidebar .sliderPanel {
	border-color:-moz-use-text-color #222 -moz-use-text-color -moz-use-text-color;
	border-style:none solid none none;
	border-width:0 1px 0 0;
	margin-bottom:0.8em;
	margin-left:5px;
	padding:0;
	margin-left:0px;
}

#sidebarOptions .searchButton {
	display:none;
}

.title {
	color:#C0C0C0;
}

.subtitle, .subtitle a {
	color: #999;
	font-size: 1em;margin:0.2em;
	font-variant: small-caps;
}

.wizard .button:hover{
	background-color:#333;
	border:1px solid #444;
	color:white;
}
.selected .toolbar a {
	color:#999;
}

.selected .toolbar a:hover {
	color:#222;
	background:transparent;
	border:1px solid #fff;
}

.viewer pre {
	background:#111111 none repeat scroll 0 0;
	border:1px solid #FFEE88;
}

* html .viewer pre {
	margin-left: 0em;
}

* html .editor textarea, * html .editor input {
	width: 98%;
}

a,#sidebarOptions .sliderPanel a, #topMenu a, #topMenu .button {
	color:green;
	background-color:transparent;
}

#sidebarOptions .sliderPanel a:hover, #topMenu a, #topMenu .button:hover {
	color:white;
	background-color:transparent;
	border:0px;
}

#topMenu a, #topMenu .button, .wizard .button {
	padding: 5px 15px;
	margin:9px;
	border:1px solid #999;
	font-weight:bold;
	line-height:40px;
	top:1em;
	color:#eee;
	background-color:#222;
}

#topMenu br {
	display:none;
}

#topMenu a:hover, #topMenu .button:hover {
	background-color:#222;
}

.tagging, .tagged {
	border: 1px solid #eee;
}

.highlight, .marked {
	background:transparent;
	color:#111;
	border:none;
	text-decoration:underline;
}

.tagging .button:hover, .tagged .button:hover, .tagging .button:active, .tagged .button:active {
	border: none;
	background:transparent;
	text-decoration:underline;
	color:#222;
}

.tiddler {
	padding-bottom: 40px;
}

.viewer th, thead td {
	background: #222;
	border:none;
	color: #fff;
}

.viewer table {
	border:1px dotted #222;
}

table.twtable {
	border-collapse:seperate;
}

.viewer pre {
	border: 1px solid #999;
}

.viewer hr {
	border-top: dashed 1px #999;
}

.tabSelected {
	background:#111 none repeat scroll 0%;
	border:1px solid #111;
	border-bottom:1px solid black;
	color:#999;
}

.tabContents {
	background:#f7f7f7;
	border:0px;
}

.viewer code {
	background:##222 none repeat scroll 0%;
color:#999;
}

h1,h2,h3,h4,h5 {
	color: #555; border-color:#333; background: transparent; padding-bottom:2px; font-family: Arial, Helvetica, sans-serif;
}

h1 {
	font-size:18px;
}

h2 {
	font-size:16px;
}

h3 {
	font-size: 14px;
}

#contentFooter {
	background:#999;
	clear: both;
	padding: 0.5em 1em;
}

.wizard input {
	border:1px solid #333;
}
#sidebarOptions input {
	border: 1px solid #222;
}

.annotation {
	background-color:green;
	border:1px solid white;
	color:white;
}

.wizardFooter .button{
	background:#222;
	margin:3px;
	padding:0.5em;
	padding-left:1.5em;
	padding-right:1.5em;
	color:white;
	border:1px solid #333;
}
table, .viewer td, .viewer tr, .twtable td, .twtable tr {
	border:0px solid #666666;
}

.tagging .listTitle, .tagged .listTitle, .txtMainTab .tabContents li {
	color:white;
}

body .wizardFooter {
	background:none;
	font-weight:bold;}

.wizardStep {
	border:none;
	background-color:none;
}

body .wizard {
	width:80%;
	padding:10px;
	border:1px solid #EBE6F5;
}

.wizard  th{
	background:#222;
	color:#888;
	padding:3px;
	margin:40px;
};

.wizard, listView twtable {
	border:0px;
};

.wizard {
	padding : 4px 14px 4px 14px;
	font-weight:bold;
	color:#292929;
	border:solid 0px #292929;
	margin-top:1px;
}

.viewer .wizard, body .wizard{
	background:#111;
	margin:2em;
	border:0px;
	border:1px solid #333;
	color:#777;
}

.wizard h1{
	color:#999;
}

.wizard h2{
	padding:4px;
	color:white;
}

body .wizardStep{
	color:#999;
	border:0px;
	margin:0m;
	background:none;
}

body select {
	border:0px;
	padding:3px;
	margin:4px;
}

#backstagePanel {
	border:0px;
	background:none;
	width:60%;
	position:fixed
	padding:0px;
	margin:0px;
	margin-top:-36px;
}

#sidebar .sliderPanel {
	background-color:#222;
	font-size:1em;
}

.viewer .wizardStep table {
	border:0px;
}

.viewer th, .viewer td, .viewer tr, .viewer caption, .twtable th, .twtable td, .twtable tr, .twtable caption {
	border:0px;
	padding:0px;
	margin:0px;
}

.viewer .sortable td  {
	padding:12px;
	margin:21px;
}

.title {
	color:#C0C0C0;
	padding:10px;
}

.viewer table, table.twtable {
	border-collapse:seperated;
	border:0px;
}

.viewer th, .viewer thead td, .twtable th, .twtable thead td {
	border:0px;
	color:white;
}

.twtable th{
	background-color:#333;
	padding:15px;
	margin:15px;
}

table.sortable td.sortedCol {
	background-color:#333;
}

#backstageArea a:hover, #backstageArea a.backstageSelTab {
	background-color:#111;
	color:white;
}
/*}}}*/

[[StyleSheet]]
powerpape
merge(config.options, {search:"search.."})


config.theme = {
	contentTitle : ' ssss »',
	contentToolTip : 'aaaa',
	contentTiddler : 'Content »',
	contentTiddlerTooltip : 'click to view TiddlyWiki content'
};
merge(config.macros.ccAbout,{
	buttonBackstageText:"about",
	buttonBackstageTooltip:"Find out more about ccTiddly ",
	stepAboutTitle:"About",
	stepAboutTextStart:"You are running ccTiddly ",
	stepAboutTextEnd:"More info about ccTiddly can be found  at <a  target=new href=http://www.tiddlywiki.org/wiki/CcTiddly>http://www.tiddlywiki.org/wiki/CcTiddly</a><br/><br/>  More information about TiddlyWiki can be found at <a target=new href=http://www.tiddlywiki.com>http://www.tiddlywiki.com</a><br/>"
});

merge(config.macros.ccChangePassword,{
	title:"Change Password", 
	subTitle : "for user ", 
	step1Html: " <label for='old'>Old Password </label><input name='old' type='password'/><br/> <label for='new1'>New Password </label> <input  name='new1' type='password' /><br /><label for='new2'>Repeat Password</label> <input  name='new2' type='password' /> ",   
	buttonChangeText:"Change Password",
	buttonChangeToolTip:"Click to change your password", 
	buttonCancelText:"Cancel",
	buttonCancelToolTip:"Click to cancel",
	noticePasswordsNoMatch : "Your new passwords do not match", 
	noticePasswordWrong : "Your password is incorrect.",
	noticePasswordUpdated : "Your Password has been updated", 
	noticePasswordUpdateFailed : "Your Password was NOT updated." 
});

merge(config.macros.ccAdmin,{
	stepAddTitle:"Add a new Workspace Administrator",
	WizardTitleText:"Workspace Administration.",
	buttonDeleteText:"Delete Users",
	buttonDeleteTooltip:"Click to delete users.",
	buttonAddText:"Add User",
	buttonAddTooltip:"Click to add user.",
	buttonCancelText:"Cancel",
	buttonCalcelTooltip:"Calcel adding user.",
	buttonCreateText:"Make User Admin",
	buttonCreateTooltip:"Click to make user admin.",
	labelWorkspace:"Workspace: ",
	labelUsername:"Username  : ",
	stepErrorTitle:"You need to be an administrator of this workspace.",
	stepErrorText:"Permission Denied to edit workspace : ",
	stepNoAdminTitle:"There are no admins of this workspace.",
	stepManageWorkspaceTitle:"",
	listAdminTemplate: {
	columns: [	
		{name: 'Selected', field: 'Selected', rowName: 'name', type: 'Selector'},
		{name: 'Name', field: 'name', title: "Username", type: 'String'},	
		{name: 'Last Visit', field: 'lastVisit', title: "Last Login", type: 'String'}
	],
	rowClasses: [
		{className: 'lowlight', field: 'lowlight'}
	]}
});
/*
merge(ccTiddlyAutoSave,{
	msgSaved:"Saved ",
	msgError:"There was an error saving "
});
*/

merge(config.macros.ccCreateWorkspace, {
	wizardTitle:"Create Workspace",
	buttonCreateText:"create",
	buttonCreateWorkspaceText:"Create Workspace",
	buttonCreateTooltip:'Create new workspace',
	errorPermissions:"You do not have permissions to create a workspace.  You may need to log in.",
	msgPleaseWait:"Please wait, your workspace is being created.",
	msgWorkspaceAvailable:"Workspace name is available.",
	errorWorkspaceNameInUse:"Workspace name is already in use.",
	stepTitle:"Please enter workspace name",
	stepCreateHtml:"<input class='input' id='workspace_name' name='workspace_name' value='' tabindex='1' /><span></span><input type='hidden' name='workspace_error'></input><h2></h2><input type='hidden' name='workspace_url'></input>"
});

merge(config.macros.ccEditWorkspace,{
	WizardTitleText:"Edit Workspace Permissions",
	stepEditTitle:null,
	stepLabelCreate:'Create',
	stepLabelRead:'Read',
	stepLabelUpdate:'Edit',
	stepLabelDelete:'Delete',
	stepLabelPermission:'',
	stepLabelAnon:'  Anonymous   ',
	stepLabelUser:' Authenticated   ',
	stepLabelAdmin:' Admin  ',
	buttonSubmitCaption:"Update Workspace Permissions",
	buttonSubmitToolTip:"Update workspace permissions",
	button1SubmitCaption:"ok",
	button1SubmitToolTip:"review permissions",
	step2Error:"Error", 
	errorTextPermissionDenied:"You do not have permissions to edit this workspace permissions.  You may need to log in.",
	errorUpdateFailed:"Permissions Not changed"
});

merge(config.macros.ccFile,{
	wizardTitleText:"Manage Files",
	wizardStepText:"Manage files in workspace ",
	buttonDeleteText:"Delete Files",
	buttonDeleteTooltip:"Click to Delete files.",
	buttonUploadText:"Upload File",
	buttonUploadTooltip:"Click to Upload files.",
	buttonCancelText:"Cancel",
	buttonCancelTooltip:"Click to cancel.",
	labelFiles:"Existing Files ",
	errorPermissionDeniedTitle:"Permission Denied",
	errorPermissionDeniedUpload:"You do not have permissions to create a file on this server. ",
	errorPermissionDeniedView:"You do not have permissions to view files in this workspace. ",
	listAdminTemplate: {
	columns: [	
	{name: 'wiki text', field: 'wikiText', title: "", type: 'WikiText'},
	{name: 'Selected', field: 'Selected', rowName: 'name', type: 'Selector'},
	{name: 'Name', field: 'name', title: "File", type: 'WikiText'},
	{name: 'URI', field: 'URI', title: "URI", type: 'WikiText'},
	{name: 'Size', field: 'fileSize', title: "size", type: 'String'}
	],
	rowClasses: [
	{className: 'lowlight', field: 'lowlight'}
	]}
});

merge(config.macros.ccLogin,{
	WizardTitleText:null,
	usernameRequest:"Username",
	passwordRequest:"Password",
	stepLoginTitle:null,
	stepLoginIntroTextHtml:"<label>username</label><input name=username id=username tabindex='1'><br /><label>password</label><input type='password' tabindex='2' name='txtPassword' class='txtPassword'><input   name='password'>",
	stepDoLoginTitle:"Logging you in",
	stepDoLoginIntroText:"we are currently trying to log you in.... ",
	stepForgotPasswordTitle:"Password Request",
	stepForgotPasswordIntroText:"Please contact your system administrator or register for a new account.  <br /><input id='forgottenPassword' type='hidden' name='forgottenPassword'/>",
	stepLogoutTitle:"Logout",
	stepLogoutText:"You are currently logged in as ",
	buttonLogout:"logout",
	buttonLogoutToolTip:"Click here to logout.",
	buttonLogin:"Login",
	buttonlogin:"login",
	buttonLoginToolTip:"Click to Login.",	
	buttonCancel:"Cancel",
	buttonCancelToolTip:"Cancel transaction ",
	buttonForgottenPassword:"Forgotten Password",	
	buttonSendForgottenPassword:"Mail me a New Password",
	buttonSendForgottenPasswordToolTip:"Click here if you have forgotten your password",
	buttonForgottenPasswordToolTip:"Click to be reminded of your password",
	msgNoUsername:"Please enter a username", 
	msgNoPassword:"Please enter a password",
	msgLoginFailed:"Login Failed, please try again. ", 
	configURL:window.url+"/handle/login.php", 
	configUsernameInputName:"cctuser",
	configPasswordInputName:"cctpass",
	configPasswordCookieName:"cctPass"
});

merge(config.macros.ccLoginStatus,{
	textDefaultWorkspaceLoggedIn:"Viewing default workspace",
	textViewingWorkspace:"Viewing Workspace : ",
	textLoggedInAs:"Logged in as ",
	status:"status »",
	textNotLoggedIn:"You are not logged in.",
	textAdmin:"You are an Administrator."
});

merge(config.macros.ccOptions, {
	linkManageUsers:"users",
	linkPermissions:"permissions",
	linkFiles:"files",
	linkPassword:"password",
	linkCreate:"create",
	linkOffline:"offline",
	linkStats:"statistics",
	options:"options »"	
});

merge(config.macros.register,{
	usernameRequest:"username",
	passwordRequest:"password",
	passwordConfirmationRequest:"confirm password",
	emailRequest:"email",
	stepRegisterTitle:"Register for an account.",
	stepRegisterIntroText:"Hi, please register below.... ",
	stepRegisterHtml:"<label> username</label><input class='input' id='reg_username' name='reg_username' tabindex='1'/><span></span><input type='hidden'  name='username_error'></input><br /><label>email</label><input class='input' name=reg_mail id='reg_mail' tabindex='2'/><span> </span><input type='hidden' name='mail_error'></input><br/><label>password</label><input type='password' class='input' id='password1' name='reg_password1' tabindex='3'/><span> </span><input type='hidden'  name='pass1_error'></input><br/><label>confirm password</label><input type='password' class='input' id='password2' name='reg_password2' tabindex='4'/><span> </span><input type='hidden'  name='pass2_error'></input>",
	buttonCancel:"Cancel",
	buttonCancelToolTip:"Cancel transaction ",
	buttonRegister:"Register",	
	buttonRegisterToolTip:"click to register",
	msgCreatingAccount:"Attempting to create the account for you.", 
	msgNoUsername:"No username entered", 
	msgEmailOk:"Email address is OK.",
	msgNoPassword:"no password entered.",
	msgDifferentPasswords:"Your Passwords do not match.",
	msgUsernameTaken:"The username requested has been taken.",
	msgUsernameAvailable:"The username is available.",
	step2Title:"",
	step2Html:"Please wait while we create you an account...",
	errorRegisterTitle:"Error",
	errorRegister:"User not created, please try again with a different username."
});

merge(config.macros.ccStats,{
	graph24HourTitle:"Last 24 hours",
	graph24HourDesc:"The number of views of this workspace in the past 24 hours",
	graph20MinsTitle:"Last 20 Minutes",
	graph20MinsDesc:"The number of views of this workspace in the last 20 minutes",
	graph7DaysTitle:"Last 7 days",
	graph7DaysDesc:"The number of views of this workspace in the last 7 days.",
	graph5MonthsTitle:"Last 5 months",
	graph5MonthsDesc:"The number of views of this workspace in the past 30 days.",
	errorPermissionDenied:"Permissions Denied to data for %0 You need to be an administrator on the %1 workspace.",
	stepTitle:"Workspace Statistics"
});


// GENERAL NON CCT CONTENT 

config.theme = {
	contentTitle:"content »",
	contentToolTip : "View the TiddlyWiki tabs",
	help : "Help"
};

merge(config.macros.importTiddlers, {
	wizardTitle: "Import tiddlers",
	step1Title: "Step 1: Locate the server or TiddlyWiki file",
	step1Html: "Specify the type of the server: <select name='selTypes'><option value=''>Choose...</option></select><br>Enter the URL here: <input type='text' size=50 name='txtPath'><br><input type='hidden' size=50 name='txtBrowse'><br><hr>...or select a pre-defined feed: <select name='selFeeds'><option value=''>Choose...</option></select>"
});

merge(config.optionsDesc,{
	txtUserName: "",
	chkRegExpSearch: "Enable regular expressions for searches",
	chkCaseSensitiveSearch: "Case-sensitive searching",
	chkIncrementalSearch: "Incremental key-by-key searching",
	chkAnimate: "Enable animations",
	chkSaveBackups: "",
	chkAutoSave: "",
	txtTheme: "Change the TiddlyWiki theme being used",
	chkGenerateAnRssFeed: "",
	chkSaveEmptyTemplate: "",
	chkOpenInNewWindow: "Open external links in a new window",
	chkToggleLinks: "Clicking on links to open tiddlers causes them to close",
	chkHttpReadOnly: "",
	chkForceMinorUpdate: "",
	chkConfirmDelete: "Require confirmation before deleting tiddlers",
	chkInsertTabs: "Use the tab key to insert tab characters instead of moving between fields",
	txtBackupFolder: "",
	txtMaxEditRows: "Maximum number of rows in edit boxes",
	txtFileSystemCharSet: "Default character set for saving changes (Firefox/Mozilla only)"});

merge(config.macros.options,{
	wizardTitle: "Change Settings",
	step1Title: "",
	step1Html: '<input type="hidden" name="markList"></input><br><input type="hidden" checked="false" name="chkUnknown"></input>These options are saved in a cookie.'
});

merge(config.macros.options,{
	wizardTitle:"Advanced settings",
	step1Title:null,
		unknownDescription: "//(unknown)//",
	listViewTemplate: {
		columns: [
			{name: 'Option', field: 'option', title: "", type: 'String'},
			{name: 'Description', field: 'description', title: "", type: 'WikiText'}
			],
			rowClasses: [
						{className: 'lowlight', field: 'lowlight'}
						]
}
});
config.macros.OpenID={};
merge(config.macros.OpenID,{
	titleOpenID:"",
	buttonOpenIDText:"Login",
	buttonOpenIDToolTip:"Click to use OpenID Login" 
});

config.macros.OpenID.handler=function(place,macroName,params,wikifier,paramString,tiddler,errorMsg){
	var w = new Wizard();
	var me = config.macros.OpenID;
	w.createWizard(place,me.titleOpenID);
	w.addStep(null,"<!--<img width='150px' src='http://openid.net/wp-content/uploads/2007/10/openid_big_logo_text.png'/><br />--><input name='open_id_login' value='%0' size=40 style='background: rgb(255, 255, 255) url(http://www.openid.net/login-bg.gif) no-repeat scroll 0pt 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: rgb(0, 0, 0); padding-left: 18px;'/>".format([decodeURIComponent(cookieString(document.cookie).txtUserName)]));
	w.setButtons([
		{caption: me.buttonOpenIDText, tooltip: me.buttonOpenIDToolTip, onClick: function(){config.macros.OpenID.login(w);  } }
	]);
};

config.macros.OpenID.login = function (w) {
	var iframe = document.createElement("iframe");
	iframe.style.display = "none";
	iframe.src = url+"plugins/OpenID/files/openid/try_auth.php?action=verify&openid_identifier="+w.formElem.open_id_login.value;
	document.body.appendChild(iframe);
	iframe.onload = function() {
		// this is not working properly.
		if(iframe.src.indexOf("finish_auth.php")){
			window.location = iframe.src;	
		}
	};
	document.body.appendChild(iframe);
}

//}}}


<<OpenID>>
<link rel='alternate' type='application/rss+xml' title='RSS Feed for ccTiddly workspace : ' href='http://www.andreanis.de/_tiddlyindex.xml'/>
/***
|''Name:''|TagsTreePlugin|
|''Description:''|Displays tags hierachy as a tree of tagged tiddlers.<br>Can be used to create dynamic outline navigation.|
|''Version:''|1.0.1|
|''Date:''|Jan 04,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|
!Demo
On the plugin [[homepage|http://visualtw.ouvaton.org/VisualTW.html]] :
*Try to tag some <<newTiddler>> with a tag displayed in the menu and edit MainMenu.
*Look at some tags like [[Plugins]] or [[menu]].
!Installation
#import the plugin,
#save and reload,
#optionally, edit TagsTreeStyleSheet.
! Usage
{{{<<tagsTree>>}}} macro accepts the following //optional// parameters.
|!#|!parameter|!description|!by default|
|1|{{{root}}}|Uses {{{root}}} tag as tree root|- In a //tiddler// content or template : uses the tiddler as root tag.<br>- In the //page// content or template (by ex MainMenu) : displays all untagged tags.|
|2|{{{excludeTag}}}|Excludes all such tagged tiddlers from the tree|Uses default excludeLists tag|
|3|{{{level}}}|Expands nodes until level {{{level}}}.<br>Value {{{0}}} hides expand/collapse buttons.|Nodes are collapsed on first level|
|4|{{{depth}}}|Hierachy depth|6 levels depth (H1 to H6 header styles)|
|5|{{{sortField}}}|Alternate sort field. By example : "index".|Sorts tags and tiddlers alphabetically (on their title)|
|6|{{{labelField}}}|Alertnate label field. By example : "label".|Displays tiddler's title|

!Useful addons
*[[FieldsEditorPlugin]] : //create//, //edit//, //view// and //delete// commands in toolbar <<toolbar fields>>.
*[[TaggerPlugin]] : Provides a drop down listing current tiddler tags, and allowing toggling of tags.
!Advanced Users
You can change the global defaults for TagsTreePlugin, like default {{{level}}} value or level styles, by editing or overriding the first config.macros.tagsTree attributes below.
!Code
***/
//{{{
config.macros.tagsTree = {
	expand : "+",
	collapse : "–",
	depth : 6,
	level : 1,
	sortField : "",	
	labelField : "",
	styles : ["h1","h2","h3","h4","h5","h6"],
	trees : {}
}

config.macros.tagsTree.handler = function(place,macroName,params,wikifier,paramString,tiddler)
{
	var root = params[0] ? params[0] : (tiddler ? tiddler.title : null);
	var excludeTag = params[1] ? params[1] : "excludeTagsTree";
	var level = params[2] ? params[2] : config.macros.tagsTree.level;
	var depth = params[3] ? params[3] : config.macros.tagsTree.depth;
	var sortField = params[4] ? params[4] : config.macros.tagsTree.sortField;
	var labelField = params[5] ? params[5] : config.macros.tagsTree.labelField;
	var showButtons = (level>0);
	var id = config.macros.tagsTree.getId(place);
	if (config.macros.tagsTree.trees[id]==undefined) config.macros.tagsTree.trees[id]={};
	config.macros.tagsTree.createSubTree(place,id,root,excludeTag,[],level>0 ? level : 1,depth, sortField, labelField,showButtons);
}

config.macros.tagsTree.createSubTree = function(place, id, root, excludeTag, ancestors, level, depth, sortField, labelField,showButtons){
	var childNodes = root ? this.getChildNodes(root, ancestors) : this.getRootTags(excludeTag);
	var isOpen = (level>0) || (!showButtons);
	if (root && this.trees[id][root]!=undefined) isOpen = this.trees[id][root]; 
	if (root && ancestors.length) {
		var t = store.getTiddler(root);
		if (childNodes.length && depth>0) {
			var wrapper = createTiddlyElement(place , this.styles[Math.min(Math.max(ancestors.length,1),6)-1],null,"branch");
			if (showButtons) {
				b = createTiddlyButton(wrapper, isOpen ? config.macros.tagsTree.collapse : config.macros.tagsTree.expand, null, config.macros.tagsTree.onClick);
				b.setAttribute("treeId",id);
				b.setAttribute("tiddler",root);					
			}
			createTiddlyText(createTiddlyLink(wrapper, root),t&&labelField ? t.fields[labelField] ? t.fields[labelField] : root : root);
		}
		else 
			createTiddlyText(createTiddlyLink(place, root,false,"leaf"),t&&labelField ? t.fields[labelField] ? t.fields[labelField] : root : root);
	}
	if (childNodes.length && depth) {
		var d = createTiddlyElement(place,"div",null,"subtree");
		d.style.display= isOpen ? "block" : "none";
		if (sortField)
			childNodes.sort(function(a, b){
				var fa=a.fields[sortField];
				var fb=b.fields[sortField];
				return (fa==undefined && fb==undefined) ? a.title < b.title ? -1 : a.title > b.title ? 1 : 0 : (fa==undefined && fb!=undefined) ? 1 :(fa!=undefined && fb==undefined) ? -1 : fa < fb ? -1 : fa > fb ? 1 : 0;
			})
		for (var cpt=0; cpt<childNodes.length; cpt++)
			this.createSubTree(d, id, childNodes[cpt].title, excludeTag, ancestors.concat(root), level-1, depth-1, sortField, labelField, showButtons);	
	}	
}

config.macros.tagsTree.onClick = function(e){
	var id = this.getAttribute("treeId");
	var tiddler = this.getAttribute("tiddler");	
	var n = this.parentNode.nextSibling;
	var isOpen = n.style.display != "none";
	if(config.options.chkAnimate && anim && typeof Slider == "function")
		anim.startAnimating(new Slider(n,!isOpen,null,"none"));
	else
		n.style.display = isOpen ? "none" : "block";
	this.firstChild.nodeValue = isOpen ? config.macros.tagsTree.expand : config.macros.tagsTree.collapse;
	config.macros.tagsTree.trees[id][tiddler]=!isOpen;
	return false;
}

config.macros.tagsTree.getChildNodes = function(root ,ancestors){
	var childs = store.getTaggedTiddlers(root);
	var result = new Array();
	for (var cpt=0; cpt<childs.length; cpt++)
		if (childs[cpt].title!=root && ancestors.indexOf(childs[cpt].title)==-1) result.push(childs[cpt]);
	return result;
}

config.macros.tagsTree.getRootTags = function(excludeTag){
	var tags = store.getTags(excludeTag);
	tags.sort(function(a,b) {return a[0].toLowerCase() < b[0].toLowerCase() ? -1 : (a[0].toLowerCase() == b[0].toLowerCase() ? 0 : +1);});
	var result = new Array();
	for (var cpt=0; cpt<tags.length; cpt++) {
		var t = store.getTiddler(tags[cpt][0]);
		if (!t || t.tags.length==0) result.push(t ? t : {title:tags[cpt][0],fields:{}});
	}
	return result;
}

config.macros.tagsTree.getId = function(element){
	while (!element.id && element.parentNode) element=element.parentNode;
	return element.id ? element.id : "<html>";
}

config.shadowTiddlers.TagsTreeStyleSheet = "/*{{{*/\n";
config.shadowTiddlers.TagsTreeStyleSheet +=".leaf, .subtree {display:block; margin-left : 0.5em}\n";
config.shadowTiddlers.TagsTreeStyleSheet +=".subtree {margin-bottom:0.5em}\n";
config.shadowTiddlers.TagsTreeStyleSheet +="#mainMenu {text-align:left}\n";
config.shadowTiddlers.TagsTreeStyleSheet +=".branch .button {border:1px solid #DDD; color:#AAA;font-size:9px;padding:0 2px;margin-right:0.3em;vertical-align:middle;text-align:center;}\n";
config.shadowTiddlers.TagsTreeStyleSheet +="/*}}}*/";

store.addNotification("TagsTreeStyleSheet", refreshStyles); 

config.shadowTiddlers.MainMenu="<<tagsTree>>"

config.shadowTiddlers.PageTemplate = config.shadowTiddlers.PageTemplate.replace(/id='mainMenu' refresh='content' /,"id='mainMenu' refresh='content' force='true' ")

//}}}
{{firstletter{ @@color:#c06;2@@}}}right{{@@color:#c06;4@@

[[jump|http://tiddlytagmindmap.tiddlyspot.com/#TiddlyTagMindMap%20]]

[[color|http://html-color-codes.info/]]

[[fine site|http://mptw2.tiddlyspot.com/#SliderSiteMap]]
/* This plugin requires the VismoLibrary */
/***
|''Name''|TiddlyTagMindMap|
|''Description''|Bring your tiddlers to life in a radial graph which displays all your tiddlywiki tiddlers and the relationships between them. (A bit like The Brain)|
|''Author''|Jon Robson|
|''Contributors''|Nicolas Garcia Belmonte|
|''Version''|1.5 in progress|
|''Date''|Nov 2008|
|''Status''|@@experimental@@;|
|''License''|BSD|
|''CoreVersion''|<...>|
|''Documentation''|<...>|
|''Keywords''|data visualisation, mindmap, The Brain, Mind Manager, FreeMind,tag relationships,graph|
!Description
Bring your TiddlyWiki to life!
!Notes
To install you will need to paste a line of text into your Theme {{{ <div id="tagmindmap"></div>}}} in the location where you would like to see the visualisation.

Currently we are unable to support this working in internet explorer.. we are working on it however.. sorry! :(
!Usage
{{{
The tagmindmap can be created from a macro call using <<tiddlytagmindmap //params//>>
alternatively paste <div id='tagmindmap'></div> into your page template.

The following macros may be useful however they can be included in the toolbar settings of the tiddlytagmindmap macro.
<<ToggleTagMindMap id>> (create button to toggle mind map with id 'id' on/off)
<<LoadMindMap id>> (create button to load all nodes into mind map  with id 'id')

There are a variety of configuration options in the backstage area under tweak. They all begin with TiddlyTagMindMapPlugin: 
}}}
!!Parameters
tiddlytagmindmap takes several (but all optional) parameters. Some examples can be seen below, note the order is irrelevant of these parameters.

!!!Animation
You can turn animation on/off by using animate:true or animate:false. By default it is on.

!!!Nodes and Edges
!!!!Directional edges 
The directed parameter allows you to add arrowheads to your edges. usage: {{{<< tiddlytagmindmap directed:true>>}}}
!!!!Name Length
nodeNameLength:x where x is an integer will shorten the name of any node with a name longer than x. If x =0, the labels will disappear so you can rely on tooltips.

!!!!Variable node sizes (tagcloud)
notagcloud:true as a parameter will flatten the nodes to have the same size font

!!!Dimensions
{{{<<tiddlytagmindmap height:100 width:100>>}}} will set a tiddlytagmindmap with height and width 100.
 
!!!Zooming
A parameter zoom allows you to specify an integer representing the initial inflation of the mind map. The smaller it is - the closer the nodes will be together.
{{{<<tiddlytagmindmap zoom:1000>>}}} will give you a very inflated TagMindMap!

!!!Tiddler Pop ups
You can now preview a tiddler by using popup:true

!!!Breadcrumb trail
You can turn visited nodes red when they are clicked on by using the {{{breadcrumb:true}}} parameter by default this is false.
!!!The toolbar
A parameter toolbar is a string of 1s. These signify the buttons. The first digit sets whether the bar should appear vertically or horizontally.
The following digits turn off or on the other available buttons.
!!!!The buttons
The digits preceding the first digit represent these buttons in this order..
toggle, loadall

{{{<<tiddlytagmindmap toolbar:101>>}}} would give you a vertical toolbar with a loadall button

!!!The Start State
A parameter can be used to specify how the map looks on start up. 
Currently the options are empty OR all OR a custom executable javascript function.
The first two options are simple strings eg.
{{{<<tiddlytagmindmap startState:empty>>}}} loads a blank tag mind map however {{{<<tiddlytagmindmap startState:all>>}}} loads all nodes excluding those in the exclude List.
the latter is more interesting. Have a look at [[Example 2]]!
!Revision History
1.6
  * can now preview tiddlers in place using popup:true
  * can turn off animations using animate:false
  * double click opens a node, single click reveals any new nodes and/or performs animations
  * fixed mouse panning
1.5 xx/xx 
	*Ability to add arrow heads to show direction
	*better performance
	*better control panel: replacement of macros for toggle/zoom in and out with built in toolbar to plugin
	*update to new version of RGraph (JIT)
	*Ability to set meta-data specific to nodes within a tiddler in optional fields see
	 http://TiddlyWiki.abego-software.de/#PartTiddlerPlugin (eg. colouring of children/parents/images in node label)
	*definable meta data (prefix,suffix,label,color)
	*can turn off click function
1.4 11/08 tag cloud integration/multiple tag mind maps/ability to call from macro
1.3 22/10/08 working with ie/packaged up code

!To Do
*bug: zoomin breaks on more than 1 mind map.. no idea why but scale resets :(
*fix ie clicking nodes
*display tiddler loads below the place it;s called from
*Ability to define your own function for relative sizing (ie. you could weight them on some meta field)
*color property should become css property
*ability to resize using %
*distinguish between tags and tiddlers (see CreateNodeJSON - tiddlers that don't exist in store are tagged in data field)
*rss hooks - specify where tags and node names come from in feed
*ability to specify what click function is
*ability to stop displayTiddler from loading into graph (*ability to turn off dynamic as you go updates)
*allow resizing
*auto spread out messy nodes (ie. zoom out if nodes are too close)
*node repositioning and saving of state
*better css support
*performance issues
*deleting edges as tiddlers are deleted
*adapt to parabolic tree mode and other visualisation types
*Self-defined click functions
*Continued code cleanup
*breadcrumbs to become encoded in the node colour (rather than label colour) define a colour of the breadcrumb trail - make it change colour each click (increment colour, so you can get an idea of path you took to get somewhere)
*add pins to locations in the mind map to jump back to (definable in meta data long term, also short term in tiddler edit menu)
!Code
***/
/***
!Layer 1: TiddlyWiki Specific 
Jon Robson
***/

{{{

//set descriptions
merge(config.optionsDesc,{
txtTTMM_canvasWidth: "TiddlyTagMindMapPlugin : Width of  visualisation. You will need to refresh the page to see the change."
,txtTTMM_canvasHeight: "TiddlyTagMindMapPlugin : Height of visualisation. You will need to refresh the page to see the change."
,txtTTMM_inflation: "TiddlyTagMindMapPlugin : The visualisation can be inflated and deflated to allow you to see the structure from above or close up. This value allows you to set a start inflation."
,txtTTMM_maxNodeNameLength:"TiddlyTagMindMapPlugin : maximum length of a tiddler name. Any tiddlers with names longer than this will be abbrieviated using '...'. Set to zero to make labels disappear altogether and rely completely on tooltips."
,chkTTMM_ignoreLoneNodes: "TiddlyTagMindMapPlugin : any lone tiddlers/nodes (ie. tiddlers that are not tagged with any data) will be ignored in the visualisation. This cleans up the visualisation greatly."
,txtTTMM_excludeNodeList: "TiddlyTagMindMapPlugin :Anything tagged with this will be ignored in the visualisation. Formatted in form ['tiddlername1', 'tiddlername2']"
,chkTTMM_leaveRedBreadCrumbTrail: "TiddlyTagMindMapPlugin : When you visit a node it will be coloured red leaving a breadcrumb trail of where you have been."
}
);

/*MACROS*/


config.macros.TagMindMapEdge={ /* params: node1|commit node2 */
	handler: function (place,macroName,params,wikifier,paramString,tiddler) {
		
		var id1 = params[0]; var id2 = params[1];
		var ttmm = config.macros.tiddlytagmindmap.getAssociatedTiddlyTagMindMapObject(null,false);
		if(!ttmm) return;
			
			
		if(id1 == "commit") {
			this.commit(); 
			return;
		}
		var name1,name2,data1,data2;
		if(id1.id){
			//its a json
			if(id1.name)name1 = id1.name;
			if(id1.data)data1 = id1.data;
			id1 = id1.id;
	
		}

		if(id2.id){
			//its a json
			if(id1.name)name2 = id2.name;
			if(id2.data)data2 = id2.data;
			id2 = id2.id;
		}
		
		if(!data1){ data1 = {};}
		if(!data2){ data2 = {};}
		
		if(!store.tiddlerExists(id1)){
			if(!data1.color && ttmm.settings.emptyTiddlerColor)data1.color = ttmm.settings.emptyTiddlerColor;
			data1.emptyTiddler = true;
		}
		if(!store.tiddlerExists(id2)){
			if(!data2.color && ttmm.settings.emptyTiddlerColor)data2.color = ttmm.settings.emptyTiddlerColor;
			data2.emptyTiddler = true;
		}
		


		if(ttmm){
		ttmm.drawEdge(id1,id2,name1,name2,data1,data2);
		
		}
	}
	,commit: function(){
		var ttmm = config.macros.tiddlytagmindmap.getAssociatedTiddlyTagMindMapObject(null,false);
		ttmm.computeThenPlot();
	}
};
	
config.macros.LoadMindMap={
	label: "loadall",
	prompt: "load all tiddlers into the tag mind map",
	handler: function (place,macroName,params,wikifier,paramString,tiddler) {
		var btn =createTiddlyButton(place,this.label,this.prompt,this.onClick);	
		
		if(params[0]){
			btn.wrapperID = params[0];
		}
	}
	,onClick: function(e,id)
	{
		var ttmm;
		if(id) 
			ttmm = config.macros.tiddlytagmindmap.store[id];
		else
			ttmm = config.macros.tiddlytagmindmap.getAssociatedTiddlyTagMindMapObject(this.wrapperID,true); 
		var list = store.getTiddlers();
		for (var t=0; t<list.length; t++) { 

			ttmm.createNodeFromJSON(config.macros.tiddlytagmindmap.createJSON(list[t].title,ttmm));
		}

		ttmm.computeThenPlot();


	}
};

config.macros.ToggleTagMindMap={
	label: "toggle",
	prompt: "Toggle on or off the tag mind map",
	handler: function(place,macroName,params,wikifier,paramString,tiddler){
		var btn = createTiddlyButton(place,this.label,this.prompt,this.onClick);
		if(params[0])btn.wrapperID = params[0];
	}
	,onClick: function(e){ 
	
		var id = config.macros.tiddlytagmindmap.getAssociatedTiddlyTagMindMapObject(this.wrapperID,true).wrapper.id;

		if(document.getElementById(id).style.display== "none"){
			document.getElementById(id).style.display=  "";
		}
		else{
			document.getElementById(id).style.display=  "none";
		}
	}

};

config.macros.tiddlytagmindmap={
	store: {}, //a library of created ttmm objects
	handler: function (place,macroName,params,wikifier,paramString,tiddler) {
		if(!place) { //give a default place
			place = document.getElementById('tagmindmap');
			if(!place) throw "no place to put ttmm!"; //unable to create
			paramString =place.getAttribute("parameters");

		}
		
		var settings = this.get_ttmm_settings(paramString);

		var elem = this.setup_ttmm_html(place,settings);

			try{
			
			this.store[elem.id]= new Tagmindmap(elem,settings);
			
			this.store['last'] = elem.id;
			this.store['cur'] = elem.id;
		
	
			if(settings.startupFunction){
				settings.startupFunction(elem.id);
			}
		
		}
		catch(e){console.log("exception thrown during tiddlytagmindmap creation:"+e);}
	},
	get_ttmm_setting_defaults: function(){
		if(!config.options.txtTTMM_canvasWidth)config.options.txtTTMM_canvasWidth = 800;
		if(!config.options.txtTTMM_canvasHeight)config.options.txtTTMM_canvasHeight = 200;
		if(!config.options.txtTTMM_inflation)config.options.txtTTMM_inflation = 80;
		if(!config.options.txtTTMM_maxNodeNameLength)config.options.txtTTMM_maxNodeNameLength = 25;
		if(config.options.chkTTMM_ignoreLoneNodes == null) config.options.chkTTMM_ignoreLoneNodes = false;
		if(config.options.chkTTMM_leaveRedBreadCrumbTrail == null) config.options.chkTTMM_leaveRedBreadCrumbTrail = true;
		if(!config.options.txtTTMM_excludeNodeList) config.options.txtTTMM_excludeNodeList= ['excludeLists'];
	
		var settings = {};
		/*set some defaults based on tweaked preferences if none passed as parameters*/
		settings.maxNodeNameLength = config.options.txtTTMM_maxNodeNameLength;
		settings.ignoreLoneNodes = config.options.chkTTMM_ignoreLoneNodes;
		settings.tagcloud = {off:false};
		settings.width = config.options.txtTTMM_canvasWidth;
		settings.height =config.options.txtTTMM_canvasHeight;
		settings.toolbar = "000";
		settings.zoomLevel = parseInt(config.options.txtTTMM_inflation);
		settings.breadcrumbs = config.options.chkTTMM_leaveRedBreadCrumbTrail;
		settings.animate = true;
		var clickfunction = function(node,id,e){
			//var tiddlerElem = story.findContainingTiddler(resolveTarget(e));
			story.displayTiddler(null, node.id,null,null,null,null,null,id);
		};
		settings.clickFunction = clickfunction;
		return settings;
	},
	get_ttmm_settings: function(paramString){
		var settings = this.get_ttmm_setting_defaults();

		var exList = null;
		var that = this;
		var startupFunction = function(id){};


	
		settings.dynamicUpdateFunction = this.createJSON;
	
		if(paramString){
			var prms = paramString.parseParams(null, null, true);
			settings.breadcrumbs = eval(getParam(prms, "breadcrumbs"));
			settings.ignoreLoneNodes = eval(getParam(prms, "ignoreLoneNodes"));
			settings.arrowheads = eval(getParam(prms, "directed"));
			settings.tagcloud.off = eval(getParam(prms, "notagcloud"));
		        if(getParam(prms,"animate")) settings.animate = eval(getParam(prms,"animate"));
			if(getParam(prms, "id")) settings.id = getParam(prms, "id");	
			if(getParam(prms, "width")) settings.width = getParam(prms, "width");
			if(getParam(prms, "height"))settings.height = getParam(prms, "height");
			if(getParam(prms, "toolbar")) settings.toolbar= getParam(prms, "toolbar");
			if(getParam(prms,"zoom")) settings.zoomLevel = parseInt(getParam(prms,"zoom"));
			if(getParam(prms,"maxNodeNameLength"))settings.maxNodeNameLength = getParam(prms,"maxNodeNameLength");
			if(getParam(prms, "exclude")) exList = getParam(prms, "exclude");
			if(getParam(prms,"displayemptytiddlers"))settings.displayemptytiddlers = getParam(prms,"displayemptytiddlers");
			if(getParam(prms,"emptyTiddlerColor")){
				settings.emptyTiddlerColor =getParam(prms,"emptyTiddlerColor");
			}
			

			var clickfunction;
			if(!getParam(prms, "click")){
			        
			        clickfunction = function(node,id,e){
			        	var tiddlerElem = story.findContainingTiddler(resolveTarget(e));
					story.displayTiddler(tiddlerElem, node.id,null,null,null,null,null,id);
					return;
                		};
                                
			}
			else if(getParam(prms, "click") == "existing") {
			       
				clickfunction = function(node,id,e){
					if(!node.data.emptyTiddler){
						var tiddlerElem = story.findContainingTiddler(resolveTarget(e));
						story.displayTiddler(tiddlerElem, node.id,null,null,null,null,null,id);
					}
					
					return;
				};
			}
			else if(getParam(prms,"click") == "none"){
			        clickfunction = function(node,id,e){};
			}
			
			settings.clickFunction = clickfunction;

                        if(getParam(prms,"popup")) {
                                settings.globalSuffix = function(node){
                                        
                                        var place = document.createElement("div");
                                        var tiddler = store.getTiddler(node.id);
                                        if(!tiddler) tiddler = config.shadowTiddlers[node.id];
                                        if(tiddler)createTiddlyPopup(place,"",node.id,tiddler);
                                        return place;
                                };
			}
			var startState = getParam(prms, "startState");
			if(startState){
				if(startState == 'all')
					startupFunction = function(id){
						config.macros.LoadMindMap.onClick(null,id);
					}
				else if(startState == 'empty'){
					startupFunction = function(id){
					
					};
				}
				/*else if(startState == 'default'){

					startupFunction = function(id){
						con
						var startState = store.filterTiddlers(store.getTiddlerText("DefaultTiddlers"));
						that.loadTiddlersIntoTTMM(startState,id);
					}
				}*/
				else{//parse as a list of tiddler names
					if(startState){
						startupFunction = function(id){
							if(startState.length == 0) return;
							that.loadTiddlersIntoTTMM(startState,id);
						} 
					}
			
				}
				settings.startupFunction = startupFunction;
			}
		}
		
		
		if(!exList){
			exList = [];
			if(config.options.txtTTMM_excludeNodeList)exList = config.options.txtTTMM_excludeNodeList;
		}
		/*set the excluded nodes */
		var l = eval(exList);
		settings.excludeNodeList = [];
		for(var i=0; i < l.length; i++){
			settings.excludeNodeList.push(l[i]);	
			settings.excludeNodeList = settings.excludeNodeList.concat(getChildren(l[i]));		
		}

	

	
	
		return settings;
	}
	,setup_ttmm_html: function(place,settings){
		if(place.id == 'tagmindmap')settings.id = 'default';
		if(place.style.width) settings.width = place.style.width;
		if(place.style.height) settings.height = place.style.height;

		/*setup tag mind map */
		var newTTMM = document.createElement("div");
		if(!settings.id) settings.id="ttmm_" +Math.random();
		newTTMM.id = settings.id;
		newTTMM.style.width = settings.width +"px";
		newTTMM.style.height= settings.height +"px";
		newTTMM.setAttribute("class","ttmm");
		/*setup toolbar */
		var toolbar = document.createElement("div");
		toolbar.setAttribute("class","ttmm_toolbar");
		var html="", divider = " ";

		if(settings.toolbar[0] == 1){//MAKE VERTICAL
			toolbar.style.height = "1px";
			toolbar.style.position = "relative";
			var temp =  parseInt(settings.width) +10;
			toolbar.style.top = "0px";
			toolbar.style.left = temp+"px";
			divider = "\n";
		}
		if(settings.toolbar[1] == 1) html += "<<ToggleTagMindMap " + newTTMM.id+">>" + divider;
		if(settings.toolbar[2] == 1) html += "<<LoadMindMap " + newTTMM.id+">>"+ divider;


		place.appendChild(toolbar);
		wikify(html,toolbar);
		place.appendChild(newTTMM);

		if(!document.getElementById(this.store['first']))this.store['first'] = newTTMM.id; //no primary ttmm exists

		if(!newTTMM.style.width) newTTMM.style.width = settings.width;
		if(!newTTMM.style.height) newTTMM.style.height = settings.height;

		return newTTMM;
	}

	,loadTiddlersIntoTTMM: function(tiddlerList,visualisationID){
		var viz;
		if(!visualisationID) 
			viz = this.store[this.store['first']];
		else
			viz = this.store[visualisationID];
		var nodesLoaded = false;


		var title ="";var firstTitle="";
		for(var i =0; i < tiddlerList.length; i++){

			if(tiddlerList[i].title) title = tiddlerList[i].title;
			else title = tiddlerList[i];
			if(i==0) firstTitle = title;
	
			nodesLoaded = viz.createNodeFromJSON(this.createJSON(title,viz)) | nodesLoaded;
	
		}


		if(viz.rgraph){
			if(nodesLoaded !=0){
				viz.rgraph.compute();
				viz.rgraph.plot();

			}
		
			viz.centerOnNode(title);
		}
	}

	,getAssociatedTiddlyTagMindMapObject: function(id,getFirstCreatedTTMM){
			if(id) return this.store[id];
			else {
				if(getFirstCreatedTTMM) 
					return this.store[this.store['first']];
				else 
					return this.store[this.store['last']];
			}
	}


	,_createJSONTagMindMapNodes: function(mylist,storeElement) { 
		var res=[]; 
		for (var t=0; t<mylist.length; t++){
			var node =mylist[t];
			res.push(config.macros.tiddlytagmindmap._createJSONTagMindMapNode(node,storeElement));
		} 
		
		return res;
	}
	
	,_createJSONTagMindMapNode: function(id,storeElement){


		var json = {};
		json.id = id;
		json.name = id;

		nodeData = {};

		var parents = getParents(id);
		for(var i=0; i < parents.length; i++){
			var nodeid = parents[i];
					
			if(store.tiddlerExists(nodeid)){
				var tiddler = store.getTiddler(nodeid);
				if(tiddler.fields.childrencolor) nodeData.color = tiddler.fields.childrencolor;
			}	
		}
				
		var children = getChildren(id);
		for(var i=0; i < children.length; i++){
			var nodeid = children[i];
			
			if(store.tiddlerExists(nodeid)){
				var tiddler = store.getTiddler(nodeid);
				if(tiddler.fields.parentcolor) nodeData.color = tiddler.fields.parentcolor;
			}	
		}

		
		
		if(store.tiddlerExists(id)){
			var tiddler = store.getTiddler(id);
			if(tiddler.fields.nodecolor) nodeData.color = tiddler.fields.nodecolor;
			if(tiddler.fields.nodeprefix) {
				var place =createTiddlyElement(null,"div");
				wikify(tiddler.fields.nodeprefix,place);
				nodeData.nodeLabelPrefix = place;
			}
			if(tiddler.fields.nodesuffix) {
				var place =createTiddlyElement(null,"div");
				wikify(tiddler.fields.nodesuffix,place);
				nodeData.nodeLabelSuffix = place;

			}
			if(tiddler.fields.nodelabel) {
				var place =createTiddlyElement(null,"div");
				wikify(tiddler.fields.nodelabel,place);
				nodeData.label = place;
			}
			if(tiddler.fields.nodetooltip) {nodeData.title = tiddler.fields.nodetooltip;}

		}

		if(!nodeData.color){
			var empty = false;
			 if(!store.tiddlerExists(id) && !store.isShadowTiddler(id)){		
				empty = true;
			}
			if(store.tiddlerExists(id)){
				var tiddler = store.getTiddler(id);
				if(tiddler.text == null || tiddler.text == "") empty =true; 
			}

			if(empty){
				nodeData.emptyTiddler = true;
				//nodeData.color = "#cccccc";
				//console.log(storeElement.settings);
				if(storeElement && storeElement.settings.emptyTiddlerColor) nodeData.color= storeElement.settings.emptyTiddlerColor;
				//storeElement
				
			}
		}

		if(nodeData){
			json.data =nodeData;
		}
		
		return json;
	}
	
	,createJSON: function(nodeid,storeElement){
		if(!nodeid) return "{}";
	    	var myjson = {};

		var children = getChildren(nodeid);
	    	var parents = getParents(nodeid);
	

		myjson.children = config.macros.tiddlytagmindmap._createJSONTagMindMapNodes(children,storeElement);
	 	myjson.parents = config.macros.tiddlytagmindmap._createJSONTagMindMapNodes(parents,storeElement);
		myjson.node  = config.macros.tiddlytagmindmap._createJSONTagMindMapNode(nodeid,storeElement);

		return myjson;
	}
	
	

};


function getParents(a){ 

  if(store.getTiddler(a)){
    return store.getTiddler(a).tags;
  }
  else
    return [];
} 

function getChildren(a){
	  if(store.getTaggedTiddlers(a)){
	    var tags = store.getTaggedTiddlers(a);
	    if(tags.length == 0) return [];

	    var a = new Array();
	    for (var t=0; t<tags.length; t++) { 
		a.push(tags[t].title);
	    }
	    return a;
	}
	  else
	    return [];
}



	



story.beforettmm_displayTiddler = story.displayTiddler;
story.displayTiddler = function(srcElement,tiddler,template,animate,unused,customFields,toggle,visualisationID)
{
	try{
		if(!document.getElementById(config.macros.tiddlytagmindmap.store['first'])) {					
			config.macros.tiddlytagmindmap.handler(); //try and setup a default one
		}
	}
	catch(e){
		
	};

	
	var title = (tiddler instanceof Tiddler)? tiddler.title : tiddler;

	if(config.macros.tiddlytagmindmap.store){
		try{
			if(!visualisationID && config.macros.tiddlytagmindmap.store['first']) { //call came from outside tagmindmap
				visualisationID =config.macros.tiddlytagmindmap.store['first'];
			}
			if(visualisationID){
				res = config.macros.tiddlytagmindmap.loadTiddlersIntoTTMM([title],visualisationID);
			}
		}
		catch(e){
			//console.log("exception in display tiddler for "+title+" in visualisation" + visualisationID +": " + e);
		}
	}
	story.beforettmm_displayTiddler(srcElement,tiddler,template,animate,unused,customFields,toggle);
};

}}}
/***
296.56
58 * 151.46
246.56
!Layer 2: DynamicInteract: Extension of RGraph
***/
{{{
Array.prototype.contains = function(item)
{
	return this.indexOf(item) != -1;
};
if(!Array.indexOf) {
	Array.prototype.indexOf = function(item,from)
	{
		if(!from)
			from = 0;
		for(var i=from; i<this.length; i++) {
			if(this[i] === item)
				return i;
		}
		return -1;
	};
}

var Tagmindmap = function(wrapper,settings){
	if(settings.clickFunction)
		this.callWhenClickOnNode = settings.clickFunction;
	else
		this.callWhenClickOnNode = function(node,id){return};
	
	if(settings.dynamicUpdateFunction)
		this.dynamicUpdateFunction = settings.dynamicUpdateFunction;
	else
		this.dynamicUpdateFunction = function(node,id){return {};};		
	this.wrapper = wrapper;
	
	this._setup(settings);
	//this._init_html_elements(wrapper.id);
	
	

	this._init_html_elements();
	this.controlpanel =new VismoController(this,wrapper,["pan","zoom","mousepanning"]);
	this.ready = false;
	this.children = {};
	this.parents = {};
	this.ready = true;
	this.controlpanel.setTransformation({translate:{x:0,y:0}, scale:{x: this.settings.zoomLevel,y: this.settings.zoomLevel}});
	
};

Tagmindmap.prototype = {
	transform: function(t){
		var compute = false;
		if(this.settings.zoomLevel != t.scale.x) {
		        t.translate.x = 0; t.translate.y = 0;
		        if(this.lastclickednode) this.rgraph.root = this.lastclickednode;
			if(t.scale.x > 0){			
				this.settings.zoomLevel = parseFloat(t.scale.x);
			}
			compute = true;
		}
	
		if(this.rgraph){
			var c= {x:t.translate.x * t.scale.x, y:t.translate.y* t.scale.y};
		
			this.rgraph.offsetCenter(c.x,c.y);
			if(compute) this.rgraph.compute();
			this.rgraph.plot();
		}
	},
	_setup: function(settings){
		
		
		this.settings = {'animate':true,'arrowheads':false,'maxNodeNameLength':99999,'breadcrumbs': true,'lineColor':'#ccddee','nodeColor':'#ccddee','zoomLevel':100, 'ignoreLoneNodes':false,'excludeNodeList': ['excludeLists']}; //put all default settings here
		this.settings.tagcloud = {'smallest': 0.8, 'largest': 1.4, 'upper':0, 'off': false}; //upper is the maximum sized node
	
		this.graph_showCirclesFlag = false; //shows circles in the mind map
		this.maxNodeNameLength = 0;
		this.displacement = {'x':0, 'y':0};
		this.maxChildrenOnSingleNode = 0;	
		this.thehiddenbridge = "RGRAPHTREEBRIDGE"; //a hidden node which bridges all dislocated nodes.

		this.settings.breadcrumb_startcolor = "red"; //rgb(0,0,0)
		/*above defaults below read in */
		for(var i in settings){
			this.settings[i] = settings[i];
		}
		this.settings.arrowheads = settings.arrowheads;
		this.settings.breadcrumbs = settings.breadcrumbs;
		this.settings.tagcloud.off = settings.tagcloud.off;
		this.settings.excludeNodeList = settings.excludeNodeList;
		this.settings.ignoreLoneNodes = settings.ignoreLoneNodes;
		this.maxNodeNameLength = settings.maxNodeNameLength;
		this.settings.zoomLevel = settings.zoomLevel;
		var ttmm = this;
	},

	
	_init_html_elements: function(){
			var wrapperID = this.wrapper.id;
			if(!document.getElementById(wrapperID)){ throw (wrapperID + " html element doesn't exist");}

			var canvasID = wrapperID + "_canvas"; //the canvas object ID
			this.labelContainer = wrapperID + "_label_container";
			this.nodeLabelPrefix = canvasID +"_";
			/*setup the divs */
			var wrapper = this.wrapper;
			wrapper.style.position = "relative";
			
			if(!wrapper.style.height){wrapper.style.height = "200px";}
			if(!wrapper.style.width){wrapper.style.width = "200px";}

			var labelContainer = document.createElement("div");
			labelContainer.id=this.labelContainer;
			labelContainer.style.position= 'relative';		
			var canvas = document.createElement("canvas");
			canvas.id = canvasID;
			canvas.width = parseInt(wrapper.style.width);
			canvas.height =parseInt(wrapper.style.height);
			
			wrapper.appendChild(labelContainer);
			wrapper.appendChild(canvas);
			this.canvas = canvas;
			if(config.browser.isIE && G_vmlCanvasManager) {G_vmlCanvasManager.init_(document);} //ie hack - needs changing to work outside tw		
	},
	

	createNodeFromJSON: function(json){

		if(json == {}) return;
		var temp = false;
		var res = false;
		var node1= json['node'];
		if(json['parents']){ 
			for(var i=0; i < json['parents'].length; i++){
				var parent = json['parents'][i];
				temp = this.drawEdge(parent['id'],node1['id'],parent['name'],node1['name'],parent['data'],node1['data']);
				res = temp | res;
			}
		 }

		if(json['children']){
			for(var i=0; i < json['children'].length; i++){
			   	var child = json['children'][i];
				temp = this.drawEdge(node1['id'],child['id'],node1['name'],child['name'],node1['data'],child['data']);
				res = temp | res;
			 }
		}

		if(json['children'] && json['parents']){
		 if(!this.settings.ignoreLoneNodes && json['children'].length ==0 && json['parents'].length == 0)
		   temp = this.drawEdge(this.thehiddenbridge, node1['id'],null,node1['name'],null,node1['data']);
		res = temp | res;
		 }
		
		return res;
	},

	centerOnNode:function(id){
		//var cur =this.getCurrentNodeID();
		//if(cur == id) return;

		this.rgraph.onClick(id);
		
	},

	getCurrentNodeID: function(){
		if(!this.rgraph.graph.root) return false;
		if(this.rgraph.graph.root.id == this.thehiddenbridge) return false;
		else return this.rgraph.graph.root.id;
	},

	setNodeName: function(nodeid,newName){
		var node = this.controller.getNode(nodeid);
		if(node.name != newName){
			node.name = newName;
			if(this.thehiddenbridge != nodeid && this.graph_index) this.graph_index[newName] = nodeid;
		}
	},
	mergeNodeData: function(id,data){

			var node = this.controller.getNode(id);
			if(!node) return;

			for (var key in data){
				if(typeof node.data[key] == 'array')
					node.data[key] = node.data[key].concat(data[key]);
				else
					node.data[key] = data[key];
			}
			
			if(node.data.weight > this.settings.tagcloud.upper) {
				this.settings.tagcloud.upper = node.data.weight;
			}
	},
	setNodeData: function(id,data,newvalue){
		var node = this.controller.getNode(id);
		if(!node) return;
		
		if(!newvalue){
			node.data = data;
		}
		else{
			node.data[data] = newvalue;	
		}

		if(node.data.weight > this.settings.tagcloud.upper) {
			this.settings.tagcloud.upper = node.data.weight;
		}
	
	},

	_nodeInExcludeList: function(id){
		return this.settings.excludeNodeList.contains(id);
	},

	drawEdge: function(id_a,id_b,name_a,name_b,data_a,data_b){
		if(this._nodeInExcludeList(id_a) || this._nodeInExcludeList(id_b)) return false;
		plotNeeded=false;

		if(id_a != "" && id_b != ""){

		  plotNeeded = this._make_connection(id_a,id_b);

		  if(name_a){this.setNodeName(id_a,name_a);}
		  if(name_b){this.setNodeName(id_b,name_b);}
		
		  if(data_a) {this.mergeNodeData(id_a,data_a); }
		  if(data_b) {this.mergeNodeData(id_b,data_b);}

		}  
		return plotNeeded;
	},

	_make_connection: function(a,b){
	  	  var drawn = this._setupMapIfNeeded(a);
		  var node1, node2; 
		  node1 = this.controller.getNode(a);
		  node2 = this.controller.getNode(b);

		  if(node1 && node2){
			if(node1.adjacentTo(node2)) {return false;}

		  }
		  else if(!node1 && !node2) {//neither in graph yet
			drawn = this._make_connection(this.thehiddenbridge,a);  //if neither node is currently in tree, then we need to create a "bridge" to connect the trees
		  
		  }
		
		
		  if(!node1) {node1= new Graph.Node(a,a,{});drawn= true; }//create this node
		  if(!node2) {node2= new Graph.Node(b,b,{});drawn= true; }//create that node

		  if(node1){			
	
			  if(!node1.adjacentTo(node2)){

		
				this.controller.addAdjacence(node1,node2);
				
				node1 = this.controller.getNode(a);
			  	node2 = this.controller.getNode(b);
			
				if(!this.children[a]) this.children[a] = [];
				if(!this.parents[b]) this.parents[b] = [];
				this.children[a].push(b);
				this.parents[b].push(a);

				return true;
			 }
		 }
	},
	deleteNode: function(id){
		var node = this.rgraph.controller.getNode(id);
		//console.log("start",node,"end");
		var parents = node.data.parents;
		var children = node.data.children;
		//console.log(id,parents,children);
		if(children){
			//sort out children
			for(var i=0; i < children.length; i++){
				var childNode = this.rgraph.controller.getNode(children[i]);
			
				var oldparents = childNode.data.parents;
				var newparents = [];
				for(var j=0; j < oldparents.length; j++){
					if(oldparents[j] != id)newparents.push(oldparents[j]);
				}

				this.setNodeData(children[i],"parents",newparents);
				
				if(newparents.length == 0) { //connect it up to the bridge
					this.drawEdge(this.thehiddenbridge,children[i]);
			
				}
			}
		}
			
		//sort out parents
		if(parents){
			for(var i=0; i < parents.length; i++){
				if(parents[i] != this.thehiddenbridge){
					
			
					var parentNode = this.rgraph.controller.getNode(parents[i]);
			
					var oldchildren = parentNode.data.children;
					var newchildren = [];
					for(var j=0; j < oldchildren.length; j++){
						if(oldchildren[j] != id)newchildren.push(oldchildren[j]);
					}
					this.setNodeData(parents[i],"children",newchildren);
				}
			}
		}
				
		this.rgraph.controller.removeNode(id);


	},
	computeThenPlot: function(){
		try{
		  this.rgraph.compute();
		  this.rgraph.plot(); 
		}
		catch(e){
			console.log(e+"in computeThenPlot");
		}
	},

	_trimNodeName: function(node_name){
		if(this.maxNodeNameLength ==0) return "<span>&nbsp;&nbsp;&nbsp;</span>";
		if(this.maxNodeNameLength){
			var nlength = this.maxNodeNameLength;

			  if(node_name.length > nlength)
			    return node_name.substr(0,nlength/2) + "..." + node_name.substr(node_name.length-nlength/2,node_name.length);
			  else
			    return node_name;
		}
		return node_name;
	},

	
	_getController: function(){

  		var ttmm = this;
		    var effectHash = {};
		  var controller =  {
			
			removeNode: function(id){
				
				var el = document.getElementById(this.getNodeLabelPrefix()+id);
				el.parentNode.removeChild(el);
				
				var graph = ttmm.rgraph.graph;
				if(graph) graph.removeNode(id);	
			
			},
			getNode: function(id){
			
			  var n = GraphUtil.getNode(ttmm.rgraph.graph,id); 

			return n;
			},
			addAdjacence: function(node1,node2){
				ttmm.rgraph.graph.addAdjacence(node1,node2);	
			},
			/*some custom defined controller operations (search in RGraph source)*/
			getZoomLevel: function(){	
				return parseFloat(ttmm.settings.zoomLevel);
			},
			setOffset: function(d){ttmm.displacement = d;},
			getOffset: function(){return ttmm.displacement;},
			getNodeLabelContainer: function(){
				return ttmm.labelContainer;
			},
			getNodeLabelPrefix: function(){return ttmm.nodeLabelPrefix;},
		  	onBeforeCompute: function(node) {									
				ttmm.createNodeFromJSON(ttmm.dynamicUpdateFunction(node.id));
				if(ttmm.settings.breadcrumbs) {
					ttmm.setNodeData(node.id,"color",ttmm.settings.breadcrumb_startcolor);	
				}
			},
		  	getName: function(node1, node2) {
		  		for(var i=0; i<node1.data.length; i++) {
		  			var dataset = node1.data[i];
		  			if(dataset.key == node2.name) return dataset.value;
		  		}
  		
				for(var i=0; i<node2.data.length; i++) {
		  			var dataset = node2.data[i];
		  			if(dataset.key == node1.name) return dataset.value;
		  		}
		  	},	
		
		  	onCreateLabel: function(domElement, node) {			
			}

			,attachClickFunction: function(domElement,node){	
				if(node.id == this.thehiddenbridge) return;
				
				var dblclickfunction = function(event){
				       //alert("!");
				        ttmm.callWhenClickOnNode(node,ttmm.wrapper.id,event);
				};
				var clickfunction = function(event){
						ttmm.createNodeFromJSON(ttmm.dynamicUpdateFunction(node.id));
                                                if(ttmm.settings.animate){
        						ttmm.centerOnNode(node.id);
                                                }
                                                else{
                                                        ttmm.lastclickednode = node.id;
                                                        //ttmm.computeThenPlot();
                                                        
                                                }
				};
				
				if(domElement.addEvent){ //for ie
				        //domElement.addEvent('click',clickfunction);
				        //domElement.addEvent('dblclick',dblclickfunction);
				}
				else {
					
					//domElement.onclick = clickfunction;
					
				}
				domElement.onmousedown = clickfunction;
                                domElement.ondblclick = dblclickfunction;
			}
			,getMaxChildren: function(){
				var max =0,num;
				for(var i in ttmm.children){
					if(ttmm.children[i])
						num = ttmm.children[i].length;
					else
						num =0;
					if(num > max) max = num;
				}
				return max;
			},
		  	
			calculateNodeWeight: function(node){
				var weight=0, u=0;
				
				if(node.data.weight) { //user has defined some sort of weight
					weight = parseFloat(node.data.weight);
					u =parseFloat(ttmm.settings.tagcloud.upper);
				}
				else{ //just take number of children
					
					if(ttmm.children[node.id]){
						weight = ttmm.children[node.id].length;
					}
					u = this.getMaxChildren();
				}
				
				var s,l;
				
				if(ttmm.settings.tagcloud.smallest){
					s = parseFloat(ttmm.settings.tagcloud.smallest);
				}
				else{	
					s = 0.5;
				} 
				if(ttmm.settings.tagcloud.largest) {
					l =parseFloat(ttmm.settings.tagcloud.largest);
				}
				else{
					l = 2;
				}
				
				var fontsize = s + ((l - s) * parseFloat(weight / u));	
				//console.log(s,l,weight,u,fontsize);
				
				return fontsize;
			},
			onPlaceLabel: function(domElement, node) {
				domElement.innerHTML = ""; //quick and dirty flush
 				if(node.id != ttmm.thehiddenbridge){
						if(node.data.color) domElement.style.color = node.data.color;
							
						if(node.data.title){
							domElement.title = node.data.title;
						}
						else{
							domElement.title = node.name;
						}
						
					
						var prefix, nodeLabel,suffix;
						if(node.data.nodeLabelPrefix) prefix =node.data.nodeLabelPrefix;
						
						if(prefix){
							prefix.setAttribute("class","nodeLabelPrefix");
							domElement.appendChild(prefix);
						}
					
						if(!node.data.label){
							nodeLabel = document.createElement("span");
						 	var labelText = ttmm._trimNodeName(node.name);
							nodeLabel.appendChild(document.createTextNode(labelText));
						}
						else{
							nodeLabel = node.data.label;
						}
						
						if(!ttmm.settings.tagcloud.off){
							var fontsize = this.calculateNodeWeight(node);

						
							
							nodeLabel.style.fontSize = fontsize + "em";
							
						}
					
						nodeLabel.setAttribute("class","nodeLabel");
				
						this.attachClickFunction(nodeLabel,node);

						domElement.appendChild(nodeLabel);
						
					
						
						if(ttmm.settings.globalSuffix){
						        suffix =ttmm.settings.globalSuffix(node);
						        suffix.setAttribute("class","nodeLabelSuffix");																						 
        						domElement.appendChild(suffix);  
						}
						if(node.data.nodeLabelSuffix) {
						        suffix =node.data.nodeLabelSuffix;
						        suffix.setAttribute("class","nodeLabelSuffix");																						 
							domElement.appendChild(suffix);		
						}
						
						
				}
				else domElement.style.display = "none";

			
				var left = parseInt(domElement.style.left);
				domElement.style.width = '';
				domElement.style.height = '';
				var w = domElement.offsetWidth;
				domElement.style.left = (left - w /2) + 'px';


			},
	
			onAfterCompute: function() {
				if(ttmm._afterComputeFunction){
					ttmm._afterComputeFunction();	
					ttmm._afterComputeFunction = false;			
				}
						
			},
	
			onBeforePlotLine: function(adj){
			  lineW = ttmm.canvas.getContext().lineWidth;  
		      nodeid = adj.nodeFrom.id;
			  nodeid2 = adj.nodeTo.id;
			  if(nodeid == ttmm.thehiddenbridge || nodeid2 == ttmm.thehiddenbridge){
				ttmm.canvas.getContext().lineWidth = "0";
				}
			  else ttmm.canvas.getContext().lineWidth = "1";

			},
	
			onAfterPlotLine: function(adj){
				var l =this.getNodeLabelContainer();				
				//document.getElementById(l).innerHTML = "";	
				var context = ttmm.canvas.getContext();
				var canvas = ttmm.canvas;
				var node = adj.nodeFrom, child = adj.nodeTo;

				var pos = node.pos.toComplex();
				var posChild = child.pos.toComplex();
				var d = this.getOffset();//jon
				
				//draw arrowhead.. (angle needs to be calculated)
				if(ttmm.settings.arrowheads){
					if(node.id == ttmm.thehiddenbridge)return;
					//console.log("arrowhead from",node.id, "to",child.id)
					canvas.path('stroke', function(context) {
					var r = 20;
					var ctx = context;
					ctx.save();
					//ctx.beginPath();
					ctx.translate(posChild.x +d.x,posChild.y+d.y);
					var o = parseFloat(posChild.y-pos.y);
					var a = parseFloat(posChild.x -pos.x);
   
					if(a !=0){
					var rad = Math.atan2(o,a);
					ctx.rotate(rad);
					ctx.moveTo(2,0);
					ctx.lineTo(-r,-4);
					ctx.lineTo(-r,4);

				    ctx.lineTo(2,0);
					ctx.fill();		
					}

					ctx.restore();

				});
			
			}
			
			ttmm.canvas.getContext().lineWidth = "1";

			}
  	
		  };
  
		return controller;

        },

	_setupMapIfNeeded: function(lastOpenNode){
		
		if(!this.canvas){
			this._init_html_elements();
		}
		var ctx = this.canvas.getContext;
		if(!ctx) {console.log("no context available! Please install ExplorerCanvas");}

		if(this.graphloaded) return false;
		
		this.graphloaded = true;
		//this._firstnode =lastOpenNode;


	  	var json = {"id":this.thehiddenbridge,"children":[{"id":lastOpenNode,"name":lastOpenNode, "data":{"parents":[this.thehiddenbridge], "children":[]}, "children":[]}], 'data':{"parents":[], "children":[lastOpenNode]}};
		
		json.data = {};
		json.data.nodraw=true;
	    	this.canvas= new Canvas(this.canvas.id, this.settings.nodeColor, this.settings.lineColor); 
		controller = this._getController();	
		this.rgraph= new RGraph(this.canvas, controller,this.labelContainer);
  


	  	Config['drawConcentricCircles'] = this.graph_showCirclesFlag;
 
	 	this.rgraph.loadTreeFromJSON(json);

		this.controller = controller;
		this.rgraph.compute();
		this.centerOnNode(lastOpenNode);
		//this.rgraph.graph.root = this.controller.getNode(lastOpenNode);	

	  		
				  //if(!this.rgraph.graph.root) this.rgraph.graph.root =this.controller.getNode(this._firstNode);
		return true;
	
	}


};

}}}
/*
 * File: RGraph.js
 * 
 * Author: Nicolas Garcia Belmonte
 * 
 * Copyright: Copyright 2008 by Nicolas Garcia Belmonte.
 *
 * Homepage: <http://thejit.org>
 * 
 * Version: 1.0.7a
 * 
 * License: BSD License
 * 
 *
 * 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.
 * 
 */

/*
   Object: $_

   Provides some common utility functions.
*/
var $_ = {
	fn: function() { return function() {}; },

	merge: function(){
		var mix = {};
		for (var i = 0, l = arguments.length; i < l; i++){
			var object = arguments[i];
			if (typeof object != 'object') continue;
			for (var key in object){
				var op = object[key], mp = mix[key];
				mix[key] = (mp && typeof op == 'object' && typeof mp == 'object') ? this.merge(mp, op) : this.unlink(op);
			}
		}
		return mix;
	},

	unlink: function (object){
		var unlinked = null;
		if(this.isArray(object)) {
				unlinked = [];
				for (var i = 0, l = object.length; i < l; i++) unlinked[i] = this.unlink(object[i]);
		} else if(this.isObject(object)) {
				unlinked = {};
				for (var p in object) unlinked[p] = this.unlink(object[p]);
		} else return object;

		return unlinked;
	},
	
	isArray: function(obj) {
		return obj.constructor.toString().match(/array/i);
	},
	
	isString: function(obj) {
		return obj.constructor.toString().match(/string/i);
	},
	
	isObject: function(obj) {
		return obj.constructor.toString().match(/object/i);
	}
} ;


/*
   Class: Canvas

   A multi-purpose Canvas object decorator.
*/

/*
   Constructor: Canvas

   Canvas initializer.

   Parameters:

      canvasId - The canvas tag id.
      fillStyle - (optional) fill color style. Default's to black
      strokeStyle - (optional) stroke color style. Default's to black

   Returns:

      A new Canvas instance.
*/
var Canvas= function (canvasId, fillStyle, strokeStyle) {
	//browser supports canvas element
		this.canvasId= canvasId;
		this.fillStyle = fillStyle;
		this.strokeStyle = strokeStyle;
		//canvas element exists
		if((this.canvas= document.getElementById(this.canvasId)) 
			&& this.canvas.getContext) {
		      this.ctx = this.canvas.getContext('2d');
		      this.ctx.fillStyle = fillStyle || 'black';
		      this.ctx.strokeStyle = strokeStyle || 'white';
			  this.setPosition();
			  this.translateToCenter();
		
		} else {
			throw "Canvas object could not initialize.";
		}
	
};


Canvas.prototype= {
	/*
	   Method: getContext

	   Returns:
	
	      Canvas context handler.
	*/
	getContext: function () {
		return this.ctx;
	},

	/*
	   Method: setPosition
	
	   Calculates canvas absolute position on HTML document.
	*/	
	setPosition: function() {
		var obj= this.canvas;
		var curleft = curtop = 0;
		if (obj.offsetParent) {
			curleft = obj.offsetLeft
			curtop = obj.offsetTop
			while (obj = obj.offsetParent) {
				curleft += obj.offsetLeft
				curtop += obj.offsetTop
			}
		}
		this.position= { x: curleft, y: curtop };
	},

	/*
	   Method: getPosition

	   Returns:
	
	      Canvas absolute position to the HTML document.
	*/
	getPosition: function() {
		return this.position;
	},

	/*
	   Method: clear
	
	   Clears the canvas object.
	*/		
	clear: function () {
		this.ctx.clearRect(-this.getSize().x / 2, -this.getSize().x / 2, this.getSize().x, this.getSize().x);
	},

	/*
	   Method: drawConcentricCircles
	
	   Draws concentric circles. Receives an integer specifying the number of concentric circles.
	*/		
	drawConcentricCircles: function (elem) {
		var config = Config;
		var times = elem || 6;
		var c = this.ctx;
		c.strokeStyle = config.concentricCirclesColor;
		var pi2 = Math.PI*2;
		for(var i=1; i<=times; i++) {
		    c.beginPath();
		  	c.arc(0, 0, (i*config.levelDistance), 0, pi2, true);
		  	c.stroke();
			c.closePath();
		}
		c.strokeStyle = this.strokeStyle;
	},
	
	/*
	   Method: translateToCenter
	
	   Translates canvas coordinates system to the center of the canvas object.
	*/
	translateToCenter: function() {
		this.ctx.translate(this.canvas.width / 2, this.canvas.height / 2);
	},
	

	/*
	   Method: getSize

	   Returns:
	
	      An object that contains the canvas width and height.
	      i.e. { x: canvasWidth, y: canvasHeight }
	*/
	getSize: function () {
		var width = this.canvas.width;
		var height = this.canvas.height;
		return { x: width, y: height };
	},
	
	/*
	   Method: path
	   
	  Performs a _beginPath_ executes _action_ doing then a _type_ ('fill' or 'stroke') and closing the path with closePath.
	*/
	path: function(type, action) {
		this.ctx.beginPath();
		action(this.ctx);
		this.ctx[type]();
		this.ctx.closePath();
	}
	
};


/*
   Class: Complex
	
	 A multi-purpose Complex Class with common methods.

*/


/*
   Constructor: Complex

   Complex constructor.

   Parameters:

      re - A real number.
      im - An real number representing the imaginary part.


   Returns:

      A new Complex instance.
*/
var Complex= function() {
	if (arguments.length > 1) {
		this.x= arguments[0];
		this.y= arguments[1];
		
	} else {
		this.x= null;
		this.y= null;
	}
	
};

Complex.prototype= {
	/*
	   Method: clone
	
	   Returns a copy of the current object.
	
	   Returns:
	
	      A copy of the real object.
	*/
	clone: function() {
		return new Complex(this.x, this.y);
	},

	/*
	   Method: toPolar
	
	   Transforms cartesian to polar coordinates.
	
	   Returns:
	
	      A new <Polar> instance.
	*/
	
	toPolar: function() {
		var rho = this.norm();
		var atan = Math.atan2(this.y, this.x);
		if(atan < 0) atan += Math.PI * 2;
		return new Polar(atan, rho);
	},
	/*
	   Method: norm
	
	   Calculates the complex norm.
	
	   Returns:
	
	      A real number representing the complex norm.
	*/
	norm: function () {
		return Math.sqrt(this.squaredNorm());
	},
	
	/*
	   Method: squaredNorm
	
	   Calculates the complex squared norm.
	
	   Returns:
	
	      A real number representing the complex squared norm.
	*/
	squaredNorm: function () {
		return this.x*this.x + this.y*this.y;
	},

	/*
	   Method: add
	
	   Returns the result of adding two complex numbers.
	   Does not alter the original object.

	   Parameters:
	
	      pos - A Complex initialized instance.
	
	   Returns:
	
	     The result of adding two complex numbers.
	*/
	add: function(pos) {
		return new Complex(this.x + pos.x, this.y + pos.y);
	},

	/*
	   Method: prod
	
	   Returns the result of multiplying two complex numbers.
	   Does not alter the original object.

	   Parameters:
	
	      pos - A Complex initialized instance.
	
	   Returns:
	
	     The result of multiplying two complex numbers.
	*/
	prod: function(pos) {
		return new Complex(this.x*pos.x - this.y*pos.y, this.y*pos.x + this.x*pos.y);
	},

	/*
	   Method: conjugate
	
	   Returns the conjugate por this complex.

	   Returns:
	
	     The conjugate por this complex.
	*/
	conjugate: function() {
		return new Complex(this.x, -this.y);
	},


	/*
	   Method: scale
	
	   Returns the result of scaling a Complex instance.
	   Does not alter the original object.

	   Parameters:
	
	      factor - A scale factor.
	
	   Returns:
	
	     The result of scaling this complex to a factor.
	*/
	scale: function(factor) {
		return new Complex(this.x * factor, this.y * factor);
	},

	/*
	   Method: equals
	
	   Comparison method.
	*/
	equals: function(c) {
		return this.x == c.x && this.y == c.y;
	},

	/*
	   Method: $add
	
	   Returns the result of adding two complex numbers.
	   Alters the original object.

	   Parameters:
	
	      pos - A Complex initialized instance.
	
	   Returns:
	
	     The result of adding two complex numbers.
	*/
	$add: function(pos) {
		this.x += pos.x; this.y += pos.y;
		return this;	
	},
	
	/*
	   Method: $prod
	
	   Returns the result of multiplying two complex numbers.
	   Alters the original object.

	   Parameters:
	
	      pos - A Complex initialized instance.
	
	   Returns:
	
	     The result of multiplying two complex numbers.
	*/
	$prod:function(pos) {
		var x = this.x, y = this.y
		this.x = x*pos.x - y*pos.y;
		this.y = y*pos.x + x*pos.y;
		return this;
	},
	
	/*
	   Method: $conjugate
	
	   Returns the conjugate for this complex.
	   Alters the original object.

	   Returns:
	
	     The conjugate for this complex.
	*/
	$conjugate: function() {
		this.y = -this.y;
		return this;
	},
	
	/*
	   Method: $scale
	
	   Returns the result of scaling a Complex instance.
	   Alters the original object.

	   Parameters:
	
	      factor - A scale factor.
	
	   Returns:
	
	     The result of scaling this complex to a factor.
	*/
	$scale: function(factor) {
		this.x *= factor; this.y *= factor;
		return this;
	},
	
	/*
	   Method: $div
	
	   Returns the division of two complex numbers.
	   Alters the original object.

	   Parameters:
	
	      pos - A Complex number.
	
	   Returns:
	
	     The result of scaling this complex to a factor.
	*/
	$div: function(pos) {
		var x = this.x, y = this.y;
		var sq = pos.squaredNorm();
		this.x = x * pos.x + y * pos.y; this.y = y * pos.x - x * pos.y;
		return this.$scale(1 / sq);
	}
};

Complex.KER = new Complex(0, 0);

/*
   Class: Polar

   A multi purpose polar representation.

*/

/*
   Constructor: Polar

   Polar constructor.

   Parameters:

      theta - An angle.
      rho - The norm.


   Returns:

      A new Polar instance.
*/

var Polar = function(theta, rho) {
	this.theta = theta;
	this.rho = rho;
};

Polar.prototype = {
	/*
	   Method: clone
	
	   Returns a copy of the current object.
	
	   Returns:
	
	      A copy of the real object.
	*/
	clone: function() {
		return new Polar(this.theta, this.rho);
	},

	/*
	   Method: toComplex
	
	    Translates from polar to cartesian coordinates and returns a new <Complex> instance.
	
	   Returns:
	
	      A new Complex instance.
	*/
	toComplex: function() {
		return new Complex(Math.cos(this.theta), Math.sin(this.theta)).$scale(this.rho);
	},

	/*
	   Method: add
	
	    Adds two <Polar> instances.
	
	   Returns:
	
	      A new Polar instance.
	*/
	add: function(polar) {
		return new Polar(this.theta + polar.theta, this.rho + polar.rho);
	},
	
	/*
	   Method: scale
	
	    Scales a polar norm.
	
	   Returns:
	
	      A new Polar instance.
	*/
	scale: function(number) {
		return new Polar(this.theta, this.rho * number);
	},
	
	/*
	   Method: equals
	
	   Comparison method.
	*/
	equals: function(c) {
		return this.theta == c.theta && this.rho == c.rho;
	},
	
	/*
	   Method: $add
	
	    Adds two <Polar> instances affecting the current object.
	
	   Returns:
	
	      The changed object.
	*/
	$add: function(polar) {
		this.theta = this.theta + polar.theta; this.rho += polar.rho;
		return this;
	},

	/*
	   Method: $madd
	
	    Adds two <Polar> instances affecting the current object. The resulting theta angle is modulo 2pi.
	
	   Returns:
	
	      The changed object.
	*/
	$madd: function(polar) {
		this.theta = (this.theta + polar.theta) % (Math.PI * 2); this.rho += polar.rho;
		return this;
	},

	
	/*
	   Method: $scale
	
	    Scales a polar instance affecting the object.
	
	   Returns:
	
	      The changed object.
	*/
	$scale: function(number) {
		this.rho *= number;
		return this;
	},
	
	/*
	   Method: interpolate
	
	    Calculates a polar interpolation between two points at a given delta moment.
	
	   Returns:
	
	      A new Polar instance representing an interpolation between _this_ and _elem_
	*/
	interpolate: function(elem, delta) {
		var pi2 = Math.PI * 2;
		var ch = function(t) {
			return (t < 0)? (t % pi2) + pi2 : t % pi2;
		};
		var tt = ch(this.theta) , et = ch(elem.theta);
		var sum;
		if(Math.abs(tt - et) > Math.PI) {
			if(tt - et > 0) {
				sum =ch((et + ((tt - pi2) - et)* delta)) ;
			} else {
				sum =ch((et - pi2 + (tt - (et - pi2))* delta));
			}
			
		} else {
				sum =ch((et + (tt - et)* delta)) ;
		}
		var  t = (sum);
		var r = (this.rho - elem.rho) * delta + elem.rho;
		return new Polar(t, r);
	}
};

Polar.KER = new Polar(0, 0);


/*
   Object: Config

   <RGraph> global configuration object. Contains important properties to enable customization and proper behavior for the <RGraph>.
*/

var Config= {
		//Property: labelContainer
		//Id for label container. The label container is a div dom element that must be explicitly added to your page in order to enable the RGraph.
		labelContainer: 'label_container',
		
		//Property: drawConcentricCircles
		//show/hide concentricCircles
		drawConcentricCircles: 4,
		
		//Property: concentricCirclesColor
		//The color of the concentric circles
		concentricCirclesColor: '#444',

		//Property: levelDistance
		//The actual distance between levels
		levelDistance: 100,
		
		//Property: nodeRadius
		//The radius of the nodes displayed
		nodeRadius: 4,
		
		//Property: allowVariableNodeDiameters
		//Set this to true if you want your node diameters to be proportional to you first dataset object value property (i.e _data[0].value_).
		//This will allow you to represent weighted tree/graph nodes.
		allowVariableNodeDiameters: false,
		
		//Property: nodeRangeDiameters
		//Diameters range. For variable node weights.
		nodeRangeDiameters: {
			min: 10,
			max: 35
		},
			
		//Property: nodeRangeValues
		// The interval of the values of the first object of your dataSet.
		// A superset of the values can also be specified.
		nodeRangeValues: {
			min: 1,
			max: 35
		},

		//Property: fps
		//animation frames per second
		fps:40,
		
		//Property: animationTime
		animationTime: 2500,
		
		//Property: interpolation
		interpolation: 'linear'
};

/*
   Object: GraphUtil

   A multi purpose object to do graph traversal and processing.
*/
var GraphUtil = {
	/*
	   Method: filter
	
	   For internal use only. Provides a filtering function based on flags.
	*/
	filter: function(param) {
		if(!param || !$_.isString(param)) return function() { return true; };
		var props = param.split(" ");
		return function(elem) {
			for(var i=0; i<props.length; i++) if(elem[props[i]]) return false;
			return true;
		};
	},
	/*
	   Method: getNode
	
	   Returns a graph's node with a specified _id_.
	*/
	getNode: function(graph, id) {
		return graph.getNode(id);
	},
	
	/*
	   Method: eachNode
	
	   Iterates over graph nodes performing an action.
	*/
	eachNode: function(graph, action, flags) {
		var filter = this.filter(flags);
		for(var i in graph.nodes) if(filter(graph.nodes[i])) action(graph.nodes[i]);
	},
	
	/*
	   Method: eachAdjacency
	
	   Iterates over a _node_ adjacencies applying the _action_ function.
	*/
	eachAdjacency: function(node, action, flags) {
		var adj = node.adjacencies, filter = this.filter(flags);
		for(var id in adj) if(filter(adj[id])) action(adj[id], id);
	},

	/*
	   Method: computeLevels
	
	   Performs a BFS traversal setting correct level for nodes.
	*/
	computeLevels: function(graph, id, flags) {
		var filter = this.filter(flags);
		this.eachNode(graph, function(elem) {
			elem._flag = false;
			elem._depth = -1;
		}, flags);
		var root = graph.getNode(id);
		root._depth = 0;
		var queue = [root];
		while(queue.length != 0) {
			var node = queue.pop();
			node._flag = true;
			this.eachAdjacency(node, function(adj) {
				var n = adj.nodeTo;
				if(n._flag == false && filter(n)) {
					if(n._depth < 0) n._depth = node._depth + 1;
					queue.unshift(n);
				}
			}, flags);
		}
	},

	/*
	   Method: eachBFS
	
	   Performs a BFS traversal of a graph beginning by the node of id _id_ and performing _action_ on each node.
	   This traversal ignores nodes or edges having the property _ignore_ setted to _true_.
	*/
	eachBFS: function(graph, id, action, flags) {
		var filter = this.filter(flags);
		this.clean(graph);
		var queue = [graph.getNode(id)];
		while(queue.length != 0) {
			var node = queue.pop();
			node._flag = true;
			action(node, node._depth);
			this.eachAdjacency(node, function(adj) {
				var n = adj.nodeTo;
				if(n._flag == false && filter(n)) {
					n._flag = true;
					queue.unshift(n);
				}
			}, flags);
		}
	},
	
	/*
	   Method: eachSubnode
	
	   After a BFS traversal the _depth_ property of each node has been modified. Now the graph can be traversed as a tree. This method iterates for each subnode that has depth larger than the specified node.
	*/
	eachSubnode: function(graph, node, action, flags) {
		var d = node._depth, filter = this.filter(flags);
		this.eachAdjacency(node, function(adj) {
			var n = adj.nodeTo;
			if(n._depth > d && filter(n)) action(n);
		}, flags);
	},
	
	/*
	   Method: getSubnodes
	
	   Collects all subnodes for a specified node. The _level_ parameter filters nodes having relative depth of _level_ from the root node.
	*/
	getSubnodes: function(graph, id, level, flags) {
		var ans = new Array(), that = this, node = graph.getNode(id);
		(function(graph, node) {
			var fn = arguments.callee;
			if(!level || level <= node._depth)	ans.push(node);
			that.eachSubnode(graph, node, function(elem) {
				fn(graph, elem);
			}, flags);
		})(graph, node);
		return ans;
	},

	/*
	   Method: getParents
	
	   Returns all nodes having a depth that is less than the node's depth property.
	*/
	getParents: function(graph, node) {
		var adj = node.adjacencies;
		var ans = new Array();
		this.eachAdjacency(node, function(adj) {
			var n = adj.nodeTo;
			if(n._depth < node._depth) ans.push(n);
		});
		return ans;
	},
	
	/*
	   Method: clean
	
	   Cleans flags from nodes (by setting the _flag_ property to false).
	*/
	clean: function(graph) { this.eachNode(graph, function(elem) { elem._flag = false; }); }
};

/*
   Object: GraphOp

   An object holding unary and binary graph operations such as removingNodes, removingEdges, adding two graphs and morphing.
*/
var GraphOp = {

	options: {
		type: 'nothing',
		duration: 2000,
		fps:30
	},
	
	/*
	   Method: removeNode
	
	   Removes one or more nodes from the visualization. It can also perform several animations like fading sequentially, fading concurrently, iterating or replotting.

	   Parameters:
	
	      viz - The visualization object (an RGraph instance in this case).
	      node - The node's id. Can also be an array having many ids.
	      opt - Animation options. It's an object with two properties: _type_, which can be _nothing_, _replot_, _fade:seq_,  _fade:con_ or _iter_. The other property is the _duration_ in milliseconds. 
	
	*/
	removeNode: function(viz, node, opt) {
		var options = $_.merge(viz.controller, this.options, opt);
		var n = $_.isString(node)? [node] : node;
		switch(options.type) {
			case 'nothing':
				for(var i=0; i<n.length; i++) 	viz.graph.removeNode(n[i]);
				break;
			
			case 'replot':
				this.removeNode(viz, n, { type: 'nothing' });
				GraphPlot.clearLabels(viz);
				viz.refresh();
				break;
			
			case 'fade:seq': case 'fade':
				var GPlot = GraphPlot, that = this;
				//set alpha to 0 for nodes to remove.
				for(var i=0; i<n.length; i++) {
					var nodeObj = viz.graph.getNode(n[i]);
					nodeObj.endAlpha = 0;
				}
				GPlot.animate(viz, $_.merge(options, {
					modes: ['fade:nodes'],
					onComplete: function() {
						that.removeNode(viz, n, { type: 'nothing' });
						GPlot.clearLabels(viz);
						viz.compute('endPos');
						GPlot.animate(viz, $_.merge(options, {
							modes: ['linear']
						}));
					}
				}));
				break;
			
			case 'fade:con':
				var GPlot = GraphPlot, that = this;
				//set alpha to 0 for nodes to remove. Tag them for being ignored on computing positions.
				for(var i=0; i<n.length; i++) {
					var nodeObj = viz.graph.getNode(n[i]);
					nodeObj.endAlpha = 0;
					nodeObj.ignore = true;
				}
				viz.compute('endPos');
				GPlot.animate(viz, $_.merge(options, {
					modes: ['fade:nodes', 'linear'],
					onComplete: function() {
						that.removeNode(viz, n, { type: 'nothing' });
					}
				}));
				break;
			
			case 'iter':
				var that = this, GPlot = GraphPlot;
				GPlot.sequence(viz, {
					condition: function() { return n.length != 0; },
					step: function() { that.removeNode(viz, n.shift(), { type: 'nothing' });  GPlot.clearLabels(viz); },
					onComplete: function() { options.onComplete(); },
					duration: Math.ceil(options.duration / n.length)
				});
				break;
				
			default: this.doError();
		}
	},
	
	/*
	   Method: removeEdge
	
	   Removes one or more edges from the visualization. It can also perform several animations like fading sequentially, fading concurrently, iterating or replotting.

	   Parameters:
	
	      viz - The visualization object (an RGraph instance in this case).
	      vertex - An array having two strings which are the ids of the nodes connected by this edge: ['id1', 'id2']. Can also be a two dimensional array holding many edges: [['id1', 'id2'], ['id3', 'id4'], ...].
	      opt - Animation options. It's an object with two properties: _type_, which can be _nothing_, _replot_, _fade:seq_,  _fade:con_ or _iter_. The other property is the _duration_ in milliseconds. 
	
	*/
	removeEdge: function(viz, vertex, opt) {
		var options = $_.merge(viz.controller, this.options, opt);
		var v = $_.isString(vertex[0])? [vertex] : vertex;
		switch(options.type) {
			case 'nothing':
				for(var i=0; i<v.length; i++) 	viz.graph.removeAdjacence(v[i][0], v[i][1]);
				break;
			
			case 'replot':
				this.removeEdge(viz, v, { type: 'nothing' });
				viz.refresh();
				break;
			
			case 'fade:seq': case 'fade':
				var GPlot = GraphPlot, that = this;
				//set alpha to 0 for nodes to remove.
				for(var i=0; i<v.length; i++) {
					var adjs = viz.graph.getAdjacence(v[i][0], v[i][1]);
					if(adjs) {
						adjs[0].endAlpha = 0;
						adjs[1].endAlpha = 0;
					}
				}
				GPlot.animate(viz, $_.merge(options, {
					modes: ['fade:vertex'],
					onComplete: function() {
						that.removeEdge(viz, v, { type: 'nothing' });
						viz.compute('endPos');
						GPlot.animate(viz, $_.merge(options, {
							modes: ['linear']
						}));
					}
				}));
				break;
			
			case 'fade:con':
				var GPlot = GraphPlot, that = this;
				//set alpha to 0 for nodes to remove. Tag them for being ignored when computing positions.
				for(var i=0; i<v.length; i++) {
					var adjs = viz.graph.getAdjacence(v[i][0], v[i][1]);
					if(adjs) {
						adjs[0].endAlpha = 0;
						adjs[0].ignore = true;
						adjs[1].endAlpha = 0;
						adjs[1].ignore = true;
					}
				}
				viz.compute('endPos');
				GPlot.animate(viz, $_.merge(options, {
					modes: ['fade:vertex', 'linear'],
					onComplete: function() {
						that.removeEdge(viz, v, { type: 'nothing' });
					}
				}));
				break;
			
			case 'iter':
				var that = this, GPlot = GraphPlot;
				GPlot.sequence(viz, {
					condition: function() { return v.length != 0; },
					step: function() { that.removeEdge(viz, v.shift(), { type: 'nothing' }); GPlot.clearLabels(viz); },
					onComplete: function() { options.onComplete(); },
					duration: Math.ceil(options.duration / v.length)
				});
				break;
				
			default: this.doError();
		}
	},
	
	/*
	   Method: sum
	
	   Adds a new graph to the visualization. The json graph (or tree) must at least have a common node with the current graph plotted by the visualization. The resulting graph can be defined as follows: <http://mathworld.wolfram.com/GraphSum.html>

	   Parameters:
	
	      viz - The visualization object (an RGraph instance in this case).
	      json - A json tree <http://blog.thejit.org/2008/04/27/feeding-json-tree-structures-to-the-jit/>, a json graph <http://blog.thejit.org/2008/07/02/feeding-json-graph-structures-to-the-jit/> or an extended json graph <http://blog.thejit.org/2008/08/05/weighted-nodes-weighted-edges/>.
	      opt - Animation options. It's an object with two properties: _type_, which can be _nothing_, _replot_, _fade:seq_,  or _fade:con_. The other property is the _duration_ in milliseconds. 
	
	*/
	sum: function(viz, json, opt) {
		var options = $_.merge(viz.controller, this.options, opt), root = viz.root;
		viz.root = opt.id || viz.root;
		switch(options.type) {
			case 'nothing':
				var graph = viz.construct(json), GUtil = GraphUtil;
				GUtil.eachNode(graph, function(elem) {
					GUtil.eachAdjacency(elem, function(adj) {
						viz.graph.addAdjacence(adj.nodeFrom, adj.nodeTo, adj.data);
					});
				});
				break;
			
			case 'replot':
				this.sum(viz, json, { type: 'nothing' });
				viz.refresh();
				break;
			
			case 'fade:seq': case 'fade': case 'fade:con':
				var GUtil = GraphUtil, GPlot = GraphPlot, that = this, graph = viz.construct(json);
				//set alpha to 0 for nodes to add.
				var fadeEdges = this.preprocessSum(viz, graph);
				var modes = !fadeEdges? ['fade:nodes'] : ['fade:nodes', 'fade:vertex'];
				viz.compute('endPos');
				if(options.type != 'fade:con') {
					GPlot.animate(viz, $_.merge(options, {
						modes: ['linear'],
						onComplete: function() {
							GPlot.animate(viz, $_.merge(options, {
								modes: modes,
								onComplete: function() {
									options.onComplete();
								}
							}));
						}
					}));
				} else {
					GUtil.eachNode(viz.graph, function(elem) {
						if(elem.id != root && elem.pos.equals(Polar.KER)) elem.pos = elem.startPos = elem.endPos;
					});
					GPlot.animate(viz, $_.merge(options, {
						modes: ['linear'].concat(modes),
						onComplete: function() {
							options.onComplete();
						}
					}));
				}
				break;

			default: this.doError();
		}
	},
	
	/*
	   Method: morph
	
	   This method will _morph_ the current visualized graph into the new _json_ representation passed in the method. Can also perform multiple animations. The _json_ object must at least have the root node in common with the current visualized graph.

	   Parameters:
	
	      viz - The visualization object (an RGraph instance in this case).
	      json - A json tree <http://blog.thejit.org/2008/04/27/feeding-json-tree-structures-to-the-jit/>, a json graph <http://blog.thejit.org/2008/07/02/feeding-json-graph-structures-to-the-jit/> or an extended json graph <http://blog.thejit.org/2008/08/05/weighted-nodes-weighted-edges/>.
	      opt - Animation options. It's an object with two properties: _type_, which can be _nothing_, _replot_, or _fade_. The other property is the _duration_ in milliseconds. 
	
	*/
	morph: function(viz, json, opt) {
		var options = $_.merge(viz.controller, this.options, opt), root = viz.root;
		viz.root = opt.id || viz.root;
		switch(options.type) {
			case 'nothing':
				var graph = viz.construct(json), GUtil = GraphUtil;
				GUtil.eachNode(graph, function(elem) {
					GUtil.eachAdjacency(elem, function(adj) {
						viz.graph.addAdjacence(adj.nodeFrom, adj.nodeTo, adj.data);
					});
				});
				GUtil.eachNode(viz.graph, function(elem) {
					GUtil.eachAdjacency(elem, function(adj) {
						if(!graph.getAdjacence(adj.nodeFrom.id, adj.nodeTo.id)) {
							viz.graph.removeAdjacence(adj.nodeFrom.id, adj.nodeTo.id);
						}
						if(!viz.graph.hasNode(elem.id)) viz.graph.removeNode(elem.id);
					});
				});
				
				break;
			
			case 'replot':
				this.morph(viz, json, { type: 'nothing' });
				viz.refresh();
				break;
			
			case 'fade:seq': case 'fade': case 'fade:con':
				var GUtil = GraphUtil, GPlot = GraphPlot, that = this, graph = viz.construct(json);
				//preprocessing for adding nodes.
				var fadeEdges = this.preprocessSum(viz, graph);
				//preprocessing for nodes to delete.
				GUtil.eachNode(viz.graph, function(elem) {
					if(!graph.hasNode(elem.id)) {
						elem.alpha = 1; elem.startAlpha = 1; elem.endAlpha = 0; elem.ignore = true;
					}
				});	
				GUtil.eachNode(viz.graph, function(elem) {
					if(elem.ignore) return;
					GUtil.eachAdjacency(elem, function(adj) {
						if(adj.nodeFrom.ignore || adj.nodeTo.ignore) return;
						var nodeFrom = graph.getNode(adj.nodeFrom.id);
						var nodeTo = graph.getNode(adj.nodeTo.id);
						if(!nodeFrom.adjacentTo(nodeTo)) {
							var adjs = viz.graph.getAdjacence(nodeFrom.id, nodeTo.id);
							fadeEdges = true;
							adjs[0].alpha = 1; adjs[0].startAlpha = 1; adjs[0].endAlpha = 0; adjs[0].ignore = true;
							adjs[1].alpha = 1; adjs[1].startAlpha = 1; adjs[1].endAlpha = 0; adjs[1].ignore = true;
						}
					});
				});	
				var modes = !fadeEdges? ['fade:nodes'] : ['fade:nodes', 'fade:vertex'];
				viz.compute('endPos');
				GUtil.eachNode(viz.graph, function(elem) {
					if(elem.id != root && elem.pos.equals(Polar.KER)) elem.pos = elem.startPos = elem.endPos;
				});
				GPlot.animate(viz, $_.merge(options, {
					modes: ['polar'].concat(modes),
					onComplete: function() {
						GUtil.eachNode(viz.graph, function(elem) {
							if(elem.ignore) viz.graph.removeNode(elem.id);
						});
						GUtil.eachNode(viz.graph, function(elem) {
							GUtil.eachAdjacency(elem, function(adj) {
								if(adj.ignore) viz.graph.removeAdjacence(adj.nodeFrom.id, adj.nodeTo.id);
							});
						});
						options.onComplete();
					}
				}));
				break;

			default: this.doError();
		}
	},
	
	preprocessSum: function(viz, graph) {
		var GUtil = GraphUtil;
		GUtil.eachNode(graph, function(elem) {
			if(!viz.graph.hasNode(elem.id)) {
				viz.graph.addNode(elem);
				var n = viz.graph.getNode(elem.id);
				n.alpha = 0; n.startAlpha = 0; n.endAlpha = 1;
			}
		});	
		var fadeEdges = false;
		GUtil.eachNode(graph, function(elem) {
			GUtil.eachAdjacency(elem, function(adj) {
				var nodeFrom = viz.graph.getNode(adj.nodeFrom.id);
				var nodeTo = viz.graph.getNode(adj.nodeTo.id);
				if(!nodeFrom.adjacentTo(nodeTo)) {
					var adjs = viz.graph.addAdjacence(nodeFrom, nodeTo, adj.data);
					if(nodeFrom.startAlpha == nodeFrom.endAlpha 
					&& nodeTo.startAlpha == nodeTo.endAlpha) {
						fadeEdges = true;
						adjs[0].alpha = 0; adjs[0].startAlpha = 0; adjs[0].endAlpha = 1;
						adjs[1].alpha = 0; adjs[1].startAlpha = 0; adjs[1].endAlpha = 1;
					} 
				}
			});
		});	
		return fadeEdges;
	}
};


/*
   Object: GraphPlot

   An object that performs specific radial layouts for a generic graph structure.
*/
var GraphPlot = {

	Interpolator: {
		'polar': function(elem, delta) {
			var from = elem.startPos;
			var to = elem.endPos;
			elem.pos = to.interpolate(from, delta);
		},
		
		'linear': function(elem, delta) {
			var from = elem.startPos.toComplex();
			var to = elem.endPos.toComplex();
			elem.pos = ((to.$add(from.scale(-1))).$scale(delta).$add(from)).toPolar();
		},
		
		'fade:nodes': function(elem, delta) {
			if(elem.endAlpha != elem.alpha) {
				var from = elem.startAlpha;
				var to   = elem.endAlpha;
				elem.alpha = from + (to - from) * delta;
			}
		},
		
		'fade:vertex': function(elem, delta) {
			var adjs = elem.adjacencies;
			for(var id in adjs) this['fade:nodes'](adjs[id], delta);
		}
	},

	//Property: labelsHidden
	//A flag value indicating if node labels are being displayed or not.
	labelsHidden: false,
	//Property: labelContainer
	//Label DOM element
	labelContainer: false,
	//Property: labels
	//Label DOM elements hash.
	labels: {},

	/*
	   Method: getLabelContainer
	
	   Lazy fetcher for the label container.
	*/
	getLabelContainer: function() {
		return this.labelContainer? this.labelContainer : this.labelContainer = document.getElementById(Config.labelContainer);
	},
	
	/*
	   Method: getLabel
	
	   Lazy fetcher for the label DOM element.
	*/
	getLabel: function(id) {
		return (id in this.labels && this.labels[id] != null)? this.labels[id] : this.labels[id] = document.getElementById(id);
	},
	
	/*
	   Method: hideLabels
	
	   Hides all labels.
	*/
	hideLabels: function (hide) {
		var container = this.getLabelContainer();
		if(hide) container.style.display = 'none';
		else container.style.display = '';
		this.labelsHidden = hide;
	},

	/*
	   Method: clearLabels
	
	   Clears the label container.
	*/
	clearLabels: function(viz) {
		for(var id in this.labels) 
			if(!viz.graph.hasNode(id)) {
				this.disposeLabel(id);
				delete this.labels[id];
			}
	},
	
	/*
	   Method: disposeLabel
	
	   Removes a label.
	*/
	disposeLabel: function(id) {
		var elem = this.getLabel(id);
		if(elem && elem.parentNode) {
			elem.parentNode.removeChild(elem);
		}  
	},
	
	/*
	   Method: animate
	
	   Animates the graph mantaining a radial layout.
	*/
	animate: function(viz, opt) {
		var that = this, GUtil = GraphUtil, Anim = Animation, duration = opt.duration || Anim.duration, fps = opt.fps || Anim.fps;
		//Should be changed eventually, when Animation becomes a class.
		var prevDuration = Anim.duration, prevFps = Anim.fps;
		
		Anim.duration = duration;
		Anim.fps = fps;
		
		if(opt.hideLabels) this.hideLabels(true);
		var animationController = {
			compute: function(delta) {
				GUtil.eachNode(viz.graph, function(node) { 
					for(var i=0; i<opt.modes.length; i++) {
							that.Interpolator[opt.modes[i]](node, delta);
					}
				});
				that.plot(viz, opt);
			},

			complete: function() {
				GUtil.eachNode(viz.graph, function(node) { 
					node.startPos = node.pos;
					node.startAlpha = node.alpha;
				});
				if(opt.hideLabels) that.hideLabels(false);
				that.plot(viz, opt);
				Anim.duration = prevDuration;
				Anim.fps = prevFps;
				opt.onComplete();
				opt.onAfterCompute();
			}		
		};
		Anim.controller = animationController;
		Anim.start();
	},


	/*
	   Method: sequence
	
	   Iteratively performs an action while refreshing the state of the visualization.
	*/
	sequence: function(viz, options) {
		options = $_.merge({
			condition: function() { return false; },
			step: $_.fn(),
			onComplete: $_.fn(),
			duration: 200
		}, options);

		var interval = setInterval(function() {
			if(options.condition()) {
				options.step();
			} else {
				clearInterval(interval);
				options.onComplete();
			}
			viz.refresh();
		}, options.duration);
	},

	/*
	   Method: plot
	
	   Plots a Graph.
	*/
	plot: function(viz, opt) {
		var aGraph = viz.graph, canvas = viz.canvas, id = viz.root;
		var that = this, ctx = canvas.getContext(), GUtil = GraphUtil;
		canvas.clear();
		if(Config.drawConcentricCircles) canvas.drawConcentricCircles(Config.drawConcentricCircles);
		var T = !!aGraph.getNode(id).visited;
		GUtil.eachNode(aGraph, function(node) {
			GUtil.eachAdjacency(node, function(adj) {
				if(!!adj.nodeTo.visited === T) {
					opt.onBeforePlotLine(adj);
					ctx.save();
					ctx.globalAlpha = Math.min(Math.min(node.alpha, adj.nodeTo.alpha), adj.alpha);
					that.plotLine(adj, canvas);
					ctx.restore();
					opt.onAfterPlotLine(adj);
				}
			});
			ctx.save();
			ctx.globalAlpha = node.alpha;
			that.plotNode(node, canvas);
	 		if(!that.labelsHidden && ctx.globalAlpha >= .95) that.plotLabel(canvas, node, opt);
	 		else if(!that.labelsHidden && ctx.globalAlpha < .95) that.hideLabel(node);
			ctx.restore();
			node.visited = !T;
		});
	},
	
	
	/*
	   Method: plotNode
	
	   Plots a graph node.
	*/
	plotNode: function(node, canvas) {
		var pos = node.pos.toComplex();
		canvas.path('fill', function(context) {
			context.arc(pos.x, pos.y, node._radius, 0, Math.PI*2, true);			
		});
	},
	
	/*
	   Method: plotLine
	
	   Plots a line connecting _node_ and _child_ nodes.
	*/
	plotLine: function(adj, canvas) {
		var node = adj.nodeFrom, child = adj.nodeTo;
		var pos = node.pos.toComplex();
		var posChild = child.pos.toComplex();
		canvas.path('stroke', function(context) {
			context.moveTo(pos.x, pos.y);
		  	context.lineTo(posChild.x, posChild.y);
		});
	},
	
	/*
	   Method: hideLabel
	
	   Hides a label having _node.id_ as id.
	*/
	hideLabel: function(node) {
		var n; if(n = document.getElementById(node.id)) n.style.display = "none";
	},
	
	/*
	   Method: plotLabel
	
	   Plots a label for a given node.
	*/
	plotLabel: function(canvas, node, controller) {
		var size = node._radius, id = node.id, tag = this.getLabel(id);
		if(!tag && !(tag = document.getElementById(id))) {
			tag = document.createElement('div');
			var container = this.getLabelContainer();
			container.appendChild(tag);
			tag.id = id;
			tag.className = 'node';
			tag.style.position = 'absolute';
			controller.onCreateLabel(tag, node);
		}
		var pos = node.pos.toComplex();
		var radius= canvas.getSize();
		var cpos = canvas.getPosition();
		var labelPos= {
			x: Math.round(pos.x + cpos.x + radius.x/2 - size /2),
			y: Math.round(pos.y + cpos.y + radius.y/2 - size /2)
		};
		tag.style.width = size + 'px';
		tag.style.height = size + 'px';
		tag.style.left = labelPos.x + 'px';
		tag.style.top = labelPos.y  + 'px';
		tag.style.display = this.fitsInCanvas(labelPos, canvas)? '' : 'none';
		controller.onPlaceLabel(tag, node);
	},
	
	/*
	   Method: fitsInCanvas
	
	   Returns _true_ or _false_ if the label for the node is contained on the canvas dom element or not.
	*/
	fitsInCanvas: function(pos, canvas) {
		var size = canvas.getSize();
		if(pos.x >= size.x + canvas.position.x || pos.x < canvas.position.x 
			|| pos.y >= size.y + canvas.position.y || pos.y < canvas.position.y) return false;
		return true;					
	}
};

/*
   Class: RGraph

	An animated Graph with radial layout.

	Go to <http://blog.thejit.org> to know what kind of JSON structure feeds this object.
	
	Go to <http://blog.thejit.org/?p=8> to know what kind of controller this class accepts.
	
	Refer to the <Config> object to know what properties can be modified in order to customize this object. 

	The simplest way to create and layout a RGraph is:
	
	(start code)

	  var canvas= new Canvas('infovis', '#ccddee', '#772277');
	  var rgraph= new RGraph(canvas, controller);
	  rgraph.loadTreeFromJSON(json);
	  rgraph.compute();
	  rgraph.plot();

	(end code)

	A user should only interact with the Canvas, RGraph and Config objects/classes.
	By implementing RGraph controllers you can also customize the RGraph behavior.
*/

/*
 Constructor: RGraph

 Creates a new RGraph instance.
 
 Parameters:

    canvas - A <Canvas> instance.
    controller - _optional_ a RGraph controller <http://blog.thejit.org/?p=8>
*/
var RGraph = function(canvas, controller) {
	var innerController = {
		onBeforeCompute: $_.fn(),
		onAfterCompute:  $_.fn(),
		onCreateLabel:   $_.fn(),
		onPlaceLabel:    $_.fn(),
		onCreateElement: $_.fn(),
		onComplete:      $_.fn(),
		onBeforePlotLine: $_.fn(),
		onAfterPlotLine: $_.fn(),
		request:         false
	};
	this.controller = $_.merge(innerController, controller);
	this.graph = new Graph();
	this.json = null;
	this.canvas = canvas;
	this.root = null;
	this.busy = false;
	
	Animation.duration = Config.animationTime;
	Animation.fps = Config.fps;
	
};

RGraph.prototype = {
	
	
	construct: function(json) {
		var isGraph = $_.isArray(json);
		var ans = new Graph();
		if(!isGraph) 
			//make tree
			(function (ans, json) {
				ans.addNode(json);
				for(var i=0, ch = json.children; i<ch.length; i++) {
					ans.addAdjacence(json, ch[i]);
					arguments.callee(ans, ch[i]);
				}
			})(ans, json);
		else
			//make graph
			(function (ans, json) {
				var getNode = function(id) {
					for(var w=0; w<json.length; w++) if(json[w].id == id) return json[w];
				};
				for(var i=0; i<json.length; i++) {
					ans.addNode(json[i]);
					for(var j=0, adj = json[i].adjacencies; j<adj.length; j++) {
						var node = adj[j], data;
						if(typeof adj[j] != 'string') {
							data = node.data;
							node = node.nodeTo;
						}
						ans.addAdjacence(json[i], getNode(node), data);
					}
				}
			})(ans, json);

		return ans;
	},
	
	/*
	 Method: loadTree
	
	 Loads a Graph from a json tree object <http://blog.thejit.org>
	 
	*/
	loadTree: function(json) {
		this.graph = this.construct(json);
	},

	/*
	 Method: loadGraph
	
	 Loads a Graph from a json graph object <http://blog.thejit.org>
	 
	*/
	loadGraph: function(json) {
		this.graph = this.construct(json);
	},
	
	/*
	 Method: refresh
	
	 Computes positions and then plots.
	 
	*/
	refresh: function() {
		this.compute();
		this.plot();
	},
	
  /*
	 Method: flagRoot
	
	 Flags a node specified by _id_ as root.
	*/
	flagRoot: function(id) {
		this.unflagRoot();
		this.graph.nodes[id]._root = true;
	},

	/*
	 Method: unflagRoot
	
	 Unflags all nodes.
	*/
	unflagRoot: function() {
		GraphUtil.eachNode(this.graph, function(elem) {elem._root = false;});
	},

	/*
	 Method: getRoot
	
	 Returns the node flagged as root.
	*/
	getRoot: function() {
		var root = false;
		GraphUtil.eachNode(this.graph, function(elem){ if(elem._root) root = elem; });
		return root;
	},
	
	/*
	 Method: loadTreeFromJSON
	
	 Loads a RGraph from a _json_ object <http://blog.thejit.org>
	*/
	loadTreeFromJSON: function(json) {
		this.json = json;
		this.loadTree(json);
		this.root = json.id;
	},
	
	/*
	 Method: loadGraphFromJSON
	
	 Loads a RGraph from a _json_ object <http://blog.thejit.org>
	*/
	loadGraphFromJSON: function(json, i) {
		this.json = json;
		this.loadGraph(json);
		this.root = json[i? i : 0].id;
	},
	
	
	/*
	 Method: plot
	
	 Plots the RGraph
	*/
	plot: function() {
		GraphPlot.plot(this, this.controller);
	},
	
	/*
	 Method: compute
	
	 Computes the graph nodes positions and stores this positions on _property_.
	*/
	compute: function(property) {
		var prop = property || ['pos', 'startPos', 'endPos'];
		var node = this.graph.getNode(this.root);
		node._depth = 0;
		this.flagRoot(this.root);
		GraphUtil.computeLevels(this.graph, this.root, "ignore");
		this.computeAngularWidths();
		this.computePositions(prop);
	},
	
	/*
	 Method: computePositions
	
	 Performs the main algorithm for computing node positions.
	*/
	computePositions: function(property) {
		var propArray = (typeof property == 'array' || typeof property == 'object')? property : [property];
		var aGraph = this.graph;
		var GUtil = GraphUtil;
		var root = this.graph.getNode(this.root);

		for(var i=0; i<propArray.length; i++)
			root[propArray[i]] = new Polar(0, 0);
		
		root.angleSpan = {
			begin: 0,
			end: 2 * Math.PI
		};
		root._rel = 1;
		
		GUtil.eachBFS(this.graph, this.root, function (elem) {
			var angleSpan = elem.angleSpan.end - elem.angleSpan.begin;
			var rho = (elem._depth + 1) * Config.levelDistance;
			var angleInit = elem.angleSpan.begin;
			var totalAngularWidths = (function (element){
				var total = 0;
				GUtil.eachSubnode(aGraph, element, function(sib) {
					total += sib._treeAngularWidth;
				}, "ignore");
				return total;
			})(elem);
			
			GUtil.eachSubnode(aGraph, elem, function(child) {
				if(!child._flag) {
					child._rel = child._treeAngularWidth / totalAngularWidths;
					var angleProportion = child._rel * angleSpan;
					var theta = angleInit + angleProportion / 2;

					for(var i=0; i<propArray.length; i++)
						child[propArray[i]] = new Polar(theta, rho);

					child.angleSpan = {
						begin: angleInit,
						end: angleInit + angleProportion
					};
					angleInit += angleProportion;
				}
			}, "ignore");
		}, "ignore");
	},


	
	/*
	 Method: setAngularWidthForNodes
	
	 Sets nodes angular widths.
	*/
	setAngularWidthForNodes: function() {
		var rVal = Config.nodeRangeValues, rDiam = Config.nodeRangeDiameters, nr = Config.nodeRadius, allow = Config.allowVariableNodeDiameters; 
		var diam = function(value) { return (((rDiam.max - rDiam.min)/(rVal.max - rVal.min)) * (value - rVal.min) + rDiam.min) };
		GraphUtil.eachBFS(this.graph, this.root, function(elem, i) {
			var dataValue = (allow && elem.data && elem.data.length > 0)? elem.data[0].value : nr;
			var diamValue = diam(dataValue);
			var rho = Config.levelDistance * i;
			elem._angularWidth = diamValue / rho;
			elem._radius = allow? diamValue / 2 : nr;
		}, "ignore");
	},
	
	/*
	 Method: setSubtreesAngularWidths
	
	 Sets subtrees angular widths.
	*/
	setSubtreesAngularWidth: function() {
		var that = this;
		GraphUtil.eachNode(this.graph, function(elem) {
			that.setSubtreeAngularWidth(elem);
		}, "ignore");
	},
	
	/*
	 Method: setSubtreeAngularWidth
	
	 Sets the angular width for a subtree.
	*/
	setSubtreeAngularWidth: function(elem) {
		var that = this, nodeAW = elem._angularWidth, sumAW = 0;
		GraphUtil.eachSubnode(this.graph, elem, function(child) {
			that.setSubtreeAngularWidth(child);
			sumAW += child._treeAngularWidth;
		}, "ignore");
		elem._treeAngularWidth = Math.max(nodeAW, sumAW);
	},
	
	/*
	 Method: computeAngularWidths
	
	 Computes nodes and subtrees angular widths.
	*/
	computeAngularWidths: function () {
		this.setAngularWidthForNodes();
		this.setSubtreesAngularWidth();
	},
	
	/*
	 Method: getNodeAndParentAngle
	
	 Returns the _parent_ of the given node, also calculating its angle span.
	*/
	getNodeAndParentAngle: function(id) {
		var theta = false;
		var n  = this.graph.getNode(id);
		var ps = GraphUtil.getParents(this.graph, n);
		var p  = (ps.length > 0)? ps[0] : false;
		if(p) {
			var posParent = p.pos.toComplex(), posChild = n.pos.toComplex();
			var newPos    = posParent.add(posChild.scale(-1));
			theta = (function(pos) {
				var t = Math.atan2(pos.y, pos.x);
				if(t < 0) t = 2 * Math.PI + t;
				return t;
			})(newPos);
		}
		return {_parent: p, theta: theta};
		
	},
	
	/*
	 Method: onClick
	
	 Performs all calculations and animation when clicking on a label specified by _id_. The label id is the same id as its homologue node.
	*/
	onClick: function(id) {		
		if(this.root != id && !this.busy) {
			this.busy = true;
			//we apply first constraint to the algorithm
			var obj = this.getNodeAndParentAngle(id);
			this.root = id, that = this;
			this.controller.onBeforeCompute(this.graph.getNode(id));
			var thetaDiff = obj.theta - obj._parent.endPos.theta;

												GraphUtil.eachNode(this.graph, function(elem) {
				elem.endPos = elem.endPos.add(new Polar(thetaDiff, 0));
			});
			
			var mode = (Config.interpolation == 'linear')? 'linear' : 'polar';


			GraphPlot.animate(this, $_.merge(this.controller, {
				hideLabels:true,
				modes: [mode],
				onComplete: function() {
					that.busy = false;
				}
			}));
				}		

	}
};

/*
 Class: Graph

 A generic Graph class.
 
*/	

/*
 Constructor: Graph

 Creates a new Graph instance.
 
*/	
var Graph= function()  {
	//Property: nodes
	//graph nodes
	this.nodes= {};
};
	
	
Graph.prototype= {

/*
	 Method: getNode
	
	 Returns a <Graph.Node> from a specified _id_.
*/	
 getNode: function(id) {
 	if(this.hasNode(id)) 	return this.nodes[id];
 	return false;
 },


/*
	 Method: getAdjacence
	
	 Returns an array of <Graph.Adjacence> that connects nodes with id _id_ and _id2_.
*/	
  getAdjacence: function (id, id2) {
	var adjs = [];
	if(this.hasNode(id) 	&& this.hasNode(id2) 
	&& this.nodes[id].adjacentTo({ 'id':id2 }) && this.nodes[id2].adjacentTo({ 'id':id })) {
		adjs.push(this.nodes[id].getAdjacency(id2));
		adjs.push(this.nodes[id2].getAdjacency(id));
		return adjs;
	}
	return false;	
 },

	/*
	 Method: addNode
	
	 Adds a node.
	 
	 Parameters:
	
	    obj - A <Graph.Node> object.
	*/	
  addNode: function(obj) {
  	if(!this.nodes[obj.id]) {
	  	this.nodes[obj.id] = new Graph.Node(obj.id, obj.name, obj.data);
  	}
  	return this.nodes[obj.id];
  },
  
	/*
	 Method: addAdjacence
	
	 Connects nodes specified by *obj* and *obj2*. If not found, nodes are created.
	 
	 Parameters:
	
	    obj - a <Graph.Node> object.
	    obj2 - Another <Graph.Node> object.
	    data - A DataSet object.
	*/	
  addAdjacence: function (obj, obj2, weight) {
  	var adjs = []
  	if(!this.hasNode(obj.id)) this.addNode(obj);
  	if(!this.hasNode(obj2.id)) this.addNode(obj2);
	obj = this.nodes[obj.id]; obj2 = this.nodes[obj2.id];
	
  	for(var i in this.nodes) {
  		if(this.nodes[i].id == obj.id) {
  			if(!this.nodes[i].adjacentTo(obj2)) {
  				adjs.push(this.nodes[i].addAdjacency(obj2, weight));
  			}
  		}
  		
  		if(this.nodes[i].id == obj2.id) {	
  			if(!this.nodes[i].adjacentTo(obj)) {
  				adjs.push(this.nodes[i].addAdjacency(obj, weight));
  			}
  		}
  	}
  	return adjs;
 },

	/*
	 Method: removeNode
	
	 Removes a <Graph.Node> from <Graph> that matches the specified _id_.
	*/	
  removeNode: function(id) {
  	if(this.hasNode(id)) {
  		var node = this.nodes[id];
  		for(var i=0 in node.adjacencies) {
  			var adj = node.adjacencies[i];
  			this.removeAdjacence(id, adj.nodeTo.id);
  		}
  		delete this.nodes[id];
  	}
  },
  
/*
	 Method: removeAdjacence
	
	 Removes a <Graph.Adjacence> from <Graph> that matches the specified _id1_ and _id2_.
*/	
  removeAdjacence: function(id1, id2) {
  	if(this.hasNode(id1)) this.nodes[id1].removeAdjacency(id2);
  	if(this.hasNode(id2)) this.nodes[id2].removeAdjacency(id1);
  },

	/*
	 Method: hasNode
	
	 Returns a Boolean instance indicating if node belongs to graph or not.
	 
	 Parameters:
	
	    id - Node id.

	 Returns:
	  
	 		A Boolean instance indicating if node belongs to graph or not.
	*/	
  hasNode: function(id) {
	return id in this.nodes;
  }
};
/*
   Class: Graph.Node
	
	 Behaviour of the <Graph> node.

*/
/*
   Constructor: Graph.Node

   Node constructor.

   Parameters:

      id - The node *unique identifier* id.
      name - A node's name.
      data - Place to store some extra information (can be left to null).


   Returns:

      A new <Graph.Node> instance.
*/
Graph.Node = function(id, name, data) {
	//Property: id
	//A node's id
	this.id= id;
	//Property: name
	//A node's name
	this.name = name;
	//Property: data
	//The dataSet object <http://blog.thejit.org/?p=7>
	this.data = data;
	//Property: drawn
	//Node flag
	this.drawn= false;
	//Property: angle span
	//allowed angle span for adjacencies placement
	this.angleSpan= {
		begin:0,
		end:0
	};
	//Property: pos
	//node position
	this.pos= new Polar(0, 0);
	//Property: startPos
	//node from position
	this.startPos= new Polar(0, 0);
	//Property: endPos
	//node to position
	this.endPos= new Polar(0, 0);
	//Property: alpha
	//node alpha
	this.alpha = 1;
	//Property: startAlpha
	//node start alpha
	this.startAlpha = 1;
	//Property: endAlpha
	//node end alpha
	this.endAlpha = 1;
	//Property: adjacencies
	//node adjacencies
	this.adjacencies= {};
};

Graph.Node.prototype= {
	
	/*
	   Method: adjacentTo
	
	   Indicates if the node is adjacent to the node indicated by the specified id

	   Parameters:
	
	      id - A node id.
	
	   Returns:
	
	     A Boolean instance indicating whether this node is adjacent to the specified by id or not.
	*/
	adjacentTo: function(node) {
		return node.id in this.adjacencies;
	},

	/*
	   Method: getAdjacency
	
	   Returns a <Graph.Adjacence> that connects the current <Graph.Node> with the node having _id_ as id.

	   Parameters:
	
	      id - A node id.
	*/	
	getAdjacency: function(id) {
		return this.adjacencies[id];
	},
	/*
	   Method: addAdjacency
	
	   Connects the node to the specified by id.

	   Parameters:
	
	      id - A node id.
	*/	
	addAdjacency: function(node, data) {
		var adj = new Graph.Adjacence(this, node, data);
		return this.adjacencies[node.id] = adj;
	},
	
	/*
	   Method: removeAdjacency
	
	   Deletes the <Graph.Adjacence> by _id_.

	   Parameters:
	
	      id - A node id.
	*/	
	removeAdjacency: function(id) {
		delete this.adjacencies[id];
	}
};
/*
   Class: Graph.Adjacence
	
	 Creates a new <Graph> adjacence.

*/
Graph.Adjacence = function(nodeFrom, nodeTo, data) {
	//Property: nodeFrom
	//One of the two <Graph.Node>s connected by this edge.
	this.nodeFrom = nodeFrom;
	//Property: nodeTo
	//One of the two <Graph.Node>s connected by this edge.
	this.nodeTo = nodeTo;
	//Property: data
	//A dataset object
	this.data = data;
	//Property: alpha
	//node alpha
	this.alpha = 1;
	//Property: startAlpha
	//node start alpha
	this.startAlpha = 1;
	//Property: endAlpha
	//node end alpha
	this.endAlpha = 1;
};

/*
   Object: Trans
	
	 An object containing multiple type of transformations. Based on the mootools library <http://mootools.net>.

*/
var Trans = {
	linear: function(p) { return p;	},
	Quart: function(p) {
		return Math.pow(p, 4);
	},
	easeIn: function(transition, pos){
		return transition(pos);
	},
	easeOut: function(transition, pos){
		return 1 - transition(1 - pos);
	},
	easeInOut: function(transition, pos){
		return (pos <= 0.5) ? transition(2 * pos) / 2 : (2 - transition(2 * (1 - pos))) / 2;
	}
};

/*
   Object: Animation
	
	 An object that performs animations. Based on Fx.Base from Mootools.

*/

var Animation = {

	duration: Config.animationTime,
	fps: Config.fps,
	transition: function(p) {return Trans.easeInOut(Trans.Quart, p);},
	//transition: Trans.linear,
	controller: false,
	
	getTime: function() {
		var ans = (Date.now)? Date.now() : new Date().getTime();
		return ans;
	},
	
	step: function(){
		var time = this.getTime();
		if (time < this.time + this.duration){
			var delta = this.transition((time - this.time) / this.duration);
			this.controller.compute(delta);
		} else {
			this.timer = clearInterval(this.timer);
			this.controller.compute(1);
			this.controller.complete();
		}
	},

	start: function(){
		this.time = 0;
		this.startTimer();
		return this;
	},

	startTimer: function(){
		if (this.timer) return false;
		this.time = this.getTime() - this.time;
		this.timer = setInterval((function () { Animation.step(); }), Math.round(1000 / this.fps));
		return true;
	}
};
/*Jon's JIT Hacks */

Config.animationTime = 1000;

/*RGRAPH*/
RGraph.prototype.offsetCenter= function(x,y){
	var d =this.controller.getOffset();
	d.x = x;
	d.y = y;
	this.controller.setOffset(d);
};

RGraph.prototype.setAngularWidthForNodes= function() {
	var rVal = Config.nodeRangeValues, rDiam = Config.nodeRangeDiameters, nr = Config.nodeRadius, allow = Config.allowVariableNodeDiameters; 
	
	var zoom = this.controller.getZoomLevel();
	var diam = function(value) { return (((rDiam.max - rDiam.min)/(rVal.max - rVal.min)) * (value - rVal.min) + rDiam.min) };
	GraphUtil.eachBFS(this.graph, this.root, function(elem, i) {
		var dataValue = (allow && elem.data && elem.data.length > 0)? elem.data[0].value : nr;
		var diamValue = diam(dataValue);

		var rho = zoom * i;//jon
		elem._angularWidth = diamValue / rho;
		elem._radius = allow? diamValue / 2 : nr;
	}, "ignore");
};



RGraph.prototype.computePositions= function(property) {
	var propArray = (typeof property == 'array' || typeof property == 'object')? property : [property];
	var aGraph = this.graph;
	var GUtil = GraphUtil;
	var root = this.graph.getNode(this.root);

	for(var i=0; i<propArray.length; i++)
		root[propArray[i]] = new Polar(0, 0);
	
	root.angleSpan = {
		begin: 0,
		end: 2 * Math.PI
	};
	root._rel = 1;
	var zoom =this.controller.getZoomLevel();
	GUtil.eachBFS(this.graph, this.root, function (elem) {
		var angleSpan = elem.angleSpan.end - elem.angleSpan.begin;
		var rho = (elem._depth + 1) * zoom;//jon
		var angleInit = elem.angleSpan.begin;
		var totalAngularWidths = (function (element){
			var total = 0;
			GUtil.eachSubnode(aGraph, element, function(sib) {
				total += sib._treeAngularWidth;
			}, "ignore");
			return total;
		})(elem);
		
		GUtil.eachSubnode(aGraph, elem, function(child) {
			if(!child._flag) {
				child._rel = child._treeAngularWidth / totalAngularWidths;
				var angleProportion = child._rel * angleSpan;
				var theta = angleInit + angleProportion / 2;

				for(var i=0; i<propArray.length; i++)
					child[propArray[i]] = new Polar(theta, rho);

				child.angleSpan = {
					begin: angleInit,
					end: angleInit + angleProportion
				};
				angleInit += angleProportion;
			}
		}, "ignore");
	}, "ignore");
};



RGraph.prototype.onClick= function(id) { //weird bug in here
		
		if(this.root != id) {//jon
			this.busy = true;
			//we apply first constraint to the algorithm
			var obj = this.getNodeAndParentAngle(id);
			this.root = id, that = this;
			this.controller.onBeforeCompute(this.graph.getNode(id));

			this.compute('endPos');

			var thetaDiff = obj.theta - obj._parent.endPos.theta;

			GraphUtil.eachNode(this.graph, function(elem) {
				elem.endPos = elem.endPos.add(new Polar(thetaDiff, 0));
			});
			
			var mode = (Config.interpolation == 'linear')? 'linear' : 'polar';


			this.controller.modes = [mode];//jon
			GraphPlot.animate(this, this.controller);//jon
		}

};
/*GRAPH PLOT */

GraphPlot.plotLine = function(adj, canvas,controller) {//jon
	var d = controller.getOffset();//jon
	var node = adj.nodeFrom, child = adj.nodeTo;
	var pos = node.pos.toComplex();
	var posChild = child.pos.toComplex();
	canvas.path('stroke', function(context) {
		
		pos.x += d.x;//jon..
		pos.y += d.y;
		posChild.x += d.x;
		posChild.y += d.y;//..jon
		
		context.moveTo(pos.x, pos.y);
	  	context.lineTo(posChild.x, posChild.y);
		
		 

			
		
	});
};


GraphPlot.getLabelContainer = function(controller){
	return document.getElementById(controller.getNodeLabelContainer());
};



GraphPlot.fitsInCanvas= function(pos, canvas) {
	//canvas.setPosition();
    var size = canvas.getSize();
	var offset1 = parseInt(size.x);
	var offset2 = parseInt(size.y);
	if(pos.x <  0 || pos.x > offset1 || pos.y < 0 || pos.y > offset2) return false;
	else
	  return true;						
};

GraphPlot.plotLabel= function(canvas, node, controller) {
	
	var size = node._radius;
	var id = controller.getNodeLabelPrefix() + node.id;//jon change
	var d = controller.getOffset(); //jon

	var pos = node.pos.toComplex();
	var radius= canvas.getSize();
	canvas.setPosition(); //jon
	var cpos = canvas.getPosition();
	
	var labelPos= {
		x: Math.round((pos.x  + radius.x/2 - size /2) +d.x),//jon
		y: Math.round((pos.y + radius.y/2 - size /2) +d.y)//jon
	};

	var tag = this.getLabel(id);
	
	if(!this.fitsInCanvas(labelPos,canvas)) {
		
		//if(tag && tag.parentNode)tag.parentNode.removeChild(tag);
		return;
	}
	
	if(!tag && !(tag = document.getElementById(id))) {
		tag = document.createElement('div');
		var container = this.getLabelContainer(controller); //jon change
		container.style.position= 'relative';//jon change
		container.appendChild(tag);
		tag.id = id;
		tag.className = 'node';
		tag.style.position = 'absolute';
		controller.onCreateLabel(tag, node);
	}

	tag.style.width = size + 'px';
	tag.style.height = size + 'px';
	tag.style.left = labelPos.x + 'px';
	tag.style.top = labelPos.y  + 'px';
	tag.style.display = this.fitsInCanvas(labelPos, canvas)? '' : 'none';
	controller.onPlaceLabel(tag, node);
};


/*overriding of several functions */
GraphPlot.plotNode =  function(node, canvas,controller) {
	var pos = node.pos.toComplex();
	var d = controller.getOffset();

	if(node.data.nodraw == undefined)  		//jon
	canvas.path('fill', function(context) {
  		context.arc(pos.x +d.x, pos.y +d.y, node._radius, 0, Math.PI*2, true);	//jon

	});		
};


GraphPlot.plot= function(viz, opt) {

	var aGraph = viz.graph, canvas = viz.canvas, id = viz.root;

	var controller = viz.controller;//jon
	var container = this.getLabelContainer(controller); //jon change
	
	container.innerHTML = "";
	var that = this, ctx = canvas.getContext(), GUtil = GraphUtil;
	canvas.clear();
	if(Config.drawConcentricCircles) canvas.drawConcentricCircles(Config.drawConcentricCircles);
	var T = !!aGraph.getNode(id).visited;
	GUtil.eachNode(aGraph, function(node) {
		GUtil.eachAdjacency(node, function(adj) {
			if(!!adj.nodeTo.visited === T) {
				opt.onBeforePlotLine(adj);
				ctx.save();
				ctx.globalAlpha = Math.min(Math.min(node.alpha, adj.nodeTo.alpha), adj.alpha);
				that.plotLine(adj, canvas,controller);//jon
				ctx.restore();
				opt.onAfterPlotLine(adj);
			}
		});
		ctx.save();
		ctx.globalAlpha = node.alpha;
		that.plotNode(node, canvas,controller); //jon
 		if(!that.labelsHidden && ctx.globalAlpha >= .95) that.plotLabel(canvas, node, opt);
 		else if(!that.labelsHidden && ctx.globalAlpha < .95) that.hideLabel(node);
		ctx.restore();
		node.visited = !T;
	});
};


/***
!Layer 4: Support Internet Explorer (Safely remove if not required)
***/

// Copyright 2006 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.


// Known Issues:
//
// * Patterns are not implemented.
// * Radial gradient are not implemented. The VML version of these look very
//   different from the canvas one.
// * Clipping paths are not implemented.
// * Coordsize. The width and height attribute have higher priority than the
//   width and height style values which isn't correct.
// * Painting mode isn't implemented.
// * Canvas width/height should is using content-box by default. IE in
//   Quirks mode will draw the canvas using border-box. Either change your
//   doctype to HTML5
//   (http://www.whatwg.org/specs/web-apps/current-work/#the-doctype)
//   or use Box Sizing Behavior from WebFX
//   (http://webfx.eae.net/dhtml/boxsizing/boxsizing.html)
// * Non uniform scaling does not correctly scale strokes.
// * Optimize. There is always room for speed improvements.

// Only add this code if we do not already have a canvas implementation
if (!document.createElement('canvas').getContext) {

(function() {

  // alias some functions to make (compiled) code shorter
  var m = Math;
  var mr = m.round;
  var ms = m.sin;
  var mc = m.cos;
  var max = m.max;
  var abs = m.abs;
  var sqrt = m.sqrt;

  // this is used for sub pixel precision
  var Z = 10;
  var Z2 = Z / 2;

  /**
   * This funtion is assigned to the <canvas> elements as element.getContext().
   * @this {HTMLElement}
   * @return {CanvasRenderingContext2D_}
   */
  function getContext() {
    return this.context_ ||
        (this.context_ = new CanvasRenderingContext2D_(this));
  }

  var slice = Array.prototype.slice;

  /**
   * Binds a function to an object. The returned function will always use the
   * passed in {@code obj} as {@code this}.
   *
   * Example:
   *
   *   g = bind(f, obj, a, b)
   *   g(c, d) // will do f.call(obj, a, b, c, d)
   *
   * @param {Function} f The function to bind the object to
   * @param {Object} obj The object that should act as this when the function
   *     is called
   * @param {*} var_args Rest arguments that will be used as the initial
   *     arguments when the function is called
   * @return {Function} A new function that has bound this
   */
  function bind(f, obj, var_args) {
    var a = slice.call(arguments, 2);
    return function() {
      return f.apply(obj, a.concat(slice.call(arguments)));
    };
  }

  var G_vmlCanvasManager_ = {
    init: function(opt_doc) {
      if (/MSIE/.test(navigator.userAgent) && !window.opera) {
        var doc = opt_doc || document;
        // Create a dummy element so that IE will allow canvas elements to be
        // recognized.
        doc.createElement('canvas');
        doc.attachEvent('onreadystatechange', bind(this.init_, this, doc));
      }
    },

    init_: function(doc) {
      // create xmlns
      if (!doc.namespaces['g_vml_']) {
        doc.namespaces.add('g_vml_', 'urn:schemas-microsoft-com:vml');
      }

      // Setup default CSS.  Only add one style sheet per document
      if (!doc.styleSheets['ex_canvas_']) {
        var ss = doc.createStyleSheet();
        ss.owningElement.id = 'ex_canvas_';
        ss.cssText = 'canvas{display:inline-block;overflow:hidden;' +
            // default size is 300x150 in Gecko and Opera
            'text-align:left;width:300px;height:150px}' +
            'g_vml_\\:*{behavior:url(#default#VML)}';
      }

      // find all canvas elements
      var els = doc.getElementsByTagName('canvas');
      for (var i = 0; i < els.length; i++) {
        this.initElement(els[i]);
      }
    },

    /**
     * Public initializes a canvas element so that it can be used as canvas
     * element from now on. This is called automatically before the page is
     * loaded but if you are creating elements using createElement you need to
     * make sure this is called on the element.
     * @param {HTMLElement} el The canvas element to initialize.
     * @return {HTMLElement} the element that was created.
     */
    initElement: function(el) {
      if (!el.getContext) {

        el.getContext = getContext;

        // do not use inline function because that will leak memory
        el.attachEvent('onpropertychange', onPropertyChange);
        el.attachEvent('onresize', onResize);

        var attrs = el.attributes;
        if (attrs.width && attrs.width.specified) {
          // TODO: use runtimeStyle and coordsize
          // el.getContext().setWidth_(attrs.width.nodeValue);
          el.style.width = attrs.width.nodeValue + 'px';
        } else {
          el.width = el.clientWidth;
        }
        if (attrs.height && attrs.height.specified) {
          // TODO: use runtimeStyle and coordsize
          // el.getContext().setHeight_(attrs.height.nodeValue);
          el.style.height = attrs.height.nodeValue + 'px';
        } else {
          el.height = el.clientHeight;
        }
        //el.getContext().setCoordsize_()
      }
      return el;
    }
  };

  function onPropertyChange(e) {
    var el = e.srcElement;

    switch (e.propertyName) {
      case 'width':
        el.style.width = el.attributes.width.nodeValue + 'px';
        el.getContext().clearRect();
        break;
      case 'height':
        el.style.height = el.attributes.height.nodeValue + 'px';
        el.getContext().clearRect();
        break;
    }
  }

  function onResize(e) {
    var el = e.srcElement;
    if (el.firstChild) {
      el.firstChild.style.width =  el.clientWidth + 'px';
      el.firstChild.style.height = el.clientHeight + 'px';
    }
  }

  G_vmlCanvasManager_.init();

  // precompute "00" to "FF"
  var dec2hex = [];
  for (var i = 0; i < 16; i++) {
    for (var j = 0; j < 16; j++) {
      dec2hex[i * 16 + j] = i.toString(16) + j.toString(16);
    }
  }

  function createMatrixIdentity() {
    return [
      [1, 0, 0],
      [0, 1, 0],
      [0, 0, 1]
    ];
  }

  function matrixMultiply(m1, m2) {
    var result = createMatrixIdentity();

    for (var x = 0; x < 3; x++) {
      for (var y = 0; y < 3; y++) {
        var sum = 0;

        for (var z = 0; z < 3; z++) {
          sum += m1[x][z] * m2[z][y];
        }

        result[x][y] = sum;
      }
    }
    return result;
  }

  function copyState(o1, o2) {
    o2.fillStyle     = o1.fillStyle;
    o2.lineCap       = o1.lineCap;
    o2.lineJoin      = o1.lineJoin;
    o2.lineWidth     = o1.lineWidth;
    o2.miterLimit    = o1.miterLimit;
    o2.shadowBlur    = o1.shadowBlur;
    o2.shadowColor   = o1.shadowColor;
    o2.shadowOffsetX = o1.shadowOffsetX;
    o2.shadowOffsetY = o1.shadowOffsetY;
    o2.strokeStyle   = o1.strokeStyle;
    o2.globalAlpha   = o1.globalAlpha;
    o2.arcScaleX_    = o1.arcScaleX_;
    o2.arcScaleY_    = o1.arcScaleY_;
    o2.lineScale_    = o1.lineScale_;
  }

  function processStyle(styleString) {
    var str, alpha = 1;

    styleString = String(styleString);
    if (styleString.substring(0, 3) == 'rgb') {
      var start = styleString.indexOf('(', 3);
      var end = styleString.indexOf(')', start + 1);
      var guts = styleString.substring(start + 1, end).split(',');

      str = '#';
      for (var i = 0; i < 3; i++) {
        str += dec2hex[Number(guts[i])];
      }

      if (guts.length == 4 && styleString.substr(3, 1) == 'a') {
        alpha = guts[3];
      }
    } else {
      str = styleString;
    }

    return [str, alpha];
  }

  function processLineCap(lineCap) {
    switch (lineCap) {
      case 'butt':
        return 'flat';
      case 'round':
        return 'round';
      case 'square':
      default:
        return 'square';
    }
  }

  /**
   * This class implements CanvasRenderingContext2D interface as described by
   * the WHATWG.
   * @param {HTMLElement} surfaceElement The element that the 2D context should
   * be associated with
   */
  function CanvasRenderingContext2D_(surfaceElement) {
    this.m_ = createMatrixIdentity();

    this.mStack_ = [];
    this.aStack_ = [];
    this.currentPath_ = [];

    // Canvas context properties
    this.strokeStyle = '#000';
    this.fillStyle = '#000';

    this.lineWidth = 1;
    this.lineJoin = 'miter';
    this.lineCap = 'butt';
    this.miterLimit = Z * 1;
    this.globalAlpha = 1;
    this.canvas = surfaceElement;

    var el = surfaceElement.ownerDocument.createElement('div');
    el.style.width =  surfaceElement.clientWidth + 'px';
    el.style.height = surfaceElement.clientHeight + 'px';
    el.style.overflow = 'hidden';
    el.style.position = 'absolute';
    surfaceElement.appendChild(el);

    this.element_ = el;
    this.arcScaleX_ = 1;
    this.arcScaleY_ = 1;
    this.lineScale_ = 1;
  }

  var contextPrototype = CanvasRenderingContext2D_.prototype;
  contextPrototype.clearRect = function() {
    this.element_.innerHTML = '';
    this.currentPath_ = [];
  };

  contextPrototype.beginPath = function() {
    // TODO: Branch current matrix so that save/restore has no effect
    //       as per safari docs.
    this.currentPath_ = [];
  };

  contextPrototype.moveTo = function(aX, aY) {
    var p = this.getCoords_(aX, aY);
    this.currentPath_.push({type: 'moveTo', x: p.x, y: p.y});
    this.currentX_ = p.x;
    this.currentY_ = p.y;
  };

  contextPrototype.lineTo = function(aX, aY) {
    var p = this.getCoords_(aX, aY);
    this.currentPath_.push({type: 'lineTo', x: p.x, y: p.y});

    this.currentX_ = p.x;
    this.currentY_ = p.y;
  };

  contextPrototype.bezierCurveTo = function(aCP1x, aCP1y,
                                            aCP2x, aCP2y,
                                            aX, aY) {
    var p = this.getCoords_(aX, aY);
    var cp1 = this.getCoords_(aCP1x, aCP1y);
    var cp2 = this.getCoords_(aCP2x, aCP2y);
    bezierCurveTo(this, cp1, cp2, p);
  };

  // Helper function that takes the already fixed cordinates.
  function bezierCurveTo(self, cp1, cp2, p) {
    self.currentPath_.push({
      type: 'bezierCurveTo',
      cp1x: cp1.x,
      cp1y: cp1.y,
      cp2x: cp2.x,
      cp2y: cp2.y,
      x: p.x,
      y: p.y
    });
    self.currentX_ = p.x;
    self.currentY_ = p.y;
  }

  contextPrototype.quadraticCurveTo = function(aCPx, aCPy, aX, aY) {
    // the following is lifted almost directly from
    // http://developer.mozilla.org/en/docs/Canvas_tutorial:Drawing_shapes

    var cp = this.getCoords_(aCPx, aCPy);
    var p = this.getCoords_(aX, aY);

    var cp1 = {
      x: this.currentX_ + 2.0 / 3.0 * (cp.x - this.currentX_),
      y: this.currentY_ + 2.0 / 3.0 * (cp.y - this.currentY_)
    };
    var cp2 = {
      x: cp1.x + (p.x - this.currentX_) / 3.0,
      y: cp1.y + (p.y - this.currentY_) / 3.0
    };

    bezierCurveTo(this, cp1, cp2, p);
  };

  contextPrototype.arc = function(aX, aY, aRadius,
                                  aStartAngle, aEndAngle, aClockwise) {
    aRadius *= Z;
    var arcType = aClockwise ? 'at' : 'wa';

    var xStart = aX + mc(aStartAngle) * aRadius - Z2;
    var yStart = aY + ms(aStartAngle) * aRadius - Z2;

    var xEnd = aX + mc(aEndAngle) * aRadius - Z2;
    var yEnd = aY + ms(aEndAngle) * aRadius - Z2;

    // IE won't render arches drawn counter clockwise if xStart == xEnd.
    if (xStart == xEnd && !aClockwise) {
      xStart += 0.125; // Offset xStart by 1/80 of a pixel. Use something
                       // that can be represented in binary
    }

    var p = this.getCoords_(aX, aY);
    var pStart = this.getCoords_(xStart, yStart);
    var pEnd = this.getCoords_(xEnd, yEnd);

    this.currentPath_.push({type: arcType,
                           x: p.x,
                           y: p.y,
                           radius: aRadius,
                           xStart: pStart.x,
                           yStart: pStart.y,
                           xEnd: pEnd.x,
                           yEnd: pEnd.y});

  };

  contextPrototype.rect = function(aX, aY, aWidth, aHeight) {
    this.moveTo(aX, aY);
    this.lineTo(aX + aWidth, aY);
    this.lineTo(aX + aWidth, aY + aHeight);
    this.lineTo(aX, aY + aHeight);
    this.closePath();
  };

  contextPrototype.strokeRect = function(aX, aY, aWidth, aHeight) {
    // Will destroy any existing path (same as FF behaviour)
    this.beginPath();
    this.moveTo(aX, aY);
    this.lineTo(aX + aWidth, aY);
    this.lineTo(aX + aWidth, aY + aHeight);
    this.lineTo(aX, aY + aHeight);
    this.closePath();
    this.stroke();
    this.currentPath_ = [];
  };

  contextPrototype.fillRect = function(aX, aY, aWidth, aHeight) {
    // Will destroy any existing path (same as FF behaviour)
    this.beginPath();
    this.moveTo(aX, aY);
    this.lineTo(aX + aWidth, aY);
    this.lineTo(aX + aWidth, aY + aHeight);
    this.lineTo(aX, aY + aHeight);
    this.closePath();
    this.fill();
    this.currentPath_ = [];
  };

  contextPrototype.createLinearGradient = function(aX0, aY0, aX1, aY1) {
    return new CanvasGradient_('gradient');
  };

  contextPrototype.createRadialGradient = function(aX0, aY0,
                                                   aR0, aX1,
                                                   aY1, aR1) {
    var gradient = new CanvasGradient_('gradientradial');
    gradient.radius1_ = aR0;
    gradient.radius2_ = aR1;
    gradient.focus_.x = aX0;
    gradient.focus_.y = aY0;
    return gradient;
  };

  contextPrototype.drawImage = function(image, var_args) {
    var dx, dy, dw, dh, sx, sy, sw, sh;

    // to find the original width we overide the width and height
    var oldRuntimeWidth = image.runtimeStyle.width;
    var oldRuntimeHeight = image.runtimeStyle.height;
    image.runtimeStyle.width = 'auto';
    image.runtimeStyle.height = 'auto';

    // get the original size
    var w = image.width;
    var h = image.height;

    // and remove overides
    image.runtimeStyle.width = oldRuntimeWidth;
    image.runtimeStyle.height = oldRuntimeHeight;

    if (arguments.length == 3) {
      dx = arguments[1];
      dy = arguments[2];
      sx = sy = 0;
      sw = dw = w;
      sh = dh = h;
    } else if (arguments.length == 5) {
      dx = arguments[1];
      dy = arguments[2];
      dw = arguments[3];
      dh = arguments[4];
      sx = sy = 0;
      sw = w;
      sh = h;
    } else if (arguments.length == 9) {
      sx = arguments[1];
      sy = arguments[2];
      sw = arguments[3];
      sh = arguments[4];
      dx = arguments[5];
      dy = arguments[6];
      dw = arguments[7];
      dh = arguments[8];
    } else {
      throw Error('Invalid number of arguments');
    }

    var d = this.getCoords_(dx, dy);

    var w2 = sw / 2;
    var h2 = sh / 2;

    var vmlStr = [];

    var W = 10;
    var H = 10;

    // For some reason that I've now forgotten, using divs didn't work
    vmlStr.push(' <g_vml_:group',
                ' coordsize="', Z * W, ',', Z * H, '"',
                ' coordorigin="0,0"' ,
                ' style="width:', W, ';height:', H, ';position:absolute;');

    // If filters are necessary (rotation exists), create them
    // filters are bog-slow, so only create them if abbsolutely necessary
    // The following check doesn't account for skews (which don't exist
    // in the canvas spec (yet) anyway.

    if (this.m_[0][0] != 1 || this.m_[0][1]) {
      var filter = [];

      // Note the 12/21 reversal
      filter.push('M11=', this.m_[0][0], ',',
                  'M12=', this.m_[1][0], ',',
                  'M21=', this.m_[0][1], ',',
                  'M22=', this.m_[1][1], ',',
                  'Dx=', mr(d.x / Z), ',',
                  'Dy=', mr(d.y / Z), '');

      // Bounding box calculation (need to minimize displayed area so that
      // filters don't waste time on unused pixels.
      var max = d;
      var c2 = this.getCoords_(dx + dw, dy);
      var c3 = this.getCoords_(dx, dy + dh);
      var c4 = this.getCoords_(dx + dw, dy + dh);

      max.x = max(max.x, c2.x, c3.x, c4.x);
      max.y = max(max.y, c2.y, c3.y, c4.y);

      vmlStr.push('padding:0 ', mr(max.x / Z), 'px ', mr(max.y / Z),
                  'px 0;filter:progid:DXImageTransform.Microsoft.Matrix(',
                  filter.join(''), ", sizingmethod='clip');")
    } else {
      vmlStr.push('top:', mr(d.y / Z), 'px;left:', mr(d.x / Z), 'px;');
    }

    vmlStr.push(' ">' ,
                '<g_vml_:image src="', image.src, '"',
                ' style="width:', Z * dw, ';',
                ' height:', Z * dh, ';"',
                ' cropleft="', sx / w, '"',
                ' croptop="', sy / h, '"',
                ' cropright="', (w - sx - sw) / w, '"',
                ' cropbottom="', (h - sy - sh) / h, '"',
                ' />',
                '</g_vml_:group>');

    this.element_.insertAdjacentHTML('BeforeEnd',
                                    vmlStr.join(''));
  };

  contextPrototype.stroke = function(aFill) {
    var lineStr = [];
    var lineOpen = false;
    var a = processStyle(aFill ? this.fillStyle : this.strokeStyle);
    var color = a[0];
    var opacity = a[1] * this.globalAlpha;

    var W = 10;
    var H = 10;

    lineStr.push('<g_vml_:shape',
                 ' filled="', !!aFill, '"',
                 ' style="position:absolute;width:', W, ';height:', H, ';"',
                 ' coordorigin="0 0" coordsize="', Z * W, ' ', Z * H, '"',
                 ' stroked="', !aFill, '"',
                 ' path="');

    var newSeq = false;
    var min = {x: null, y: null};
    var max = {x: null, y: null};

    for (var i = 0; i < this.currentPath_.length; i++) {
      var p = this.currentPath_[i];
      var c;

      switch (p.type) {
        case 'moveTo':
          c = p;
          lineStr.push(' m ', mr(p.x), ',', mr(p.y));
          break;
        case 'lineTo':
          lineStr.push(' l ', mr(p.x), ',', mr(p.y));
          break;
        case 'close':
          lineStr.push(' x ');
          p = null;
          break;
        case 'bezierCurveTo':
          lineStr.push(' c ',
                       mr(p.cp1x), ',', mr(p.cp1y), ',',
                       mr(p.cp2x), ',', mr(p.cp2y), ',',
                       mr(p.x), ',', mr(p.y));
          break;
        case 'at':
        case 'wa':
          lineStr.push(' ', p.type, ' ',
                       mr(p.x - this.arcScaleX_ * p.radius), ',',
                       mr(p.y - this.arcScaleY_ * p.radius), ' ',
                       mr(p.x + this.arcScaleX_ * p.radius), ',',
                       mr(p.y + this.arcScaleY_ * p.radius), ' ',
                       mr(p.xStart), ',', mr(p.yStart), ' ',
                       mr(p.xEnd), ',', mr(p.yEnd));
          break;
      }


      // TODO: Following is broken for curves due to
      //       move to proper paths.

      // Figure out dimensions so we can do gradient fills
      // properly
      if (p) {
        if (min.x == null || p.x < min.x) {
          min.x = p.x;
        }
        if (max.x == null || p.x > max.x) {
          max.x = p.x;
        }
        if (min.y == null || p.y < min.y) {
          min.y = p.y;
        }
        if (max.y == null || p.y > max.y) {
          max.y = p.y;
        }
      }
    }
    lineStr.push(' ">');

    if (!aFill) {
      var lineWidth = this.lineScale_ * this.lineWidth;

      // VML cannot correctly render a line if the width is less than 1px.
      // In that case, we dilute the color to make the line look thinner.
      if (lineWidth < 1) {
        opacity *= lineWidth;
      }

      lineStr.push(
        '<g_vml_:stroke',
        ' opacity="', opacity, '"',
        ' joinstyle="', this.lineJoin, '"',
        ' miterlimit="', this.miterLimit, '"',
        ' endcap="', processLineCap(this.lineCap), '"',
        ' weight="', lineWidth, 'px"',
        ' color="', color, '" />'
      );
    } else if (typeof this.fillStyle == 'object') {
      var focus = {x: '50%', y: '50%'};
      var width = max.x - min.x;
      var height = max.y - min.y;
      var dimension = width > height ? width : height;

      focus.x = mr(this.fillStyle.focus_.x / width * 100 + 50) + '%';
      focus.y = mr(this.fillStyle.focus_.y / height * 100 + 50) + '%';

      var colors = [];

      // inside radius (%)
      if (this.fillStyle.type_ == 'gradientradial') {
        var inside = this.fillStyle.radius1_ / dimension * 100;

        // percentage that outside radius exceeds inside radius
        var expansion = this.fillStyle.radius2_ / dimension * 100 - inside;
      } else {
        var inside = 0;
        var expansion = 100;
      }

      var insidecolor = {offset: null, color: null};
      var outsidecolor = {offset: null, color: null};

      // We need to sort 'colors' by percentage, from 0 > 100 otherwise ie
      // won't interpret it correctly
      this.fillStyle.colors_.sort(function(cs1, cs2) {
        return cs1.offset - cs2.offset;
      });

      for (var i = 0; i < this.fillStyle.colors_.length; i++) {
        var fs = this.fillStyle.colors_[i];

        colors.push(fs.offset * expansion + inside, '% ', fs.color, ',');

        if (fs.offset > insidecolor.offset || insidecolor.offset == null) {
          insidecolor.offset = fs.offset;
          insidecolor.color = fs.color;
        }

        if (fs.offset < outsidecolor.offset || outsidecolor.offset == null) {
          outsidecolor.offset = fs.offset;
          outsidecolor.color = fs.color;
        }
      }
      colors.pop();

      lineStr.push('<g_vml_:fill',
                   ' color="', outsidecolor.color, '"',
                   ' color2="', insidecolor.color, '"',
                   ' type="', this.fillStyle.type_, '"',
                   ' focusposition="', focus.x, ', ', focus.y, '"',
                   ' colors="', colors.join(''), '"',
                   ' opacity="', opacity, '" />');
    } else {
      lineStr.push('<g_vml_:fill color="', color, '" opacity="', opacity,
                   '" />');
    }

    lineStr.push('</g_vml_:shape>');

    this.element_.insertAdjacentHTML('beforeEnd', lineStr.join(''));
  };

  contextPrototype.fill = function() {
    this.stroke(true);
  }

  contextPrototype.closePath = function() {
    this.currentPath_.push({type: 'close'});
  };

  /**
   * @private
   */
  contextPrototype.getCoords_ = function(aX, aY) {
    var m = this.m_;
    return {
      x: Z * (aX * m[0][0] + aY * m[1][0] + m[2][0]) - Z2,
      y: Z * (aX * m[0][1] + aY * m[1][1] + m[2][1]) - Z2
    }
  };

  contextPrototype.save = function() {
    var o = {};
    copyState(this, o);
    this.aStack_.push(o);
    this.mStack_.push(this.m_);
    this.m_ = matrixMultiply(createMatrixIdentity(), this.m_);
  };

  contextPrototype.restore = function() {
    copyState(this.aStack_.pop(), this);
    this.m_ = this.mStack_.pop();
  };

  contextPrototype.translate = function(aX, aY) {
    var m1 = [
      [1,  0,  0],
      [0,  1,  0],
      [aX, aY, 1]
    ];

    this.m_ = matrixMultiply(m1, this.m_);
  };

  contextPrototype.rotate = function(aRot) {
    var c = mc(aRot);
    var s = ms(aRot);

    var m1 = [
      [c,  s, 0],
      [-s, c, 0],
      [0,  0, 1]
    ];

    this.m_ = matrixMultiply(m1, this.m_);
  };

  contextPrototype.scale = function(aX, aY) {
    this.arcScaleX_ *= aX;
    this.arcScaleY_ *= aY;
    var m1 = [
      [aX, 0,  0],
      [0,  aY, 0],
      [0,  0,  1]
    ];

    var m = this.m_ = matrixMultiply(m1, this.m_);

    // Get the line scale.
    // Determinant of this.m_ means how much the area is enlarged by the
    // transformation. So its square root can be used as a scale factor
    // for width.
    var det = m[0][0] * m[1][1] - m[0][1] * m[1][0];
    this.lineScale_ = sqrt(abs(det));
  };

  /******** STUBS ********/
  contextPrototype.clip = function() {
    // TODO: Implement
  };

  contextPrototype.arcTo = function() {
    // TODO: Implement
  };

  contextPrototype.createPattern = function() {
    return new CanvasPattern_;
  };

  // Gradient / Pattern Stubs
  function CanvasGradient_(aType) {
    this.type_ = aType;
    this.radius1_ = 0;
    this.radius2_ = 0;
    this.colors_ = [];
    this.focus_ = {x: 0, y: 0};
  }

  CanvasGradient_.prototype.addColorStop = function(aOffset, aColor) {
    aColor = processStyle(aColor);
    this.colors_.push({offset: 1 - aOffset, color: aColor});
  };

  function CanvasPattern_() {}

  // set up externs
  G_vmlCanvasManager = G_vmlCanvasManager_;
  CanvasRenderingContext2D = CanvasRenderingContext2D_;
  CanvasGradient = CanvasGradient_;
  CanvasPattern = CanvasPattern_;

})();

} // if
[[GettingStarted]]
[[Rechtssystematik]]
[[Prinzipien]]
[[Gesetze]]
[[Entscheidungen]]
[[Tools]]
[[Impressum]]
@@display:none;@@[img[andreani|http://www.andreanis.de/_tiddly/uploads/logoverlag.jpg][http://www.andreanis.de]] 
!Format text
|!Format|!It will look like this...|!...if you format it like this...|
|Bold-faced type|''text''|{{{''text''}}}|
|Italic text|//text//|{{{//text//}}}|
|Underlined text|__text__|{{{__text__}}}|
|Strike-through text|--text--|{{{--text--}}}|
|Colored text|@@color(green):green colored@@|{{{@@color(green):green colored@@}}}|
|Text with colored background|@@bgcolor(#ff0000):color(#ffffff):red colored@@|{{{@@bgcolor(#ff0000):color(#ffffff):red colored@@}}}|
|Highlighting|@@text@@|{{{@@text@@}}}|
|Superscript|2^^3^^=8|{{{2^^3^^=8}}}|
|Subscript|a~~ij~~ = -a~~ji~~|{{{a~~ij~~ = -a~~ji~~}}}|

!Make the first letter of a paragraph extra large
(from Morris Gray's TW Help)

''Sample'':

{{firstletter{
 @@color:#bbbbbb;O@@}}}kay, so you know how to use ~TiddlyWiki, but now you want more. You want to change the color or layout. You want to add features to it. As the subtitle says, this is an entry-level introduction, so I am not going to show you how to do every possible thing you can do with ~TiddlyWiki. I probably don't know half of what can be done. Advanced documentation such as that found at http://www.tiddlywiki.org/wiki and http://tiddlyspot.com/twhelp/ can hopefully expand your horizons. 

''How to do it:''

1. Add the following code to your StyleSheet:

 {{{
.firstletter{ float:left; width:0.75em; font-size:400%; font-family:times,arial; line-height:60%; }
}}}

2. Add the following code to your tiddler at the place where your enlarged letter would go (replacing "O" with the appropriate letter):
{{{
{{firstletter{
 @@color:#c06;O@@
 }}}
}}}
.firstletter{ float:left; width:0.75em; font-size:250%; font-family:verdana; line-height:50%; } 
.nodeName {font-size:3.0em}
.nodeNameLength:30
.nodeLabel:hover {color:#19A463;font-size:70%}
.nodeLabel {cursor:pointer;z-index:1;font-size:70%}
.ttmm canvas {z-index:0;}
.ttmm div {z-index:1;}
.shape {z-index:0;}

.ttmm {border: none;border_width : 0px;}

.siteTitle {font-size:150%;position: relative;float: right;width: auto;padding: 0.2em 0.2em 0.2em 0.2em;}
.siteSubtitle {font-size:0.5em;}
|bgcolor(#dddddd):Links with wikiwords|EnchiLada (inactive link - no tiddler yet)<br>WikiWord (active link to tiddler)|{{{EnchiLada}}}<br>{{{WikiWord}}}|
|bgcolor(#dddddd):~De-Wikify a ~WikiWord|~WikiWord, ~EnchiLada|{{{~WikiWord, ~EnchiLada}}}|
|bgcolor(#dddddd):Links with brackets|[[How to add background images]]|{{{[[How to add background images]]}}}|
|bgcolor(#dddddd):Pretty links|[[display text|ColorSchemes]] - links to the tiddler of color schemes|{{{[[display text|ColorSchemes]]}}}|
|bgcolor(#dddddd):External links work the same way:|http://groups.google.com/group/TiddlyWiki <br><br>[[TiddlyWiki Google group|http://groups.google.com/group/TiddlyWiki]]|{{{http://groups.google.com/group/TiddlyWiki}}} <br><br> {{{[[TiddlyWiki Google group|http://groups.google.com/group/TiddlyWiki]]}}}|
|bgcolor(#dddddd):Links to local files|To a file on a CD in your D drive: <br><br>To a file on your USB stick on your e drive: <br><br>To a file in your hard drive:|{{{file:///D:/filename.doc/}}}<br><br>{{{file:///E:/filename.doc/}}}<br><br>{{{file:///C:/filepath/filename.doc/}}}| 

''Images:''
{{{[img[http://farm1.static.flickr.com/39/122259544_6913ca58f3_m.jpg]]}}} is the formatting for:

[img[http://farm1.static.flickr.com/39/122259544_6913ca58f3_m.jpg]]

''A tip from Jeremy Hodge:''
"...[You] may add an image as a local file with the following: {{{[img[.\filepath\filename.jpg]]}}} which adds a picture from the directory that is contained within the same directory as TW. This is very useful for me or anyone who carries their own TW on a USB drive such as myself."
Mark this side at your @@color:#900;favorite Network@@
<html>
<h3>Social Networks</h3>
<table>
<tr>
<td>twitter</td>
<td>facebook</td>
<td>delicious</td>
</tr>
<tr>
<td><a href="http://twitter.com/home?status=http%3A%2F%2Fwww.andreanis.de/_tiddly/index.php" target="_blank" title="Twitter"><img src="/_tiddly/uploads/twitter.gif" width="16" height="16" border="0" hspace="0" alt="Twitter"/></a></td>
<td><a href="http://de.facebook.com/sharer.php?u=http%3A%2F%2Fwww.andreanis.de/_tiddly/index.php" target="_blank"><img src="/_tiddly/uploads/facebook.gif" alt="Facebook" title="Facebook" align="left" border="0" height="16" hspace="0" width="16"></a></td>
<td><a href="http://del.icio.us/post?url=http%3A%2F%2Fwww.andreanis.de/_tiddly/index.php" target="_blank"><img src="/_tiddly//uploads/delicious.gif" alt="deli.cio.us" title="deli.cio.us" align="left" border="0" height="16" hspace="0" width="16"></a></td>
</tr>
</table> 
</html>




Type the text for 'KaufR'
Type the text for 'Rechtsgebiet'
Type the text for 'AufenthaltsRecht'
Einerseits git es die für 3 Monate befristete Variante des Schengen-VISA, die einen Aufenhalt für die beantragte Dauer bis höchstens 3 Monaten einräumt.

Anderseits ist der Aufenthalt an einen Aufenthaltszweck geknüpft:

http://www.wien.diplo.de/Vertretung/wien/de/04/Seite_20Langzeit-Visa.html
<<search>><<closeAll>><<permaview>><<newTiddler>><<newJournal "DD MMM YYYY" "journal">><<saveChanges>><<slider chkSliderOptionsPanel OptionsPanel "options »" "Change TiddlyWiki advanced options">>
admin
Bob
Jack
Jane
Josh
/* 
vismo library is designed to make it easier to bring cross browser visualisations to Firefox/IE using canvas and vml
Some plugins are dependent on it.
Including GeoTiddlyWiki, TiddlyTagMindMap and ImageTaggingPlugin

If you have any of these installed in the condensed form you must install this!
 */
var VismoLibraryInstalled = true;var VismoOptimisations = {
	packCoordinates: function(coordlist){
		var res = [];
		for(var i=0; i < coordlist.length-1; i+=2){
			res.push([coordlist[i],coordlist[i+1]]);
		}
		
		return res;
	}
	,unpackCoordinates: function(coordlist){
		var res = [];
		for(var i=0; i < coordlist.length; i+=1){
			res.push(coordlist[i][0]);
			res.push(coordlist[i][1]);
		}
		return res;	
	}
	//coords in form [[x1,y1],[x2,y2]]
	,douglasPeucker: function(coords,tolerance, start,end){
		var results = [];

		if(!start) start = 0;
		if(!end) end = coords.length - 1;
		if(start >= coords.length || end >= coords.length || start == end -1){
			return [];
		}	
		var midpoint = {};
	
	
		midpoint.x = (coords[end][0] + coords[start][0]) /2;
		midpoint.y = (coords[end][1] + coords[start][1]) /2;
		
		var bestPoint = {distance:-1, index:-1};
		for(var i=start+1; i < end; i++){
			var x = coords[i][0];
			var y = coords[i][1];
			var deltax = midpoint.x - x;
			var deltay= midpoint.y - y;
			
			var perpendicular_d = Math.sqrt((deltax * deltax ) + (deltay *deltay)); //this is not perpendicular distancd.. i think!
			if(perpendicular_d > bestPoint.distance){
				bestPoint.index = i;
				bestPoint.distance = perpendicular_d;
			}
		}
	
		if(bestPoint.index ==-1 || bestPoint.distance<tolerance){
			var res = [];
			res.push(coords[start]);
			//res.push(coords[end])
			return res; //none of these points are interesting except last
		}
		else{
			results.push(coords[start]);
			var ref = bestPoint.index;
			var splice1 = VismoOptimisations.douglasPeucker(coords,tolerance,start+1,ref);
			var splice2 = VismoOptimisations.douglasPeucker(coords,tolerance,ref,end);
			results = results.concat(splice1);
			results = results.concat(splice2);
			results.push(coords[end]);
			return results;
		}
		
	}
  
	,vismoShapeIsInVisibleArea: function(vismoShape,canvas,transformation){
		var left = 0,top = 0;
		var right =  parseInt(canvas.width) + left; 
		var bottom = parseInt(canvas.height) + top;
		var topleft =  VismoClickingUtils.undotransformation(left,top,transformation);
		var bottomright =  VismoClickingUtils.undotransformation(right,bottom,transformation);				
		var frame = {};
		frame.top = topleft.y;
		frame.bottom = bottomright.y;
		frame.right = bottomright.x;
		frame.left = topleft.x;
		var g = vismoShape.getBoundingBox();
		if(g.x2 < frame.left) {
			return false;}
		if(g.y2 < frame.top) {
			return false;}
		if(g.x1 > frame.right){
			return false;
		}
		if(g.y1 > frame.bottom){
			return false;	
		}
		
		return true;
	}
	
	,vismoShapeIsTooSmall: function(vismoShape,transformation){
	
		if(!transformation ||!transformation.scale) return false;
		var g = vismoShape.getBoundingBox();
		var s = transformat