LOADING: ...

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

hr {height:1px;}

a {text-decoration:none;}

dt {font-weight:bold;}

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

.txtOptionInput {width:11em;}

#contentWrapper .chkOptionInput {border:0;}

.externalLink {text-decoration:underline;}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

.whenBackstage {display:none;}
.backstageVisible .whenBackstage {display:block;}
/*}}}*/
/***
StyleSheet for use when a translation requires any css style changes.
This StyleSheet can be used directly by languages such as Chinese, Japanese and Korean which 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 closeTiddler closeOthers +editTiddler > fields syncing permalink references jump'></div>
<div class='title' macro='view title'></div>
<div class='subtitle'><span macro='view modifier link'></span>, <span macro='view modified date'></span> (<span macro='message views.wikified.createdPrompt'></span> <span macro='view created date'></span>)</div>
<div class='tagging' macro='tagging'></div>
<div class='tagged' macro='tags'></div>
<div class='viewer' macro='view text wikified'></div>
<div class='tagClear'></div>
<!--}}}-->
<!--{{{-->
<div class='toolbar' macro='toolbar +saveTiddler -cancelTiddler deleteTiddler'></div>
<div class='title' macro='view title'></div>
<div class='editor' macro='edit title'></div>
<div macro='annotations'></div>
<div class='editor' macro='edit text'></div>
<div class='editor' macro='edit tags'></div><div class='editorFooter'><span macro='message views.editor.tagPrompt'></span><span macro='tagChooser'></span></div>
<!--}}}-->
To get started with this blank TiddlyWiki, you'll need to modify the following tiddlers:
* SiteTitle & SiteSubtitle: The title and subtitle of the site, as shown above (after saving, they will also appear in the browser title bar)
* MainMenu: The menu (usually on the left)
* DefaultTiddlers: Contains the names of the tiddlers that you want to appear when the TiddlyWiki is opened
You'll also need to enter your username for signing your edits: <<option txtUserName>>
These InterfaceOptions for customising TiddlyWiki are saved in your browser

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

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

----
Also see AdvancedOptions
<<importTiddlers>>
[[<Back|BoneYard]]
!DUMP
Simple routine to check the status of a variable during program development and halt execution at that point.
{{{
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
sub DUMP
{	my $var = $_[0];
	print "\n\n>> $var << \n\n";
	die; 
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
}}}
|''Type:''|file|
|''URL:''|http://mptw.tiddlyspot.com|
|''Workspace:''|(default)|

This tiddler was automatically created to record the details of this server
|''Type:''|file|
|''URL:''|http://tiddlywiki.bidix.info|
|''Workspace:''|(default)|

This tiddler was automatically created to record the details of this server
|''Type:''|file|
|''URL:''|http://tw.lewcid.org|
|''Workspace:''|(default)|

This tiddler was automatically created to record the details of this server
|''Type:''|file|
|''URL:''|http://www.tiddlytools.com|
|''Workspace:''|(default)|

This tiddler was automatically created to record the details of this server
{{tableindex{
|[[Test1]]|[[Test2]]|[[subtopic3]]|
}}}
<!--{{{-->
<div class='toolbar' macro='toolbar closeTiddler closeOthers +editTiddler > fields syncing permalink references jump'></div>
<div class='01macro='tiddler 01subtopicMenu'></div><div class='title' macro='view title'></div>
<div class='viewer' macro='view text wikified'></div><div class='tagClear'></div>
<!--}}}-->
[[BACK to Working Code|BoneYard]]
!!!
!Count Amino Acids:

{{{
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
sub AAfreq
{	print "   Amino Acid frequencies . . . \n";
	my @AAx = qw | A C D E F G H I K L M N P Q R S T V W Y |;
	my $GenDict = $_[0];
	foreach my $id (keys %{$GenDict})
	{	my $seq = ${$GenDict}{$id}{'aaseq'};
		my $N = length($seq);
		if ($N < 1) { print "\n\nError in aaseq length; see sub &AAfreq\n\n"; die; }
		while ($seq =~ s/^(.)//) 
		{	${$GenDict}{$id}{'AAfreq'}{'p'.$1} += 1/$N;  }
		foreach my $aa (@AAx)
		{	${$GenDict}{$id}{'AAfreq'}{'p'.$aa} = &RoundOff(${$GenDict}{$id}{'AAfreq'}{'p'.$aa}, 4); }
	}
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
}}}
[[<Back to Index|BoneYard]]
!Protein Mass from Amino Acid Composition

{{{
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
sub AAmass
{	print "   Protein mass . . . \n";
	my @AAx = qw | A C D E F G H I K L M N P Q R S T V W Y |;
	my %mass = qw | A	71.0788 R	156.1875	N	114.1038	D	115.0886	C	103.1388	E	129.1155	Q	128.1307	G	57.0519	H	137.1411	I	113.1594	L	113.1594	K	128.1741	M	131.1926	F	147.1766	P	97.1167	S	87.0782	T	101.1051	W	186.2132	Y	163.1760	V	99.1326 |;
	my $GenDict = $_[0];
	foreach my $id (keys %{$GenDict})
	{	my $N = length(${$GenDict}{$id}{'aaseq'});
		${$GenDict}{$id}{'AAmass'} = 0;
		foreach my $aa (@AAx)
		{	${$GenDict}{$id}{'AAmass'} += &RoundOff(0.001 * ${$GenDict}{$id}{'AAfreq'}{'p'.$aa} * $N * $mass{$aa}, 2); }
		#&DUMP(${$GenDict}{$id}{'AAmass'});
	}
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
}}}


!
[[<Back to Index|BoneYard]]
!AA Side Chain Nitrogen Count

Subroutine coded by K.Hoadley.

{{{
# - - - - - - - - -- - - - - - - - - -  - - - - - - - - - - - - - - - - - - - - 
sub AAnitrogen
{	print "   Protein nitrogen requirement . . . \n";
	my @AAx = qw | A C D E F G H I K L M N P Q R S T V W Y |;
	my %nitrog = qw | R	 3	N	1	Q	1	H	2	K	1	P	1	W	1  |;
	my $GenDict = $_[0];
	foreach my $id (keys %{$GenDict})
	{	my $W = length(${$GenDict}{$id}{'aaseq'});
		${$GenDict}{$id}{'AAnitrogen'} = 0;
		foreach my $aa (@AAx)
		{	${$GenDict}{$id}{'AAnitrogen'} += &RoundOff(0.001 * ${$GenDict}{$id}{'AAfreq'}{'p'.$aa} * $W * $nitrog{$aa}, 2); }
		#&DUMP(${$GenDict}{$id}{'AAnitrogen'});
	}
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
}}}
<!--{{{-->
<div class='toolbar' macro='toolbar closeTiddler closeOthers +editTiddler > fields syncing permalink references jump'></div>
<div class='AAuse' macro='tiddler AAuseSubtopicMenu'></div><div class='title' macro='view title'></div>
<div class='viewer' macro='view text wikified'></div><div class='tagClear'></div>
<!--}}}-->
/***
|''Name:''|AnnotationsPlugin|
|''Description:''|Inline annotations for tiddler text.|
|''Author:''|Saq Imtiaz ( lewcid@gmail.com )|
|''Source:''|http://tw.lewcid.org/#AnnotationsPlugin|
|''Code Repository:''|http://tw.lewcid.org/svn/plugins|
|''Version:''|2.0|
|''Date:''||
|''License:''|[[Creative Commons Attribution-ShareAlike 3.0 License|http://creativecommons.org/licenses/by-sa/3.0/]]|
|''~CoreVersion:''|2.2.3|

!!Usage:
*{{{((text to annotate(annotation goes here)}}}
* To include the text being annotated, in the popup as a title, put {{{^}}} as the first letter of the annotation text.
** {{{((text to annotate(^annotation goes here)}}}

!!Examples:
Mouse over, the text below:
* ((banana(the best fruit in the world)))
* ((banana(^ the best fruit in the world)))

***/
// /%
config.formatters.unshift({name:"annotations",match:"\\(\\(",lookaheadRegExp:/\(\((.*?)\((\^?)((?:.|\n)*?)\)\)\)/g,handler:function(w){
this.lookaheadRegExp.lastIndex=w.matchStart;
var _2=this.lookaheadRegExp.exec(w.source);
if(_2&&_2.index==w.matchStart){
var _3=createTiddlyElement(w.output,"span",null,"annosub",_2[1]);
_3.anno=_2[3];
if(_2[2]){
_3.subject=_2[1];
}
_3.onmouseover=this.onmouseover;
_3.onmouseout=this.onmouseout;
_3.ondblclick=this.onmouseout;
w.nextMatch=_2.index+_2[0].length;
}
},onmouseover:function(e){
popup=createTiddlyElement(document.body,"div",null,"anno");
this.popup=popup;
if(this.subject){
wikify("!"+this.subject+"\n",popup);
}
wikify(this.anno,popup);
addClass(this,"annosubover");
Popup.place(this,popup,{x:25,y:7});
},onmouseout:function(e){
removeNode(this.popup);
this.popup=null;
removeClass(this,"annosubover");
}});
setStylesheet(".anno{position:absolute;border:2px solid #000;background-color:#DFDFFF; color:#000;padding:0.5em;max-width:15em;width:expression(document.body.clientWidth > (255/12) *parseInt(document.body.currentStyle.fontSize)?'15em':'auto' );}\n"+".anno h1, .anno h2{margin-top:0;color:#000;}\n"+".annosub{background:#ccc;}\n"+".annosubover{z-index:25; background-color:#DFDFFF;cursor:help;}\n","AnnotationStyles");


// %/
[[<Back to Code Index|BoneYard]]
!Passing Arrays to Subroutines by Name Reference
In a standard call to a subroutine, you can simple "send" a variable to it so that it can be used in the subroutine code, like this:
{{{
my $x = 10;
my $y = 15;
my $Sum = &AddNumbers($x,$y);

# - - - - - -  - - -
sub AddNumbers
{
   my ($N1,$N2) = @_;
   my $SUM = $N1 + $N2;
   return($SUM);
}
}}}
!!Array Referencing:
But often you will have an array of numbers that you would like a subroutine to process, and so there is a way to pass the "variable name" of an array (rather than all the elements) by what is called ''Referencing''. In the example below, line 1 defines array ''@X''. Line 2 then calls subroutine ''~AddNumbers'' and sends to it the name of the variable array (using ''\@X'') instead of sending it all the elements separately. When the subroutine starts, it assigns the name of the array to the variable ''$arrayname'', and then we can access ''@X'' using the ''$arrayname'' name by enclosing it within brackets: @@{{{@{$arrayname} }}}@@. The advantages to array referencing are:  faster processing when subroutines are working with arrays; the ability for manipulations within a subroutine to change the original array;  allows subroutines to be more transportable/independent because they access only their internally defined variables.
{{{
  my @X = (10, 25, 56, 74, 82, 96, 105, 123, 173);
  my $SUM = &AddNumbers(\@X);

# - - - - - - - -  
sub AddNumbers
{
    my $arrayname = $_[0];
    my $sum = 0;
    foreach my $num (@{$arrayname})
    {     $sum += $num;    }
    return($sum);
}
}}}

This also works for hashes as well (see script LODscore). Just remember that inside the subroutine the hash name now needs to be enclosed in ''{...}''. In this example, the name of the hash in the subroutine is stored in the variable ''$Pvalues'' so we can get to the hash elements by using: @@{{{ ${$Pvalues}{$nt} }}}@@.
{{{
my $Pcod = &Pcalc($query,\%Pcode);

#-----------------
sub Pcalc
{	my ($QS,$Pvalues) = @_;
	my @QS = split(//,$QS);
	my $prob = 1; 
	foreach my $nt (@QS)
	{	$prob = $prob * ${$Pvalues}{$nt}; }
	return $prob;
}
}}}
If you needed a foreach loop to iterate through the hash values, it would look like this within the subroutine block:
{{{
    # within subroutine . . . . .
    foreach my $x (keys %{$Pvalues})
    {        ... code to work with ${$Pvalues}{$x} ..... ; }
}}}


!
[[<Back to Lecture Index|Lecture Index]]|[[Next>|BLAST-02]]
!Sequence Alignment Algorithms
If two sequences are not identical, then to compare them, we generate an alignment of those sequences. The alignment process is logically clear, but computationally complex.

If we take these two sequences: __''{{{ C A T D O G }}}''__  and  __''{{{ B A T H O G }}}''__, we could quickly ascertain that two "good" alignments would be:
{{{
   Alignment #1:
          C A T D O G
          B A T H O G

   Alignment #2:
          C - A T D - O G
          - B A T - H O G
}}}
 
''What makes a good alignment?''
# Sequence homology: evolutionary relationship allows re-positioning.
# The original order of characters in both sequences must be preserved (linearity of sequence).
# Gaps "-" can be introduced to allow for homologous amino acid positions to be aligned over each other (mutations in sequence).
# The alignment of identical characters is maximized.
# The introduction of gaps into either sequence is minimized.


!
[[<BACK|BLAST-01]]|[[NEXT>|BLAST-03]]
!!ALIGNMENTS: setting up the strings
We first start with the two strings that we want to align:
{{{
my $seq1 = "CATDOG";
my $seq2 = "BATHOG";
}}}
Both sequences contain 6 letters. The minimum similarity alignment we could possible have is:
{{{
     C A T D O G - - - - - - 
     - - - - - - B A T H O G
}}}
So we start by developing a generalized series of sequence-gap patterns, starting with the string: | ''{{{XXXXXX------}}}'' |, where the "X" signifies an amino acid (or nucleotide) and "-" signifies a gap. We will call each sequence pattern a CHAIN of X's and gaps. Here's the code to setup the first CHAIN:
{{{
my @chain;
foreach (1..length($seq1))   {	push(@chain,"x"); }
foreach (length($seq1)+1..$N){	push(@chain,"-"); }
print join('',@chain);
}}}
!
[[<BACK|BLAST-02]]|[[NEXT>|BLAST-04]]
!!ALIGNMENTS: setting up chains
Now the task is to generate all the possible combinations of 6 characters and 6 gaps but keeping the 6 characters in the same order. We will store each chain pattern in an array called @Gaps.
{{{
my @Gaps;
foreach my $i (1..length($seq1))
{	for(my $j = length($seq1)-1; $j>=0; $j -= 1)
	{	foreach my $k ($j..$N-2)
		{   @chain[$k,$i+$k] = @chain[$i+$k, $k];
			my $match = 0;
			my $seq = join('',@chain);
		# Check to see if seq pattern has already been found:
			foreach my $gap (@Gaps)
			{	if ($gap eq $seq){ $match = 1; last;} }
		# Store unique chain patterns in @Gaps:
			if ($match == 0)
			{	push(@Gaps,$seq); }  
		}
	}
}
my $n = $#Gaps +1;
print "There are $n permutations in the gap set\n";
}}}

The output: ''{{{There are 176 permutations in the gap set.}}}''
The elements in @Gap look like:
{{{
xxxxx-x-----
xxxxx--x----
xxxxx---x---
xxxxx----x--
xxxxx-----x-
xxxxx------x
xxxx-x-----x
xxxx--x----x
xxxx---x---x
xxxx----x--x
xxxx-----x-x
xxxx------xx
xxx-x-----xx
xxx--x----xx
xxx---x---xx
xxx----x--xx
xxx-----x-xx
xxx------xxx
xx-x-----xxx
xx--x----xxx
xx---x---xxx
xx----x--xxx
xx-----x-xxx
xx------xxxx
x-x-----xxxx
x--x----xxxx
x---x---xxxx
x----x--xxxx
x-----x-xxxx
x------xxxxx
-x-----xxxxx
--x----xxxxx
---x---xxxxx
----x--xxxxx
-----x-xxxxx
------xxxxxx
-----xx-xxxx
-----xxxx-xx
-----xxxxxx-
-----xxxxx-x
----xx-xxx-x
----xxxx-x-x
----xxxxx--x
----xxxx--xx
----xxxx-xx-
---xx-xx-xx-
---xxxx--xx-
---xxx-x-xx-
---xxx-xxx--
---xxx-xx--x
--xx-x-xx--x
--xxx--xx--x
--xx--xxx--x
--xx-xx-x--x
--xx-xx---xx
--xx-xx--xx-
-xx--xx--xx-
-x-x-xx--xx-
-x-xxx---xx-
-x-xx--x-xx-
-x-xx--xxx--
-x-xx--xx--x
x--xx--xx--x
-xx-x--xx--x
-xx---xxx--x
-xx--xx-x--x
-xx--xx---xx
-xx---x-xxx-
-xx---xxxx--
-xx---xx-x-x
-xx---xx--xx
-xxx---x--xx
-xxxx-----xx
-xxxx--x---x
-xxxx--xx---
-x-xxx-xx---
-x--xxxxx---
-x--xx-xxx--
-x--xx--xxx-
-x--xx---xxx
---xxx---xxx
--xx-x---xxx
--xxx----xxx
--xx--x--xxx
--xx---x-xxx
--xx---xxx-x
--xx---xxxx-
x-x----xxxx-
x----x-xxxx-
x---xx--xxx-
x---xxx-x-x-
x---xxxxx---
x---xxxx---x
x---xxxx--x-
-x--xxxx--x-
---xxxxx--x-
--xx-xxx--x-
--xxx-xx--x-
--xxxxx---x-
--xxxx-x--x-
--xxxx--x-x-
--xxxx--xx--
--xxxx--x--x
--xxxx---x-x
--xxx--xx-x-
--xxx-x--xx-
--x-xxx--xx-
--x-x-xx-xx-
--x-x--xxxx-
--x-x--xx-xx
----xx-xx-xx
----xxx-x-xx
----xx--xxxx
----xx-x-xxx
-x--x--xx-xx
-x-xx---x-xx
-x-x---xx-xx
-x-xx--x--xx
-x-xx-x---xx
-x-xxx----xx
-x-xx----xxx
-x-xx-x--x-x
-x-xx-xx-x--
x-x-x-xx-x--
xx-x--xx-x--
x-xxx-x--x--
x-xx--x-xx--
x-xx-xx-x---
x-xx-x--x-x-
x--x-x-xx-x-
x--x-x-x-x-x
x-x-x--x-x-x
xx-xx--x-x--
xx-xx-x-x---
xx-xx-x--x--
x-x-xxx--x--
x-x--xx-xx--
x-x--x-x-xx-
x-x--x--xxx-
x-x--x--xx-x
x---x-x-xx-x
x--x-x--xx-x
x--xx--x-x-x
x--xx-xx-x--
xx-x--x--xx-
xx-x-x--xx--
xx-x----xx-x
xx-x---xx-x-
xxx---xx-x--
xxxx--x--x--
xxxx---x-x--
xxxx-x-x----
xxxx-x--x---
x--xx-xxx---
x--x--xxxx--
x--x-xxxx---
x--x--xxx-x-
x--x--xx-xx-
x--x---xx-xx
x---x--xx-xx
x--xx--x--xx
x--xx---x-xx
x--xx-x--x-x
---xxxxxx---
-xx-xxx-x---
-xxxxx--x---
-xxx-x--xx--
-xxx---xxx--
-xxx--xxx---
--xxx--xxx--
-xx-x--xxx--
--x-xx-xxx--
---x-xxxxx--
---xx-xxxx--
---xxx-xx-x-
---xxx--x-xx
}}}



!
[[<BACK|BLAST-03]]|[[NEXT>|BLAST-05]]
!!ALIGNMENTS: setting up gap sequence matrices
There are 176 gap-sequence patterns possible for 6 characters and 6 gaps. In aligning two 6 character strings, that equates to 30,976 total alignments.

Alignment is the wrong word to really describe what we are doing with the two sequences. It would be better to call it something like "filtering" or "sorting", because the process is passive in that there is no "aligning" or shifting of sequence characters. We start with all possible potential string results, and then just compare them all to figure out which pair combination is best. Then that one is output as the "ALIGNMENT".

We know have to translate the chain patterns in @Gaps into amino acid patterns specific for each of the target sequences we want to compare:
{{{
# Set Seq array 1 - - - - - - - - - - - 
foreach my $gap (@Gaps)
{	my @x = split(//, $gap);
	my @seq = split(//,$seq1);
	my $gapseq = "";
	foreach my $x (@x)
	{	if ($x =~ m/-/)
		{	$gapseq .= "-"; }
		else
		{	$gapseq .= shift(@seq); }
	}
	push (@Seq1, $gapseq);
	print "$gapseq\n";
}
}}}
So the elements of @Seq1 now have same chain patterns as in @Gaps except that for each "X" in the chain, an amino acid from $seq1 has been substituted:
{{{
CATDO-G-----
CATDO--G----
CATDO---G---
CATDO----G--
CATDO-----G-
CATDO------G
CATD-O-----G
CATD--O----G
CATD---O---G
CATD----O--G
CATD-----O-G
CATD------OG
CAT-D-----OG
CAT--D----OG
CAT---D---OG
CAT----D--OG
CAT-----D-OG
CAT------DOG
CA-T-----DOG
CA--T----DOG
CA---T---DOG
CA----T--DOG
CA-----T-DOG
CA------TDOG
C-A-----TDOG
C--A----TDOG
C---A---TDOG
C----A--TDOG
C-----A-TDOG
C------ATDOG
-C-----ATDOG
--C----ATDOG
---C---ATDOG
----C--ATDOG
-----C-ATDOG
------CATDOG
-----CA-TDOG
-----CATD-OG
-----CATDOG-
-----CATDO-G
----CA-TDO-G
----CATD-O-G
----CATDO--G
----CATD--OG
----CATD-OG-
---CA-TD-OG-
---CATD--OG-
---CAT-D-OG-
---CAT-DOG--
---CAT-DO--G
--CA-T-DO--G
--CAT--DO--G
--CA--TDO--G
--CA-TD-O--G
--CA-TD---OG
--CA-TD--OG-
-CA--TD--OG-
-C-A-TD--OG-
-C-ATD---OG-
-C-AT--D-OG-
-C-AT--DOG--
-C-AT--DO--G
C--AT--DO--G
-CA-T--DO--G
-CA---TDO--G
-CA--TD-O--G
-CA--TD---OG
-CA---T-DOG-
-CA---TDOG--
-CA---TD-O-G
-CA---TD--OG
-CAT---D--OG
-CATD-----OG
-CATD--O---G
-CATD--OG---
-C-ATD-OG---
-C--ATDOG---
-C--AT-DOG--
-C--AT--DOG-
-C--AT---DOG
---CAT---DOG
--CA-T---DOG
--CAT----DOG
--CA--T--DOG
--CA---T-DOG
--CA---TDO-G
--CA---TDOG-
C-A----TDOG-
C----A-TDOG-
C---AT--DOG-
C---ATD-O-G-
C---ATDOG---
C---ATDO---G
C---ATDO--G-
-C--ATDO--G-
---CATDO--G-
--CA-TDO--G-
--CAT-DO--G-
--CATDO---G-
--CATD-O--G-
--CATD--O-G-
--CATD--OG--
--CATD--O--G
--CATD---O-G
--CAT--DO-G-
--CAT-D--OG-
--C-ATD--OG-
--C-A-TD-OG-
--C-A--TDOG-
--C-A--TD-OG
----CA-TD-OG
----CAT-D-OG
----CA--TDOG
----CA-T-DOG
-C--A--TD-OG
-C-AT---D-OG
-C-A---TD-OG
-C-AT--D--OG
-C-AT-D---OG
-C-ATD----OG
-C-AT----DOG
-C-AT-D--O-G
-C-AT-DO-G--
C-A-T-DO-G--
CA-T--DO-G--
C-ATD-O--G--
C-AT--D-OG--
C-AT-DO-G---
C-AT-D--O-G-
C--A-T-DO-G-
C--A-T-D-O-G
C-A-T--D-O-G
CA-TD--O-G--
CA-TD-O-G---
CA-TD-O--G--
C-A-TDO--G--
C-A--TD-OG--
C-A--T-D-OG-
C-A--T--DOG-
C-A--T--DO-G
C---A-T-DO-G
C--A-T--DO-G
C--AT--D-O-G
C--AT-DO-G--
CA-T--D--OG-
CA-T-D--OG--
CA-T----DO-G
CA-T---DO-G-
CAT---DO-G--
CATD--O--G--
CATD---O-G--
CATD-O-G----
CATD-O--G---
C--AT-DOG---
C--A--TDOG--
C--A-TDOG---
C--A--TDO-G-
C--A--TD-OG-
C--A---TD-OG
C---A--TD-OG
C--AT--D--OG
C--AT---D-OG
C--AT-D--O-G
---CATDOG---
-CA-TDO-G---
-CATDO--G---
-CAT-D--OG--
-CAT---DOG--
-CAT--DOG---
--CAT--DOG--
-CA-T--DOG--
--C-AT-DOG--
---C-ATDOG--
---CA-TDOG--
---CAT-DO-G-
---CAT--D-OG
}}}
!
[[<BACK|BLAST-04]]|[[NEXT>|BLAST-06]]
!Character Sequence Alignment Code:
Simple scoring routine. Subroutines are used to contain the setup functions. Note that arrays are passed indirectly by reference using the "\@Gaps1" syntax. This means that the memory address location of the @Gaps1 array is what is passed to the subroutine, not the actual list values themselves. 
{{{
#!/usr/bin/perl
use strict;
use Benchmark;
$|=1;

# - - - - - H E A D E R - - - - - - - - - - - - - - - -
# Objective: Compare two strings with a quantitative metric for similarity scoring
# How to brute force compare two sequences . . . . 
# MAST698 - 2013

# - - - - - U S E R   V A R I A B L E S - - - - - - - -
my $seq1 = "CATDOG";
my $seq2 = "BATHOG";

# Set score values here:
my $match   = 4;
my $gap     = -2;
my $nomatch = -1;

# - - - - - G L O B A L  V A R I A B L E S  - - - - - -
my @Gaps1;
my @Gaps2;
my @Seq1;
my @Seq2;
my $N = length($seq1) + length($seq2);

# - - - - - - - - - - - - - - - - - - - - - - - - - - -
# - - - - - M A I N - - - - - - - - - - - - - - - - - -
# - - - - - - - - - - - - - - - - - - - - - - - - - - -
my $Time0 = new Benchmark;

print "\n\n  Philosophy is a walk on the slippery rocks . . . . . \n\n";

# 1. Initialize the first chain pattern; save in @GapsX . . . . . . 
  	push(@Gaps1, &GapPattern($N,$seq1) );
  	push(@Gaps2, &GapPattern($N,$seq2) );

# 2. Generate the permutation patterns . . . . .
	&Permute($N,$seq1,\@Gaps1);
	&Permute($N,$seq2,\@Gaps2);

# 3. Set the sequences into the chain patterns . . . 
	@Seq1 = &SeqChain($seq1,\@Gaps1);
	@Seq2 = &SeqChain($seq2,\@Gaps2);
	
# 4. Sequence comparison scoring - - - - - - - - - - -
	my $count = 0;
	my $max = 0;
	my ($t1,$t2); 
	foreach my $s1 (@Seq1)
	{	my @c1 = split(//,$s1);
		foreach my $s2 (@Seq2)
		{	my ($z1, $z2) = ('','');
			my @c2 = split(//,$s2);
			my $score = 0;
			foreach my $i (0..$#c1)
			{	if ($c1[$i] eq "-" && $c2[$i] eq "-" )
				{	my $do = "nothing"; }
				else
				{	# Amino Acid matching . . . . 
					if ($c1[$i] ne "-" && $c2[$i] ne "-" ) 
					{	if ($c1[$i] eq $c2[$i])
						{	$score += $match; }
						else
						{	$score += $nomatch; }
					}
					# Gap penalty . . . . . 
					elsif ($c1[$i] eq "-" || $c2[$i] eq "-" )
					{	$score += $gap; }
					
					$z1 .= $c1[$i];
					$z2 .= $c2[$i];
				}
			}
			
			if ($score >= $max)
			{	$max = $score;
				$t1 = $z1;
				$t2 = $z2;
			}
			
			#if ($score == 12)
			#{	print "-------------\n";
			#   print "score = $score\n";
			#   print "$z1\n";
			#   print "$z2\n";
			#   print "$s1\n";
			#   print "$s2\n";
			#   $count += 1;
			#}
		}
	}

# Print Results
print "\n\n          MAX ALIGNMENT:\n";
print "          score = $max\n";
print "              $t1\n";
print "              $t2\n";

&TIME;
print "\n\n\n   DONE   \n\n\n";
# - - - - - - - - - - - - - - - - - - - - - - - - - - -
# - - - - - S U B R O U T I N E S - - - - - - - - 
# - - - - - - - - - - - - - - - - - - - - - - - - - - -
sub GapPattern
{	# call with: &GapPattern($N,$seq1)
	# returns the first seq-gap character string
	my $n = shift(@_);
	my $s = shift(@_);
	my @c;
	foreach (1..length($s))   {	push(@c,"x"); }
	foreach (length($s)+1..$n){	push(@c,"-"); }
	return join('',@c);
}
# - - - - - - - - - - - - - - - - - - - - - - - - - -
sub Permute
{	# called with: &Permute($N,$seq1,\@Gaps1);
	# returns all seq-gap permutations
	my ($n, $m, $gaps) = @_;
	my @chain = split(//,@{$gaps}[0]);
	foreach my $i (1..length($m))
	{	for(my $j = length($m)-1; $j>=0; $j -= 1)
		{	foreach my $k ($j..$n-2)
			{   @chain[$k,$i+$k] = @chain[$i+$k, $k];
				my $match = 0;
				my $seq = join('',@chain);
			# Check to see if seq pattern has already been found:
				foreach my $gap (@{$gaps})
				{	if ($gap eq $seq){ $match = 1; last;} }
			# Store unique chain patterns in @Gaps:
				if ($match == 0)
				{	push(@{$gaps},$seq); }  
			}
		}
	}
	#my $z = $#{$gaps} + 1;
	#print "There are $z permutations for \"$m\" using \"@{$gaps}[0]\"\n";	
}
# - - - - - - - - - - - - - - - - - - - - - - - - - -
sub SeqChain
{	# call with: @Seq1 = &SeqChain($seq1,\@Gaps1);
	# returns the seq-gap chains with SEQUENCE data
	my ($seq, $gaps) = @_;
	my @seqchains;
	foreach my $gap (@{$gaps})
	{	my @x = split(//, $gap);
		my @s = split(//,$seq);
		my $gapseq = "";
		foreach my $x (@x)
		{	if ($x =~ m/-/)
			{	$gapseq .= "-"; }
			else
			{	$gapseq .= shift(@s); }
		}
		push (@seqchains, $gapseq);
		# print "$gapseq\n";
	}
	return @seqchains;
}
# - - - - - - - - - - - - - - - - - - - - - - - - -
sub TIME
{	my $t1 = new Benchmark;
    my $td = timediff($t1, $Time0);
    print "\nCode Time:\n",timestr($td),"\n";
}
# - - - - - - - - - - - - - - - - - - - - - - - - - -
#   EOF ---------------------------------------------
}}}
[[<BACK|BLAST-05]]|[[NEXT>|BLAST-07]]
!Computational Complexity
If you had to compare two 100-aa long sequences, there are ~10^^58^^ possible gap-sequence strings that would have to be scored.

Even if we just have short strings, and gradually add one additional character to the comparison in an iterative fashion, the increase in execution time is exponential:

{{{
my $seqX = "CATDOGHORSEGHOSTDEER";
my $seqY = "BATHOGHOUSEGOATSBEAR";
}}}
<html><table><tr>
<td><img src="06/AlignTime-linear.png" style="height:350px"></td>
<td><img src="06/AlignTime-log.png" style="height:350px"></td>
</tr></table></html>
In the above example, the [[Benchmark Module|TimeBenchmark]] was used to calculate the execution time for strings of different character lengths. 

!!!How to make the comparison more time efficient?
Ideally, you want to "direct" the scoring process to only consider the most likely alignments, instead of ALL of the possible alignments. The minimum similarity alignment we could possible have in our example is:
{{{
     C A T D O G - - - - - - 
     - - - - - - B A T H O G
}}}
But do we need to expend CPU time to actually execute this comparison?

So efforts at reducing the computational tasks of string comparisons geared toward limiting the initial set of possibilities that are considered. 

You should have an appreciation for the sophistication of programs like BLAST in its high-throughput ability for string manipulation. The actual scoring algorithms for these alignment programs are not the complex part of the code. It is the string "pre-processing" that gives them their real power.

!
[[<BACK|BLAST-06]]|[[NEXT>|BLAST-08]]
!How to simplify?
The Search and match problem really boils down to trying to reduce the possible number of combinations that must be scored to arrive at the best alignment. Reducing the size of the 'pattern array' is the key. 

Given these starting patterns, would you really accept an alignment with a total of 12 gaps below?
{{{
     C A T D O G - - - - - - 
     - - - - - - B A T H O G
}}}

First question to consider would then be what is the maximum number of gaps you would be willing to consider as meaningful in a sequence alignment?  Would it be reasonable to limit an alignment of 2 x 6 character strings to only 2 gaps? If so, then the pattern set would be:

{{{
     C A T D O G - - 
     - - B A T H O G
}}}

This would greatly reduce the computational complexity of the scoring process. 

!
[[<BACK|BLAST-07]]|[[NEXT>|BLAST-09]]
!Running Faster Code:
The biggest limitation on code execution time is the recombinatorial diversity of all potential alignments. Given $seq1 has length ''m'' and $seq2 has length ''n'', then the running time of our present script is going to be proportional to:
{{engindent{{{engindent{  ''n^^2^^ * m^^2^^'' }}}}}}

//This is really bad for any program. If execution time is proportional to an exponential function of the size of the input data, then you are fighting a losing battle. You will never have enough computer time to finish a REAL, biological analysis!!!// 

So we often have to look for ways to reduce the computational complexity. They are logical shortcuts to reduce CPU time overhead, but without sacrificing any accuracy of the work.
{{{
# Alignment options: . . . . . 
	# max number of gaps in a row
		my $maxgap = 2;
	# decimal percent of how much sequence MUST be aligned
		my $OVERlap = 0.0;       
}}}
So by simple altering the these two variables, we can largely reduce the scope of the computational problem:
{{{
# Just using default zero values:
There are 261 permutations for "CATDOG"    using "xxxxxx----------"
There are 477 permutations for "BATPIGDOG" using "xxxxxxxxx-------"
------------------------------
1. Score = 35
    |-CAT---DOG|
    |B-ATPIGDOG|
------------------------------
2. Score = 35
    |C-AT---DOG|
    |-BATPIGDOG|

(Time for code execution : . . . 232.46 CPU)

# Now using maxgap at 3 and sequence overlap at 50%:
There are 177 permutations for "CATDOG"    using "xxxxxx------"
There are 123 permutations for "BATPIGDOG" using "xxxxxxxxx---"
------------------------------
1. Score = 35
    |-CAT---DOG|
    |B-ATPIGDOG|
------------------------------
2. Score = 35
    |C-AT---DOG|
    |-BATPIGDOG|

(Time for code execution :  . . . 7.05 CPU)
}}}
|@@''Here we have changed the scope of the calculation without changing the algorithm or the accuracy of the results''@@|
!
[[<BACK|BLAST-08]]|[[NEXT>|BLAST-10]]
!Dynamic Tables
__REFERENCE:__
Needleman, S.B. and C.D. Wunsch. 1970. A general method applicable to the search for similarities in the amino acid sequences of two proteins. //Journal Molecular Biology// ''48'',443-453.

The algorithm presented in this paper falls into a broad classification of code blocks known as ''Dynamic Programming''. Basically, this type of approach allows for recursive iterations to solve problems with the level of recursiveness and number of iterations determined at run time based on the current progress of the algorithm. 

This approach to matching or aligning strings utilizes a character x character comparison matrix instead of a direct string x string comparison. 

!Tables
Consider an alignment of the following words: ''PELICAN'' and ''COELACANTH''

<html><img src="2011/pelicanalign.png" style="height:50px"></html>

<html><img src="2011/pelicantable.png" style="height:300px"></html>

!
[[<BACK|BLAST-09]]|[[NEXT>|BLAST-11]]
!String Table

Let's compare ''CAT'' to ''BAT''.

<html><img src="2011/table01.png" style="height:200px"></html>

~Needleman-Wunsch Algorithm uses a simple neighbor analysis statistic:
## ''Compute the MATCH score:''
### the sum of the diagonal cell score and the score for a match (+1 or -1)
## ''Compute the horizontal gap score:''
### the sum of the cell score to the left and the gap score (-1)
## ''Compute the vertical gap score:''
### the sum of the cell score above and the gap score (-1)
## ''Keep the largest of the three values:''
### MAX(match, h-gap,v-gap)


!!!Fill in the default no-match all-gap row and column
<html><img src="2011/table02.png" style="height:200px"></html>
So the B x C cell has three calculated values:
# Match = 0 + -1 = -1
# H-gap = -1 + (-1) = -2
# V-gap = -1 + (-1) = -2
And the MAX value for these calcs is thus -1. So that is the value that ends up in the matrix in the B x C cell.

Before moving ahead with this comparison, let's first look at the most simple comparison possible . . . one string compared to itself . . . [[Next>|L06b1]]

!




[[<BACK|BLAST-10]]|[[NEXT>|BLAST-12]]
!Scoring Matrix
Rather than generating individual gap-sequence-chains for separate alignment scores, the dynamic scoring table or matrix generates this information on the fly by a simple character to character comparison. The simplest example is a comparison of one string to itself:
{{{
my $seq1 = "CATDOG";
my $seq2 = "CATDOG";
}}}
In the table below, the gap penalty is -0.5 and the match score is +1.0:
|   | - | C | A | T | D | O | G |
| - |bgcolor(yellow): 0.0 | -0.5 | -1.0 | -1.5 | -2.0 | -2.5 | -3.0 |
| C | -0.5 |bgcolor(yellow): 1.0 | 0.5 | 0.0 |-0.5 | -1.0 | -1.5 |
| A | -1.0 | 0.5 |bgcolor(yellow): 2.0 | 1.5 | 1.0 | 0.5 | 0.0 |
| T | -1.5 | 0.0 | 1.5 |bgcolor(yellow): 3.0 | 2.5 | 2.0 | 1.5 |
| D | -2.0 | -0.5 | 1.0 | 2.5 |bgcolor(yellow): 4.0 | 3.5 | 3.0 |
| O | -2.5 | -1.0 | 0.5 | 2.0 | 3.5 |bgcolor(yellow): 5.0 | 4.5 |
| G | -3.0 | -1.5 | 0.0 | 1.5 | 3.0 | 4.5 |bgcolor(yellow): 6.0 |
<html><img src="06/Mscore-CATDOG.png" style="height:500px"></html>
[[<BACK|BLAST-11]]|[[NEXT>|BLAST-13]]
!CATXXXXDOG
{{{
my $seq1 = "CATXXXXDOG";
my $seq2 = "CATDOG";
}}}
|   | - | C | A | T | D | O | G |
| - |bgcolor(yellow): 0.0 | -0.5 | -1.0 | -1.5 | -2.0 | -2.5 | -3.0 |
| C | -0.5 |bgcolor(yellow): 1.0 | 0.5 | 0.0 |-0.5 | -1.0 | -1.5 |
| A | -1.0 | 0.5 |bgcolor(yellow): 2.0 | 1.5 | 1.0 | 0.5 | 0.0 |
| T | -1.5 | 0.0 | 1.5 |bgcolor(yellow): 3.0 | 2.5 | 2.0 | 1.5 |
| X | -2.0 | -0.5 | 1.0 | 2.5 | 2.0 | 1.5 | 1.0 |
| X | -2.5 | -1.0 | 0.5 | 2.0 | 1.5 | 1.0 | 0.5 |
| X | -3.0 | -1.5 | 0.0 | 1.5 | 1.0 | 1.5 | 0.0 |
| X | -3.5 | -2.0 | -0.5 | 1.0 | 0.5 | 0.0 | -0.5 |
| D | -4.0 | -2.5 | -1.0 | 0.5 |bgcolor(yellow): 2.0 | 1.5 | 1.0 |
| O | -4.5 | -3.0 | -1.5 | 0.0 | 1.5 |bgcolor(yellow): 3.0 | 2.5 |
| G | -5.0 | -3.5 | -2.0 | -0.5 | 1.0 | 2.5 |bgcolor(yellow): 4.0 |
<html><img src="06/Mscore-CATXDOG.png" style="height:500px"></html>
[[<BACK|BLAST-12]]|[[NEXT>|BLAST-14]]
!CAT vs BAT: Gap penalty = -1
Three variables are set:
# Score for Match = +1
# Score for Mismatch = -1
# Score for a gap = -1
!!Compute the table:
~Needleman-Wunsch Algorithm uses a simple neighbor analysis statistic:
## ''Compute the MATCH score:''
### the sum of the diagonal cell score and the score for a match (+1 or -1)
## ''Compute the horizontal gap score:''
### the sum of the cell score to the left and the gap score (-1)
## ''Compute the vertical gap score:''
### the sum of the cell score above and the gap score (-1)
## ''Keep the largest of the three values:''
### MAX(match, h-gap,v-gap)
<html><img src="2011/Table-CATBAT01.png" style="height:300px"></html>

!!Back Trace through max table values
<html><img src="2011/Table-CATBAT02.png" style="height:300px"></html>

!!Decisions based on maximizing algorithm sum
<html><img src="2011/Table-CATBAT03.png" style="height:300px"></html>

!!Final Alignment String:
{{{
       CAT
       BAT
}}}
<html><img src="2011/Table-CATBAT04.png" style="height:300px"></html>

!
[[<BACK|BLAST-13]]|[[NEXT>|BLAST-15]]
!CAT vs BAT: Gap penalty = 0
Three variables are set:
# Score for Match = +1
# Score for Mismatch = -1
# Score for a gap = 0

!!Fill out table
<html><img src="2011/Table-CATBAT05.png" style="height:300px"></html>

!!Trace back maximizing cell sum
<html><img src="2011/Table-CATBAT06.png" style="height:300px"></html>

!!Final Alignment
{{{
1.     CAT
      B-AT
or

2.    C-AT
       BAT
}}}
<html><img src="2011/Table-CATBAT07.png" style="height:300px"></html>
!
[[<BACK|BLAST-14]]|[[NEXT>|BLAST-16]]

!~NeedlemanWunschAlign

The authors algorithm presented in this paper falls into a broad classification of code blocks known as ''Dynamic Programming''. Basically, this type of approach allows for recursive iterations to solve problems with the level of recursiveness and number of iterations determined at run time based on the current progress of the algorithm. 
{{{
# Program calls subroutine LOOP:
    &LOOP($i,$j);

#-------------------
sub LOOP
{     my ($x, $y) = @_;
      my $m = somefunction<<$x>>;
      my $n = somefunction<<$y>>;
      &LOOP($m,$n);  # But LOOP calls itself again and again . . . 
}
}}}

!Working Code:
Save this script as: ''01.0-~NeedlemanWunschAlign.pl''
{{{
#!/usr/bin/perl
use strict;
# - - - - - H E A D E R - - - - - - - - - - - - - - - - -
################################################################
# An implementation of a Dynamic Programming Table for sequence
#   alignment using the Needleman-Wunsch Algorithm.
# Source: Genomic Perl: From Bioinformatics Basics to Working Code
#         Copyright (c) 2002 Rex A. Dwyer.
################################################################

# - - - - - U S E R    V A R I A B L E S - - - - - - - -
my $seq1 = "CATDOGHOUSE";
my $seq2 = "BATHOGBIRDHOUSE";

# - - - - - G L O B A L  V A R I A B L E S  - - - - - -
my @M;        # alignment matrix; filled by similarity scores
my $g = -0.5;   # gap penalty

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# - - - - - M A I N - - - - - - - - - - - - - - - - - - - -
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
print "\n\nNeedleman-Wunsch Dynamic Programming Table Alignment:\n";

# 1. Run similarity score first . . . . . . 
	print "      Similarity score: ", &Similarity($seq1,$seq2), "\n";
	
# 2. Find the alignment for that similarity score . . . . 
	print "      Alignment: \n";
	foreach my $x (&Alignment($seq1,$seq2)) 
	{	print "                 ",$x,"\n"; }

&Dump;

print "\n\n    * * * D O N E * * *\n\n";
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# - - - - - S U B R O U T I N E S - - - - - - - - - - -
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
sub Similarity 
{	# call &Similarity($seq1, $seq2)
	# Determines score of best alignment of strings $seq1 and $seq2
	# Score values are stored in @M
	# Returns max alignment score
	# Calls subroutines &ID and &MAX
	#. . . . . . . . . . . . . . . . .
    my($s,$t) = @_;  # sequences to be aligned.
    foreach my $i (0..length($s)) { $M[$i][0] = $g * $i; }
    foreach my $j (0..length($t)) { $M[0][$j] = $g * $j; }
	
    foreach my $i (1..length($s)) 
	{	foreach my $j (1..length($t)) 
		{	my $p =  &ID(substr($s,$i-1,1),substr($t,$j-1,1));
			$M[$i][$j] = &MAX($M[$i-1][$j] + $g, $M[$i][$j-1] + $g,$M[$i-1][$j-1] + $p);
		}
    }
    return ( $M[length($s)][length($t)] );
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
sub ID 
{  # call &ID(char1,char2)
    my ($aa1, $aa2) = @_;
    return ($aa1 eq $aa2)?1:-1;
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
sub MAX
{	# find max value
	# call &MAX(default value, other values . . . )
	my ($m,@l) = @_;
    foreach my $x (@l) { $m = $x if ($x > $m); }
    return $m;
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
sub Alignment
{	# call &Alignment(seq1,seq2)
    my ($s,$t) = @_;  ## sequences to be aligned.
    my ($i,$j) = (length($s), length($t));
    return ( "-"x$j, $t) if ($i==0);
    return ( $s, "-"x$i) if ($j==0);
    my ($sLast,$tLast) = (substr($s,-1),substr($t,-1));
    
    if ($M[$i][$j] == $M[$i-1][$j-1] + &ID($sLast,$tLast)) 
	{ ## Case 1: last letters are paired in the best alignment
		my ($sa, $ta) = &Alignment(substr($s,0,-1), substr($t,0,-1));
		return ($sa . $sLast , $ta . $tLast );
    } 
	elsif ($M[$i][$j] == $M[$i-1][$j] + $g) 
	{ ## Case 2: last letter of the first string is paired with a gap
		my ($sa, $ta) = &Alignment(substr($s,0,-1), $t);
		return ($sa . $sLast , $ta . "-");
    } 
	else 
	{ ## Case 3: last letter of the 2nd string is paired with a gap
		my ($sa, $ta) = &Alignment($s, substr($t,0,-1));
		return ($sa . "-" , $ta . $tLast );
    }
}

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
sub Dump
{	# output score matrix . . . . . 
	open(OUT,">Mscore3.txt");
	print OUT "X\tY\tM\n";
	foreach my $i (0..length($seq1))
	{	foreach my $j (0..length($seq2))
		{	print OUT "$i\t$j\t$M[$i][$j]\n"; }
	}
	close(OUT);
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# - - - - - EOF - - - - - - - - - - - - - - - - - - - - - -
}}}

!
[[<BACK|BLAST-15]]|[[Return to Lecture Index>|Lecture Index]]
!~NeedlemanWunsch BLAST 
This script uses the ~Needleman-Wunsch algorithm in a "BLAST"-like implementation to find the best similarity alignment between a query sequence and a FASTA file of reference sequences.
{{{
#!/usr/bin/perl
use strict;
$|=1;      # forces print output to be sent to screen in real-time

# - - - - - H E A D E R - - - - - - - - - - - - - - - - -
#     OBJECTIVE: simple implementation of the Needleman-Wunsch algorithm 
#     to find the best alignment for a target sequence in a FASTA file.

# - - - - - U S E R    V A R I A B L E S - - - - - - - -
my $infile = "xxxx";  
my $TargetSeq = "yyyy";

# - - - - - G L O B A L  V A R I A B L E S  - - - - - -
my @FILE;        # input array to hold file contents
my %NTs;         # Hash-Array to hold each orf name & sequence
my @M;           # alignment matrix; filled by similarity scores
my $match = 2.25;          # match bonus
my $g = -0.50;                # gap penalty
my $mismatch = -0.75;   # mismatch penalty

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# - - - - - M A I N - - - - - - - - - - - - - - - - - - - -
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
print "\n\nI don't know Toto, but I don't think we are in Kansas anymore:\n";

# 1. Input FASTA and make protein sequences . . . . 
	&ReadFasta($infile);

# 2. Iteratively execute the similarity scoring subroutine: 
	my $max = -99999;
	my $seq1 = $TargetSeq;
	foreach my $gene (keys %NTs)
	{	my $seq2 = $NTs{$gene};
	 	my $score = &Similarity($seq1,$seq2);
		if ($score > $max)
		{	$max = $score;
			print "\n\n---------------------------------\n";
			print "      Alignment: $gene\n      Score= $score\n";
			foreach my $x (&Alignment($seq1,$seq2)) 
			{	print "                 ",$x,"\n"; }
		}
		else
		{	print " . "; } # just "." so you know the program is still runnning
	}

print "\n\n    * * * D O N E * * *\n\n";
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# - - - - - S U B R O U T I N E S - - - - - - - - - - -
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# - - - - - - - - - - - - - - - - - - - - - - - - - -
sub ReadFasta
{   my $file = $_[0];
	$/=">";
	open(FASTA,"<$file") or die "\n\n\n Nada $file\n\n\n";
	@FILE=<FASTA>;
	close(FASTA);
	shift(@FILE); 
	foreach my $orf (@FILE)
	{	my @Lines = split(/\n/,$orf);
		my $name = $Lines[0];
		my $seq = "";
		foreach my $i (1..$#Lines)
		{	$seq .= $Lines[$i]; }
		$seq =~ s/>//;
		$NTs{$name} = $seq;
	}
	$/="\n"; # reset input break character
}
# - - - - - - - - - - - - - - - - - - - - - - - - - -
# - - - - - - - - - - - - - - - - - - - - - - - - - -
sub Similarity 
{	# call &Similarity($seq1, $seq2)
	# Determines score of best alignment of strings $seq1 and $seq2
	# Score values are stored in @M
	# Returns max alignment score
	# Calls subroutines &ID and &MAX
	#. . . . . . . . . . . . . . . . .
    my($s,$t) = @_;  # sequences to be aligned.
    foreach my $i (0..length($s)) { $M[$i][0] = $g * $i; }
    foreach my $j (0..length($t)) { $M[0][$j] = $g * $j; }
	
    foreach my $i (1..length($s)) 
	{	foreach my $j (1..length($t)) 
		{	my $p =  &ID(substr($s,$i-1,1),substr($t,$j-1,1));
			$M[$i][$j] = &MAX($M[$i-1][$j] + $g, $M[$i][$j-1] + $g,$M[$i-1][$j-1] + $p);
		}
    }
    return ( $M[length($s)][length($t)] );
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
sub ID 
{  # call &ID(char1,char2)
    my ($aa1, $aa2) = @_;
    return ($aa1 eq $aa2)?$match:$mismatch;
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
sub MAX
{	# find max value
	# call &MAX(default value, other values . . . )
	my ($m,@l) = @_;
    foreach my $x (@l) { $m = $x if ($x > $m); }
    return $m;
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
sub Alignment
{	# call &Alignment(seq1,seq2)
    my ($s,$t) = @_;  ## sequences to be aligned.
    my ($i,$j) = (length($s), length($t));
    return ( "-"x$j, $t) if ($i==0);
    return ( $s, "-"x$i) if ($j==0);
    my ($sLast,$tLast) = (substr($s,-1),substr($t,-1));
    
    if ($M[$i][$j] == $M[$i-1][$j-1] + &ID($sLast,$tLast)) 
	{ ## Case 1: last letters are paired in the best alignment
		my ($sa, $ta) = &Alignment(substr($s,0,-1), substr($t,0,-1));
		return ($sa . $sLast , $ta . $tLast );
    } 
	elsif ($M[$i][$j] == $M[$i-1][$j] + $g) 
	{ ## Case 2: last letter of the first string is paired with a gap
		my ($sa, $ta) = &Alignment(substr($s,0,-1), $t);
		return ($sa . $sLast , $ta . "-");
    } 
	else 
	{ ## Case 3: last letter of the 2nd string is paired with a gap
		my ($sa, $ta) = &Alignment($s, substr($t,0,-1));
		return ($sa . "-" , $ta . $tLast );
    }
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# ---------------------------------------------------------
# ---------------------------------------------------------
# - - - - - EOF - - - - - - - - - - - - - - - - - - -

}}}
[[<Back to Lecture Index|Lecture Index]]|[[Recombinometrics>|Babel02]]
!Lecture: Recombinatorial Diversity
# [[Recombinometrics: Library of Babel|Babel02]]
# [[Unimaginable Mathematics|Babel03]]
# [[Babel Library of Genomes?|Babel04]]
# [[Computational Challenge|Babel05]]
# [[Computational Advantage|Babel06]]
# [[Recombinatorial Proofreading|Babel07]]
# [[Emergence|Babel08]]
# [[Entropy|Babel09]]
# [[Simplified Model Systems|Babel10]]
# [[Babel Gallery|Babel11]]
# [[Genetic Algorithms|Babel12]]
# [[Babel Model|Babel13]]
# [[Reading References|Babel14]]
!
<[[BACK|Babel-01]]|[[MAIN|Babel-01]]|[[NEXT|Babel03]]>
!!!
!Recombinometric Diversity
<html><img src="01/Borges-Google.jpg" style="height:300px"></html>
^^Google Images^^

Borges ([[see more info here|Jorge Borges]]) was a writer and philosopher with a large interest in classical theology and mathematics. But his day job was as a librarian and in this 1941 essay one can see a very well developed day-dream of his as he roamed the book stacks of the Argentine National Library in Buenos Ares. 

Reading Assignment: [[Library of Babel]]

''Borges:'' keen interests in theology and geometry

//Library of Babel// essay written in 1941 describing the combinometrics of 22 letters and three punctuation characters (space, comma, period). 25 orthographic symbols in the total set of characters.
!!!
Each book is:
{{engindent{410 pages
40 lines per page
80 characters per line}}}

Total characters in a book:  410 x 40 x 80 = 1,312,000 total characters
!!!
How many different books are there?

{{engindent{25^^1,312,000^^}}}
OR
{{engindent{10^^1,834,097^^}}}
(//note: this number is a digit 1 followed by 1,834,097 "0" digits, which is a number too large to even represent within a book of 410 pages x 40 lines per page x 80 characters per line//). 
!!!
   

<[[BACK|Babel02]]|[[MAIN|Babel-01]]|[[NEXT|Babel04]]>
!!!
!Unimaginable Mathematics
William Goldbloom Bloch, "The Unimaginable Mathematics of Borges' Library of Babel".
<html><img src="01/bookcover.jpg" style="height:300px"></html>

Bloch provides some interesting mathematical insights into the "structure" of Library of Babel. 

''How big would it be?''
1. Assume that you could fit 1000 (10^^3^^) books into one cubic meter. This is an admittedly large over-estimate. 
2. Our known universe is ~1.5 x 10^^26^^ meters across. Round up to again be generous and call it 10^^27^^ meters. 
3. Make a generous estimate of the size of the universe by assuming it is a cube, 10^^27^^ meters on a side, giving a total volume of 10^^81^^ m^^3^^

SO . . . . given a universe of 10^^81^^ m^^3^^ and 10^^3^^ books per m^^3^^, our universe could physically contain 10^^84^^ such books. 

Far short of the 10^^1,834,097^^ total books in the library.

In fact, it would take 10^^1,834,013^^ parallel universes to ours in order to fit all these combinatorial books.

!!!
<[[BACK|Babel03]]|[[MAIN|Babel-01]]|[[NEXT|Babel05]]>
!!!
!Babel Library of Genomes?

Daniel Dennet, __Darwin's Dangerous Idea__ (1995), proposed a "Library of Mendel" based on Borges' recombinatorial library.

Imagine such a "~GenBank" where every genome that has existed, or now exists, or would exist in the future, would be accessible . . . . if you could find them.

//Given that there are only 4 DNA letters (nucleotides A, G, T, C), would a recombinatorial library of genomes be more manageable?//

Take an average bacterial genome of 3 MB. 
How many possible genomes would there be?

{{engindent{4^^3,000,000^^}}}
OR
{{engindent{10^^1,806,180^^}}}

How different does this number look to you from: 10^^1,834,097^^

OK, but bacteria are much smaller than books. Assume the average size of a bacterium to be ~ 5 cubic microns  or 5 x10^^-18^^ m^^3^^. Then you could fit ~ 2 x 10^^17^^ bacteria in one m^^3^^. 

In a universe of 10^^81^^ m^^3^^, then you could fit a total of 10^^98^^ bacteria.

(//for scale, remember that the age of our solar system is only 10^^18^^ seconds//)

!!!
<[[BACK|Babel04]]|[[MAIN|Babel-01]]|[[NEXT|Babel06]]>
!!!
!Computational Challenge

As biologists, you are faced with the daunting task of trying to decipher biological patterns in sequence data but with only being able to see a infinitesmally small limited myopic unfocused biased fraction of sequence data.

''~BioInformatics:'' discerning patterns of system organization against a background of disorganization. 

!
^^(from http://en.wikipedia.org/wiki/Bioinformatics)^^
''Bioinformatics'' is the application of information technology to the field of molecular biology. The term bioinformatics was coined by Paulien Hogeweg in 1978 for the study of informatic processes in biotic systems. Bioinformatics nowadays entails the creation and advancement of databases, algorithms, computational and statistical techniques, and theory to solve formal and practical problems arising from the management and analysis of biological data. Over the past few decades rapid developments in genomic and other molecular research technologies and developments in information technologies have combined to produce a tremendous amount of information related to molecular biology. It is the name given to these mathematical and computing approaches used to glean understanding of biological processes. Common activities in bioinformatics include mapping and analyzing DNA and protein sequences, aligning different DNA and protein sequences to compare them and creating and viewing 3-D models of protein structures. Bioinformatics is the branch of life science that deals with the study of application of information technology to the field of molecular biology.

!
!//We are all __babel librarians__ wandering the stacks, flipping through pages in books looking for signs or hints of sense.//

!!! 

<[[BACK|Babel05]]|[[MAIN|Babel-01]]|[[NEXT|Babel07]]>
!!!
!Computational Advantage

Biological systems are NOT random recombinatorial systems. 

Consider the calculation that there are 10^^1,806,180^^ possible bacterial genomes of 3 MB in size. 

What fraction of that total genome "space" would be occupied by "viable" genomes of bacteria that have existed, or currently exist, or could possibly exist in the future?

Well, if you can only fit 10^^90^^ in the universe, then that would be:

{{engindent{10^^90^^/10^^1,806,180^^ = 10^^-1,806,090^^}}}

Yes, that is a very small fraction, regardless of how rough the estimates above may be.

So biological system organization bypasses all the __''potential''__  genotype space. Evolution proceeds down a narrow path . . . . canalization. 

The importance of this simple realization is that we know a GREAT deal about what biological systems are NOT like. We call these random or null models or distributions and our computational goals are basically to statistically test if observed features in a biological system are best described by a null or random process (we attempt to affirm a null hypothesis).

!!!
<[[BACK|Babel06]]|[[MAIN|Babel-01]]|[[NEXT|Babel08]]>
!!!
!Recombinatorial Proofreading

In Bloch's book __The Unimaginable Mathematics of Borges' Library of Babel__, he ends his presentation with a metaphor of the librarian as a Turing machine. A simple, linear processor running through the text of each book programmed only to look for "words." 

So consider a simple system in which a computer program was tasked to parse through the library, looking for books in which all the orthographic entries were "words" determined by matching against a language dictionary (rule 1)?

And if the processing rule was optimized so that when the first non-word was encountered, the rest of the book was skipped (rule 2).

Obviously the task of the Librarian would be greatly accelerated.

If a third rule was imposed to select only those books in which there were no grammatical errors, the search for books with meaning would be even more tightly focused and efficient.

So for biological systems, could Natural Selection operate like a great Turing machine to efficiently retain only those units that "qualify" as making sense as defined by these 3 simple rules?

!





  

<[[BACK|Babel07]]|[[MAIN|Babel-01]]|[[NEXT|Babel09]]>
!!!
!Emergence
| //"What limit can be put to this power, acting during long ages and rigidly scrutinizing the whole constitution, structure, and habits of each creature -- favoring the good and rejecting the bad? I can see no limit to this power, in slowly and beautifullyadapting each form to the most complex relations of life."// |
^^Charles Darwin, __Origin of Species__, p.469^^

Complex systems can evolve from simple rule sets (solar systems, mammalian circulatory systems, a squid eye . . . . )

This is possible only when there is an "unimaginable" amount of recombinatorial space (//phenotypes or genotypes//) that could potentially exist. Then a series of simple rules for parsing or selecting a path through that space has a high probability of "reaching" the end of that path. In this way, Biological sequence organization, structure, complexity organically EMERGE from the process of natural selection. @@Is this TRUE?@@

In trying to distinguish between a random sequence vs. a structured sequence we often employ concepts related to measuring the information content or information complexity of sequences (Entropy), because we believe that as genomes evolve, their information content changes. @@Is this TRUE?@@

!
<[[BACK|Babel08]]|[[MAIN|Babel-01]]|[[NEXT|Babel10]]>
!!!
!Entropy
''ENTROPY'' is a concept to describe the information content of a system given different states of organization. It is borrowed by molecular biologists to describe the "organization" of sequence information. The idea of information entropy was first developed for telecommunications by: Shannon and Weaver, 1949, "The mathematical theory of communication," University of Illinois Press, Chicago.

The idea is that the more information you have about a system, the more certain you are about the current state of that system. The ~Shannon-Weaver entropy statistics works by a fairly simple summation of the probability states of any system to establish a metric that represents how much you DON'T know about that system. Entropy (H') is an inverse measure in that the greater the system entropy value, the more complex a system is because it's current state is known with less certainty.

Weather Example:  let's say there is a 90% chance of rain today, a 9% chance of overcast clouds but no rain, and a 1% chance of partly cloudy, sunny skies, with no rain. This weather "system" has the following potential probabilities: 

''WEATHER~~system1~~ = [//p//(Rain), //p//(Clouds), //p//(Sun)] = [0.90, 0.09, 0.01]''

If you heard this information on the radio when you woke up, you would likely make a mental note to be prepared fro rain when you left home. If however the forecast was for 33% chance of rain and a 34% chance of overcast skies with no rain and a 33% chance of partly cloudy, sunny skies, with no rain, then you would not be quick to conclude that you needed an umbrella for the day. 

''WEATHER~~system2~~ = [//p//(Rain), //p//(Clouds), //p//(Sun)] = [0.33, 0.34, 0.33]''

To make a decision about whether or not to bring an umbrella you would need to access more weather data (doppler radar, etc.) to better ascertain the impending state of system 2.

So these two weather states have very different levels of predictability or complexity or entropy. We generally calculate an entropy statistic as the summation of the probability of each possible state (//p//~~i~~) multiplied by the natural log of that probability:

| ''H'' = -1 * sum [//p//~~i~~ * Ln(//p//~~i~~) ]  |

''H''-WEATHER~~system1~~ = -1 * ( (0.90 * -0.11) + (0.09 * -2.41) + (0.01 * -4.61) ) = __0.157__
''H''-WEATHER~~system2~~ = -1 * ( (0.33 * -1.11) + (0.34 * -1.08) + (0.33 * -1.11) ) = __1.099__

So if we compare the entropy numbers, the larger value for WEATHER~~system2~~ is interpreted to mean that there is more uncertainty about whether or not it will rain or shine on this day. The high number value means that it is more complex of a decision to ascertain the true state of the weather for day 2. 


!
<[[BACK|Babel09]]|[[MAIN|Babel-01]]|[[NEXT|Babel11]]>
!!!
!Simplifying Models

| //Can the human mind study the human brain?// |

!Is this LIFE?
{{{
MSSQNRPLRIYYSRRHRIGECCGTGSRRTPSAGTVVGISTKDLAKKEERDRFRQLFSARLSWDRRTPLICAVAVLIYPTR
IGDEWGTRGAIGPGTGSRAMRDFMGKPEPVQCSSWHRCRRNDTHEMLARSGIIVERCDHDSLDPRSRNERRISNRVVAPVLVPPCLMRN
MKPHLTPGEENRLSLSSQPVRDPTRVGKNPFERGGWNRDPVLRDSPEGRRVLWWEFRVPHTVRTVFRRSQPKYVIYNGSTEMEEH
STFRWLPRGATGAGWLRGRGQKQSMSVRTTPVKTPADGRASAGPPVLMRYRSLGAIGYRYRSINAQIRDG
NRIKRNGPAMLPLQGVGYKQYHRVEIVPLAAGRSSRNSKQMECLISLVMIWVSGLATSIVPALRILTDLDGLLDQAVFHSRRMLR
RTQSCSSHMLELVRCKKCSGRVGMIRGSVPRLSAQICHITLERNTQSPKELDSVRRARTTKTNVETRRWPSMLRFRRPRLP
}}}
!Is this ART?
<html><img src="01/Claude_Monet_Nympheas_Marmottan.jpg" style="height:300px"></html>
!
| //Can one computer program study the output of another computer program?// |
''Often you need to work with a simple model system prior to develop metrics and code so that you have a clear understanding of what exactly your bioinformatic pipeline is doing.'' 
!

<[[BACK|Babel10]]|[[MAIN|Babel-01]]|[[NEXT|Babel12]]>
!!!
!Genetic Algorithms
Class of models for solving computational problems "de novo"

Example: de novo polygon car design [[http://boxcar2d.com/|http://boxcar2d.com/]]
<html><img src="01/boxcar2d.png" style="height:400px"></html>

!!!Simple Logic:
# Create ANCESTOR object
# Ancestor object replicates to form DESCENDANT object
# DESCENDANT object mutates during the replication process
# DESCENDANT object is functionally evaluated
# If DESCENDANT is better than ANCESTOR, then the DESCENDANT becomes the new ANCESTOR of the next generation
# If DESCENDANT is not better than ANCESTOR, it is discarded and the existing ANCESTOR is replicated for the next generation

Run through a million generations, and a very complex, functionally intricate DESCENDANT can evolve from a simple ANCESTOR with a simple set of selection rules. 

|@@Although the recombinatorial space may be unimaginable in total, the descendants will trace but a single path through the phenotype space@@|

!

<[[BACK|Babel11]]|[[MAIN|Babel-01]]|[[NEXT|Babel13]]>
!!!
!Babel Library of Art

* Simple model for gene/protein relationship:
* 3 nucleotides = a codon triplet = 1 amino acid
* 3 channels = an RGB triplet =  1 color
* Implementation to utilize the immediacy of recognizing color patterns in a 2D tile grid as opposed to trying to sort out amino acid pattern in a 1D character string. 

As a more tangible model of generating a directed library via recombinatorial diversity, consider a babel gallery of images each 80 x 60 pixels in size. 

Each pixel is reproduced as a color tile so the image size is larger. 
Each pixel has three integers that determine color: R, G, B channels
Each channel can hold an integer from 0 to 255.

Inside this Babel recombinatorial gallery, would be a representation of every 2D artwork that has ever been produced and that will ever be produced. All paintings, prints, lithographs, photographs . . . . European, Eastern, Inuit, Roman, Norse,  . . . . 
| @@How many images would be contained in this babel gallery?@@|
!!Randomized Color Map:
<html><img src="01/Babel-090220.png" style="height:400px"></html>
//Is this ART?//

!
<[[BACK|Babel12]]|[[MAIN|Babel-01]]|[[NEXT|Babel14]]>
!!!
!Babel Model
{{{
while(lineage < 40000):    
      # Generate new descendant from ancestor image
      descendant = copy.deepcopy(ancestor)
      descendant.mutate()
      descendant.evaluate()
      if (descendant.cvscore > ancestor.cvscore):
            descendant.save_current_image_data(namestr)
            del(ancestor)
            ancestor = copy.deepcopy(descendant)
            lineage = lineage + 1 
      del(descendant)
}}}

The only tricky part of this model is the "evaluation" function. How do you evaluate an image to decide if it is a better image or not? 

Could use Entropy . . . . 
Could use color pallete . . . . 
Could use . . . . . 

In this implementation, I have just chosen to use a simple metric that scores each pixel for how different the R, G and B values are from the pixels that surround it. The idea is to select for some degree of localized color uniformity. So the selection force is to minimize variance in RGB channels among neighboring tiles.

<html><table><tr>
<td><img src="01/Alpha-090115-start.png" style="height:250px"></td>
<td><img src="01/Alpha-090115-end.png" style="height:250px"></td>
</tr></table></html>
//Final image is generation #940,891//
''Plot of functional scores for each descendant in a lineage''
<html><img src="01/PlotData-MuteScores.png" style="height:300px"></html>

''Image Evolution Examples:''
http://icewater.cms.udel.edu/babel/


!
<[[BACK|Babel13]]|[[MAIN|Babel-01]]
!!!
!Reading Refresher
<html><table><tr>
<td><img src="01/DarwinOriginSpecies.png" style="height:300px"></td>
<td><img src="01/DennettDDI.png" style="height:300px"></td>
</tr>
<tr>
<td><img src="01/Bloch.png" style="height:300px"></td>
<td><img src="01/ShannonWeaver.png" style="height:300px"></td>
</tr>
<tr>
<td><img src="01/Morowitz.png" style="height:300px"></td>
<td><img src="01/Dawkins.png" style="height:300px"></td>

</tr></table></html>
!
[[< Back to Resources|Resource Index]]
!Bioinformatics Core at DBI:

BIOHEN is a new (started in 2011) shared computing cluster at Delaware Biotechnology Institute (DBI).  Computing nodes come from different sources: some are contributed by DBI, some are contributed by faculty members.

INFORMATION: http://bioit.dbi.udel.edu/

SYSTEM ADMINISTRATOR: Karol Miaskiewicz <miaskiew@udel.edu>

BIOHEN nodes are located in the computing center at DBI.  They are linked by gigabit ethernet network (upgrade to 10 gigabit network is expected). Storage is a mix of local storage (the amount varies among nodes) and shared storage - /home filesystem, where users' home directories reside, is NFS-shared across the cluster. 

The master node of BIOHEN is //biohen.dbi.udel.edu//.  This is the host where you log in via ssh:  

| prompt> ssh name@biohen.dbi.udel.edu |

where “name” is username of your Unix account at DBI.  After you successfully login to biohen.dbi.udel.edu, you can perform your calculations by submitting them for execution in the Torque/PBS batch system. 

!!!Basic UNIX commands
Work through this simple @@[[UNIX TUTORIAL|http://www.ee.surrey.ac.uk/Teaching/Unix/unix1.html]]@@ to get an introduction to command window controls.
These are the basic commands you will need to use:
{{{
commands:
      ls  = list files aka "dir"
      rm = remove file aka "delete"
      cd .. = change directory up one level
      cd foldername = change directory down one level to foldername
      mkdir foldername = make directory foldername
}}}

!!!
[[<BACK to Code Page|BoneYard]]
!
Here's a skeleton outline for your PERL scripts:
{{{
#!/usr/bin/perl
use strict;

# - - - - - H E A D E R - - - - - - - - - - - - - - - - -


# - - - - - U S E R    V A R I A B L E S - - - - - - - -


# - - - - - G L O B A L  V A R I A B L E S  - - - - - -


# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# - - - - - M A I N - - - - - - - - - - - - - - - - - - - -
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -


# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# - - - - - S U B R O U T I N E S - - - - - - - - - - -
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -


# - - - - - EOF - - - - - - - - - - - - - - - - - - - - - -
}}}

# SETUP: The file has to start with a "shebang" line. This line tells the OS what interpreter to use for executing the following script commands. Here, "/usr/bin/perl" designates the name and file location of the binary executable file. Then the modules or packages to be included during the run are listed. Here the "strict" package is invoked to provide better error recognition and reporting from the perl interpreter.
# HEADER: describe what the script actually does.
# USER VARS: whatever the user has to do to easily run the program should be put here.
# GLOBAL VARS: declare the most important variables that will be used up front.
# MAIN: this is the actual program.
# SUBROUTINES: functions that are built-in to the script.
#EOF: just flags the end of the file.

!
!Script Crypt
# A skeleton file for starting a PERL script: @@[[BoneCode]]@@
# A Tic Tac Toe game board script 3x3: @@[[TicTacToe Human 3x3|TicTacToe-07]]@@  
# A Tic Tac Toe game board script ~NxN: @@[[TicTacToe Human NxN|TicTacToe-08]]@@ 
# A Tic Tac Toe game board script ~NxN: @@[[TicTacToe Computer NxN Replicate|TicTacToe SuperBowl]]@@ 
# An R script for analyzing Tic Tac Toe game results: @@[[TicTacToe R Analysis|TicTacToe R Stats]]@@ 

!!Subroutines
# Notes: [[Array Referencing for subroutines|ArrayRef]]
# sub [[&GBKread|GenBank read genome subroutine]]
# sub [[&FASTAread|FASTA read subroutine]]
# sub [[&LoadCodonTable|LoadCodonTable]]
# sub [[&TranslateFasta|TransFasta]]
# sub [[&GCcalc|GCcalc]]
# sub [[&Codon Frequency|CodonFreq]]
# sub [[&AAfreq|AAcounter]]
# sub [[&AAmass|AAmass]]
# sub [[&AAnitrogen|AAnitrogen]]
# sub [[&Entropy H'|Entropy Calc]]
# sub [[&Codon Adaptation Index|CAI]]
# sub [[&Protein Isoelectric Point|IEP]]
# sub [[&SKEW|SKEW]]
# sub [[&ROUND|Round]]
# sub [[&TIME BENCHMARK|TimeBenchmark]]
# sub [[&TimeStamp|TimeStamp]]
# sub [[&Mean, Median, SkewCalc|MeanMedSkew]]
# sub [[&DUMP]]


/%
** 2nd version with WINNER recognition algorithm: @@[[TTT-WINNER|TicTacToe Winner 04]]@@
** 3rd version with cpu players: @@[[TTT-autoplay|TicTacToe CPU Players]]@@
# Simple Sorting Routines:
** Sort a numerical list hard-coded as an array within the script: @@[[Sort-01|Sorting-08]]@@
** Sort a list input from a data file and parsed into {{{@nums}}}:  @@[[Sort-02|Sorting-10]]@@
** Sort a dictionary structure {{{%Genes}}}:  @@[[Sort-03|Sorting-13]]@@
# HTML Parser: @@[[HTML-ReadParse|HTMLread-03]]@@
# FASTA Reader Script: @@[[FASTAread|FastaRead-05]]@@
# FASTA Bioinformatics Profiling Script: @@[[FASTAanalyze|FastaAnalyze-06]]@@
# FASTA Primary Gene/Protein Characterization: @@[[FASTApipe]]@@
# Character Sequence Alignment Code: @@[[SeqAlign|BLAST-05]]@@
# ~Needleman-Wunsch BLAST Algorithm: @@[[NWblast|BLAST-16]]@@

!!Subroutines
# Notes: [[Array Referencing for subroutines|ArrayRef]]
# sub [[&GBKread|GenBank read genome subroutine]]
# sub [[&FASTAread|FASTA read subroutine]]
# sub [[&LoadCodonTable|LoadCodonTable]]
# sub [[&TranslateFasta|TransFasta]]
# sub [[&GCcalc|GCcalc]]
# sub [[&Codon Frequency|CodonFreq]]
# sub [[&AAfreq|AAcounter]]
# sub [[&AAmass|AAmass]]
# sub [[&AAnitrogen|AAnitrogen]]
# sub [[&Entropy H'|Entropy Calc]]
# sub [[&Codon Adaptation Index|CAI]]
# sub [[&Protein Isoelectric Point|IEP]]
# sub [[&SKEW|SKEW]]
# sub [[&ROUND|Round]]
# sub [[&TIME BENCHMARK|TimeBenchmark]]
# sub [[&TimeStamp|TimeStamp]]
# sub [[&Mean, Median, SkewCalc|MeanMedSkew]]
# sub [[&DUMP]]

!

# FASTA Reader Script: @@[[FASTAread|FastaRead-05]]@@
# Simple FASTA read script @@[[FASTAread]]@@ 
# Simple FASTA translate script @@[[FASTAtranslate]]@@
# Simple Calculation for %GC content by gene @@[[GCcountList]]@@
# FASTA translate script with subroutines and hashes @@[[FASTAtranslate2]]@@
# Generate AA Freq table for Arabidopsis:  @@[[AAfreqCountTable]]@@
# Calculate %GC and AA frequencies by gene: @@[[GCvsAAcount]]@@

# Sorting Code @@[[SortList]]@@
# Simple FASTA read script @@[[FASTAread]]@@ 
# Simple FASTA translate script @@[[FASTAtranslate]]@@
# Simple Calculation for %GC content by gene @@[[GCcountList]]@@
# FASTA translate script with subroutines and hashes @@[[FASTAtranslate2]]@@
# Generate AA Freq table for Arabidopsis:  @@[[AAfreqCountTable]]@@
# Calculate %GC and AA frequencies by gene: @@[[GCvsAAcount]]@@
# Word Comparison Script:
##  Single run comparison: @@[[WordCompare]]@@
##  Looping run comparison to collect benchmark stats: @@[[WordCompareLoop]]@@ 
# MidTerm: ~Needleman-Wunsch "BLAST" similarity/alignment: @@NW-AlignBlast@@
# Calculate LOD scores: @@LODscore@@
# Profile LOD scores along a genomic clone: @@LODprofiling@@
# ~Smith-Waterman implementation for local alignment scoring: @@LocalBLAST@@
# Submitting batch BLAST jobs on Biowolf: @@BLASTrunner@@
# Parsing a BLAST output file: @@BLASTparse_script@@
# Shakespeare's Monkeys typing Hamlet: @@MonkeysTyping@@
!!!Subroutines:
Here are just the subroutine parts that you can move between scripts. Note the variable declaration requirements and the dependence of some on others (ex. &LoadCodonTable has to be called before &[[TranslateFasta|TransFasta]]).
# [[&ReadFasta|ReadFasta]]
# [[&LoadCodonTable - Bacteria|LoadCodonTable-Bacteria]]
# [[&LoadCodonTable GenBank Style|LoadCodonTable-GenBank]]
# [[&TranslateFasta|TransFasta]]
# [[&GCcalc|GCcalc]]
# [[&AAfreq|AAcounter]]
# [[&ROUND|Round]]
# [[&TIME BENCHMARK|TimeBenchmark]]
# [[&TimeStamp|TimeStamp]]
# [[Array Referencing for subroutines|ArrayRef]]
%/
[[<Back to Index|BoneYard]]
!Codon Adaptation Index

Sharp PM, Li WH (February 1987). "The codon Adaptation Index: a measure of directional synonymous codon usage bias, and its potential applications". Nucleic Acids Res. 15 (3): 1281–95. doi:10.1093/nar/15.3.1281. PMC 340524. PMID 3547335.
From Wikipedia: [[http://en.wikipedia.org/wiki/Codon_Adaptation_Index|http://en.wikipedia.org/wiki/Codon_Adaptation_Index]]
<html><img src="01/cai-wiki.png" style="height:250px"></html>


{{{
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
sub CAI
{	print "   Codon Adaptation Index . . . \n";
	my $GenDict = $_[0];
	foreach my $id (keys %{$GenDict})
	{	# 1. Find maxfj = max(fi) for any group of synonymous codons (i.e., codons with the same AA)
		my %maxfj;
		my @AAx = qw | A C D E F G H I K L M N P Q R S T V W Y |;
		foreach my $aa (@AAx)                                                     # < Look at each AA . . . . 
		{	my $max = -1;                                                         # < Initialize with min value . . 
			$maxfj{$aa} = 0;                                                      # < Initialize with min value . . 
			foreach my $codon (keys %CodonTable)                                  # < Look at each Codon . . . 
			{	if ($CodonTable{$codon} == $aa)                                   # < When current codon = current AA . . . 
				{	if (${$GenDict}{$id}{'CDfreq'}{'n'.$codon} > $max)            # < Check if codon freq is max . . .
					{	$maxfj{$aa} = ${$GenDict}{$id}{'CDfreq'}{'n'.$codon}; }
				}
			}
		}
		# 2. CAI Calculation . . . . . . .
		my $seq = ${$GenDict}{$id}{'ntseq'};
		my $N = length(${$GenDict}{$id}{'aaseq'});  # total codons
		my $cai = 0;
		while($seq =~ s/^(...)//)
		{	my $fi = ${$GenDict}{$id}{'CDfreq'}{'n'.$1};
			my $aa = $CodonTable{$1};
			if ($maxfj{$aa} > 0 && $fi > 0)
			{	$cai += log($fi/$maxfj{$aa}); }
		}
		$cai = exp($cai/$N);
		${$GenDict}{$id}{'CAI'} = &RoundOff($cai, 3);
		#&DUMP(${$GenDict}{$id}{'CAI'}); 
	}
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
}}}

!
/***
''Name:'' CalendarPlugin
''Version:'' <<getversion calendar>> (<<getversiondate calendar "DD MMM YYYY">>)
''Author:'' SteveRumsby

''Configuration:''

|''First day of week:''|<<option txtCalFirstDay>>|(Monday = 0, Sunday = 6)|
|''First day of weekend:''|<<option txtCalStartOfWeekend>>|(Monday = 0, Sunday = 6)|

''Syntax:'' 
|{{{<<calendar>>}}}|Produce a full-year calendar for the current year|
|{{{<<calendar year>>}}}|Produce a full-year calendar for the given year|
|{{{<<calendar year month>>}}}|Produce a one-month calendar for the given month and year|
|{{{<<calendar thismonth>>}}}|Produce a one-month calendar for the current month|
|{{{<<calendar lastmonth>>}}}|Produce a one-month calendar for last month|
|{{{<<calendar nextmonth>>}}}|Produce a one-month calendar for next month|

***/
// //Modify this section to change the text displayed for the month and day names, to a different language for example. You can also change the format of the tiddler names linked to from each date, and the colours used.

// // ''[[Changes]] by ELS 2005.10.30:''
// // config.macros.calendar.handler()
// // ^^use "tbody" element for IE compatibility^^
// // ^^IE returns 2005 for current year, FF returns 105... fix year adjustment accordingly^^
// // createCalendarDays()
// // ^^use showDate() function (if defined) to render autostyled date with linked popup^^
// // calendar stylesheet definition
// // ^^use .calendar class-specific selectors, add text centering and margin settings^^

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

config.macros.calendar.monthnames = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
config.macros.calendar.daynames = ["M", "T", "W", "T", "F", "S", "S"];

config.macros.calendar.weekendbg = "#c0c0c0";
config.macros.calendar.monthbg = "#e0e0e0";
config.macros.calendar.holidaybg = "#ffc0c0";

//}}}
// //''Code section:''
// (you should not need to alter anything below here)//
//{{{
if(config.options.txtCalFirstDay == undefined)
  config.options.txtCalFirstDay = 0;
if(config.options.txtCalStartOfWeekend == undefined)
  config.options.txtCalStartOfWeekend = 5;

config.macros.calendar.tiddlerformat = "0DD/0MM/YYYY";  // This used to be changeable - for now, it isn't// <<smiley :-(>> 

version.extensions.calendar = { major: 0, minor: 6, revision: 0, date: new Date(2006, 1, 22)};
config.macros.calendar.monthdays = [ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];

config.macros.calendar.holidays = [ ]; // Not sure this is required anymore - use reminders instead
//}}}

// //Is the given date a holiday?
//{{{
function calendarIsHoliday(date)
{
 var longHoliday = date.formatString("0DD/0MM/YYYY");
 var shortHoliday = date.formatString("0DD/0MM");

 for(var i = 0; i < config.macros.calendar.holidays.length; i++) {
   if(config.macros.calendar.holidays[i] == longHoliday || config.macros.calendar.holidays[i] == shortHoliday) {
     return true;
   }
 }
 return false;
}
//}}}

// //The main entry point - the macro handler.
// //Decide what sort of calendar we are creating (month or year, and which month or year)
// // Create the main calendar container and pass that to sub-ordinate functions to create the structure.
// ELS 2005.10.30: added creation and use of "tbody" for IE compatibility and fixup for year >1900//
// ELS 2005.10.30: fix year calculation for IE's getYear() function (which returns '2005' instead of '105')//
//{{{
config.macros.calendar.handler = function(place,macroName,params)
{
   var calendar = createTiddlyElement(place, "table", null, "calendar", null);
   var tbody = createTiddlyElement(calendar, "tbody", null, null, null);
   var today = new Date();
   var year = today.getYear();
   if (year<1900) year+=1900;
   if (params[0] == "thismonth")
  {
      cacheReminders(new Date(year, today.getMonth(), 1, 0, 0), 31);
      createCalendarOneMonth(tbody, year, today.getMonth());
  } 
  else if (params[0] == "lastmonth") {
      var month = today.getMonth()-1; if (month==-1) { month=11; year--; }
      cacheReminders(new Date(year, month, 1, 0, 0), 31);
      createCalendarOneMonth(tbody, year, month);
   }
   else if (params[0] == "nextmonth") {
      var month = today.getMonth()+1; if (month>11) { month=0; year++; }
      cacheReminders(new Date(year, month, 1, 0, 0), 31);
      createCalendarOneMonth(tbody, year, month);
   }
   else {
      if (params[0]) year = params[0];
      if(params[1])
      {
         cacheReminders(new Date(year, params[1]-1, 1, 0, 0), 31);
         createCalendarOneMonth(tbody, year, params[1]-1);
      }
      else
      {
         cacheReminders(new Date(year, 0, 1, 0, 0), 366);
         createCalendarYear(tbody, year);
      }
   }
  window.reminderCacheForCalendar = null;
}
//}}}
//{{{
//This global variable is used to store reminders that have been cached
//while the calendar is being rendered.  It will be renulled after the calendar is fully rendered.
window.reminderCacheForCalendar = null;
//}}}
//{{{
function cacheReminders(date, leadtime)
{
  if (window.findTiddlersWithReminders == null)
    return;
  window.reminderCacheForCalendar = {};
  var leadtimeHash = [];
  leadtimeHash [0] = 0;
  leadtimeHash [1] = leadtime;
  var t = findTiddlersWithReminders(date, leadtimeHash, null, 1);
  for(var i = 0; i < t.length; i++) {
    //just tag it in the cache, so that when we're drawing days, we can bold this one.
     window.reminderCacheForCalendar[t[i]["matchedDate"]] = "reminder:" + t[i]["params"]["title"]; 
  }
}
//}}}
//{{{
function createCalendarOneMonth(calendar, year, mon)
{
  var row = createTiddlyElement(calendar, "tr", null, null, null);
  createCalendarMonthHeader(calendar, row, config.macros.calendar.monthnames[mon] + " " + year, true, year, mon);
  row = createTiddlyElement(calendar, "tr", null, null, null);
  createCalendarDayHeader(row, 1);
  createCalendarDayRowsSingle(calendar, year, mon);
}
//}}}

//{{{
function createCalendarMonth(calendar, year, mon)
{
  var row = createTiddlyElement(calendar, "tr", null, null, null);
  createCalendarMonthHeader(calendar, row, config.macros.calendar.monthnames[mon] + " " + year, false, year, mon);
  row = createTiddlyElement(calendar, "tr", null, null, null);
  createCalendarDayHeader(row, 1);
  createCalendarDayRowsSingle(calendar, year, mon);
}
//}}}

//{{{
function createCalendarYear(calendar, year)
{
  var row;
  row = createTiddlyElement(calendar, "tr", null, null, null);
  var back = createTiddlyElement(row, "td", null, null, null);
  var backHandler = function() {
      removeChildren(calendar);
      createCalendarYear(calendar, year-1);
    };
  createTiddlyButton(back, "<", "Previous year", backHandler);
  back.align = "center";

  var yearHeader = createTiddlyElement(row, "td", null, "calendarYear", year);
  yearHeader.align = "center";
  yearHeader.setAttribute("colSpan", 19);

  var fwd = createTiddlyElement(row, "td", null, null, null);
  var fwdHandler = function() {
    removeChildren(calendar);
    createCalendarYear(calendar, year+1);
  };
  createTiddlyButton(fwd, ">", "Next year", fwdHandler);
  fwd.align = "center";

  createCalendarMonthRow(calendar, year, 0);
  createCalendarMonthRow(calendar, year, 3);
  createCalendarMonthRow(calendar, year, 6);
  createCalendarMonthRow(calendar, year, 9);
}
//}}}

//{{{
function createCalendarMonthRow(cal, year, mon)
{
  var row = createTiddlyElement(cal, "tr", null, null, null);
  createCalendarMonthHeader(cal, row, config.macros.calendar.monthnames[mon], false, year, mon);
  createCalendarMonthHeader(cal, row, config.macros.calendar.monthnames[mon+1], false, year, mon);
  createCalendarMonthHeader(cal, row, config.macros.calendar.monthnames[mon+2], false, year, mon);
  row = createTiddlyElement(cal, "tr", null, null, null);
  createCalendarDayHeader(row, 3);
  createCalendarDayRows(cal, year, mon);
}
//}}}

//{{{
function createCalendarMonthHeader(cal, row, name, nav, year, mon)
{
  var month;
  if(nav) {
    var back = createTiddlyElement(row, "td", null, null, null);
    back.align = "center";
    back.style.background = config.macros.calendar.monthbg;

/*
    back.setAttribute("colSpan", 2);

    var backYearHandler = function() {
      var newyear = year-1;
      removeChildren(cal);
      cacheReminders(new Date(newyear, mon , 1, 0, 0), 31);
      createCalendarOneMonth(cal, newyear, mon);
    };
    createTiddlyButton(back, "<<", "Previous year", backYearHandler);
*/
    var backMonHandler = function() {
      var newyear = year;
      var newmon = mon-1;
      if(newmon == -1) { newmon = 11; newyear = newyear-1;}
      removeChildren(cal);
      cacheReminders(new Date(newyear, newmon , 1, 0, 0), 31);
      createCalendarOneMonth(cal, newyear, newmon);
    };
    createTiddlyButton(back, "<", "Previous month", backMonHandler);


    month = createTiddlyElement(row, "td", null, "calendarMonthname", name)
//    month.setAttribute("colSpan", 3);
    month.setAttribute("colSpan", 5);

    var fwd = createTiddlyElement(row, "td", null, null, null);
    fwd.align = "center";
    fwd.style.background = config.macros.calendar.monthbg; 

//    fwd.setAttribute("colSpan", 2);
    var fwdMonHandler = function() {
      var newyear = year;
      var newmon = mon+1;
      if(newmon == 12) { newmon = 0; newyear = newyear+1;}
      removeChildren(cal);
      cacheReminders(new Date(newyear, newmon , 1, 0, 0), 31);
      createCalendarOneMonth(cal, newyear, newmon);
    };
    createTiddlyButton(fwd, ">", "Next month", fwdMonHandler);
/*
    var fwdYear = createTiddlyElement(row, "td", null, null, null);
    var fwdYearHandler = function() {
      var newyear = year+1;
      removeChildren(cal);
      cacheReminders(new Date(newyear, mon , 1, 0, 0), 31);
      createCalendarOneMonth(cal, newyear, mon);
    };
    createTiddlyButton(fwd, ">>", "Next year", fwdYearHandler);
*/
  } else {
    month = createTiddlyElement(row, "td", null, "calendarMonthname", name)
    month.setAttribute("colSpan", 7);
  }
  month.align = "center";
  month.style.background = config.macros.calendar.monthbg;
}
//}}}

//{{{
function createCalendarDayHeader(row, num)
{
  var cell;
  for(var i = 0; i < num; i++) {
    for(var j = 0; j < 7; j++) {
      var d = j + (config.options.txtCalFirstDay - 0);
      if(d > 6) d = d - 7;
      cell = createTiddlyElement(row, "td", null, null, config.macros.calendar.daynames[d]);

      if(d == (config.options.txtCalStartOfWeekend-0) || d == (config.options.txtCalStartOfWeekend-0+1))
        cell.style.background = config.macros.calendar.weekendbg;
    }
  }
}
//}}}

//{{{
function createCalendarDays(row, col, first, max, year, mon)
{
  var i;
  for(i = 0; i < col; i++) {
    createTiddlyElement(row, "td", null, null, null);
  }
  var day = first;
  for(i = col; i < 7; i++) {
    var d = i + (config.options.txtCalFirstDay - 0);
    if(d > 6) d = d - 7;
    var daycell = createTiddlyElement(row, "td", null, null, null);
    var isaWeekend = ((d == (config.options.txtCalStartOfWeekend-0) || d == (config.options.txtCalStartOfWeekend-0+1))? true:false);

    if(day > 0 && day <= max) {
      var celldate = new Date(year, mon, day);
      // ELS 2005.10.30: use <<date>> macro's showDate() function to create popup
      if (window.showDate) {
        showDate(daycell,celldate,"popup","DD","DD-MMM-YYYY",true, isaWeekend); 
      } else {
        if(isaWeekend) daycell.style.background = config.macros.calendar.weekendbg;
        var title = celldate.formatString(config.macros.calendar.tiddlerformat);
        if(calendarIsHoliday(celldate)) {
          daycell.style.background = config.macros.calendar.holidaybg;
        }
        if(window.findTiddlersWithReminders == null) {
          var link = createTiddlyLink(daycell, title, false);
          link.appendChild(document.createTextNode(day));
        } else {
          var button = createTiddlyButton(daycell, day, title, onClickCalendarDate);
        }
      }
    }
    day++;
  }
}
//}}}

// //We've clicked on a day in a calendar - create a suitable pop-up of options.
// //The pop-up should contain:
// // * a link to create a new entry for that date
// // * a link to create a new reminder for that date
// // * an <hr>
// // * the list of reminders for that date
//{{{
function onClickCalendarDate(e)
{
  var button = this;
  var date = button.getAttribute("title");
  var dat = new Date(date.substr(6,4), date.substr(3,2)-1, date.substr(0, 2));

  date = dat.formatString(config.macros.calendar.tiddlerformat);
  var popup = createTiddlerPopup(this);
  popup.appendChild(document.createTextNode(date));
  var newReminder = function() {
    var t = store.getTiddlers(date);
    displayTiddler(null, date, 2, null, null, false, false);
    if(t) {
      document.getElementById("editorBody" + date).value += "\n<<reminder day:" + dat.getDate() +
                                                                                         " month:" + (dat.getMonth()+1) +
                                                                                         " year:" + (dat.getYear()+1900) + " title: >>";
    } else {
      document.getElementById("editorBody" + date).value = "<<reminder day:" + dat.getDate() +
                                                                                       " month:" + (dat.getMonth()+1) +
                                                                                       " year:" + (dat.getYear()+1900) + " title: >>";
    }
  };
  var link = createTiddlyButton(popup, "New reminder", null, newReminder); 
  popup.appendChild(document.createElement("hr"));

  var t = findTiddlersWithReminders(dat, [0,14], null, 1);
  for(var i = 0; i < t.length; i++) {
    link = createTiddlyLink(popup, t[i].tiddler, false);
    link.appendChild(document.createTextNode(t[i].tiddler));
  }
}
//}}}

//{{{
function calendarMaxDays(year, mon)
{
 var max = config.macros.calendar.monthdays[mon];
 if(mon == 1 && (year % 4) == 0 && ((year % 100) != 0 || (year % 400) == 0)) {
 max++;
 }
 return max;
}
//}}}

//{{{
function createCalendarDayRows(cal, year, mon)
{
 var row = createTiddlyElement(cal, "tr", null, null, null);

 var first1 = (new Date(year, mon, 1)).getDay() -1 - (config.options.txtCalFirstDay-0);
 if(first1 < 0) first1 = first1 + 7;
 var day1 = -first1 + 1;
 var first2 = (new Date(year, mon+1, 1)).getDay() -1 - (config.options.txtCalFirstDay-0);
 if(first2 < 0) first2 = first2 + 7;
 var day2 = -first2 + 1;
 var first3 = (new Date(year, mon+2, 1)).getDay() -1 - (config.options.txtCalFirstDay-0);
 if(first3 < 0) first3 = first3 + 7;
 var day3 = -first3 + 1;

 var max1 = calendarMaxDays(year, mon);
 var max2 = calendarMaxDays(year, mon+1);
 var max3 = calendarMaxDays(year, mon+2);

 while(day1 <= max1 || day2 <= max2 || day3 <= max3) {
 row = createTiddlyElement(cal, "tr", null, null, null);
 createCalendarDays(row, 0, day1, max1, year, mon); day1 += 7;
 createCalendarDays(row, 0, day2, max2, year, mon+1); day2 += 7;
 createCalendarDays(row, 0, day3, max3, year, mon+2); day3 += 7;
 }
}
//}}}

//{{{
function createCalendarDayRowsSingle(cal, year, mon)
{
 var row = createTiddlyElement(cal, "tr", null, null, null);

 var first1 = (new Date(year, mon, 1)).getDay() -1 - (config.options.txtCalFirstDay-0);
 if(first1 < 0) first1 = first1+ 7;
 var day1 = -first1 + 1;
 var max1 = calendarMaxDays(year, mon);

 while(day1 <= max1) {
 row = createTiddlyElement(cal, "tr", null, null, null);
 createCalendarDays(row, 0, day1, max1, year, mon); day1 += 7;
 }
}
//}}}

// //ELS 2005.10.30: added styles
//{{{
setStylesheet(".calendar, .calendar table, .calendar th, .calendar tr, .calendar td { font-size:10pt; text-align:center; } .calendar, .calendar a { margin:0px !important; padding:0px !important; }", "calendarStyles");
//}}}
/***
|Name|CheckboxPlugin|
|Source|http://www.TiddlyTools.com/#CheckboxPlugin|
|Version|2.2.4|
|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||
|Description|Add checkboxes to your tiddler content|
This plugin extends the TiddlyWiki syntax to allow definition of checkboxes that can be embedded directly in tiddler content.  Checkbox states are preserved by either:
* automatically modifying the tiddler content (deprecated)
* or, by setting/removing tags on specified tiddlers,
* or, by setting custom field values on specified tiddlers,
* or, by saving to a locally-stored cookie ID.
When an ID is assigned to the checkbox, it enables direct programmatic access to the checkbox DOM element, as well as creating an entry in TiddlyWiki's config.options[ID] internal data.  In addition to tracking the checkbox state, you can also specify custom javascript for programmatic initialization and onClick event handling for any checkbox, so you can provide specialized side-effects in response to state changes.
!!!!! Inline wiki-syntax usage
<<<
//{{{
[ ]or[_] and [x]or[X]
//}}}
Simple checkboxes using 'Inline X' storage.  The current unchecked/checked state is indicated by the character between the {{{[}}} and {{{]}}} brackets ("_" means unchecked, "X" means checked).  When you click on a checkbox, the current state is retained by directly modifying the tiddler content to place the corresponding "_" or "X" character in between the brackets.
>//''NOTE: 'Inline X' syntax has been deprecated...''  This storage format only works properly for checkboxes that are directly embedded and accessed from content in a single tiddler.  However, if that tiddler is 'transcluded' into another (by using the {{{<<tiddler TiddlerName>>}}} macro), the 'Inline X' will be ''erroneously stored in the containing tiddler's source content, resulting in corrupted content in that tiddler.''  For anything but the most simple of "to do list" uses, you should select from the various alternative storage methods described below...//
//{{{
[x=id]
//}}}
Assign an optional ID to the checkbox so you can use {{{document.getElementByID("id")}}} to manipulate the checkbox DOM element, as well as tracking the current checkbox state in {{{config.options["id"]}}}.  If the ID starts with "chk" the checkbox state will also be saved in a cookie, so it can be automatically restored whenever the checkbox is re-rendered (overrides any default {{{[x]}}} or {{{[_]}}} value).  If a cookie value is kept, the "_" or "X" character in the tiddler content remains unchanged, and is only applied as the default when a cookie-based value is not currently defined.
//{{{
[x(title|tag)] or [x(title:tag)]
//}}}
Initializes and tracks the current checkbox state by setting or removing a particular tag value from a specified tiddler.  If you omit the tiddler title (and the | or : separator), the specified tag is assigned to the current tiddler.  If you omit the tag value, as in {{{(title|)}}}, the default tag, {{{checked}}}, is assumed.  Omitting both the title and tag, {{{()}}}, tracks the checkbox state by setting the "checked" tag on the current tiddler.  When tag tracking is used, the "_" or "X" character in the tiddler content remains unchanged, and is not used to set or track the checkbox state.  If a tiddler title named in the tag does not exist, the checkbox state defaults to the "inline X" value.  If this value is //checked//, or is subsequently changed to //checked//, it will automatically create the missing tiddler and then add the tag to it.  //''NOTE: beginning with version 2.1.2 of this plugin, the "|" separator is the preferred separator between the title and tag name, as it avoids syntactic ambiguity when ":" is used within tiddler titles or tag names.''//
//{{{
[x(field@tiddler)]
//}}}
Initializes and tracks the current checkbox state by setting a particular custom field value from a specified tiddler.  If you omit the tiddler title (but not the "@" separator), the specified field on the current tiddler is used.  If you omit the field name, as in {{{(@tiddler)}}}, a default fieldname of {{{checked}}} is assumed.  Omitting both the field and the tiddler title, {{{(@)}}}, defaults to setting the "checked" field on the current tiddler.  When field tracking is used, the "_" or "X" character in the tiddler content remains unchanged, and is not used to set or track the checkbox state.  If the tiddler title named in the parameter does not exist, the checkbox state defaults to the "inline X" value.  If this value is //checked// or is subsequently changed to //checked//, it will automatically create the missing tiddler and then add the field to it.
//{{{
[x{javascript}{javascript}]
//}}}
You can define optional javascript code segments to add custom initialization and/or 'onClick' handling to a checkbox.  The current checkbox state (and it's other DOM attributes) can be set or read from within these code segments by reference to the default context-object, 'this'.

The first code segment will be executed when the checkbox is initially displayed, so that you can programmatically determine it's starting checked/unchecked state.  The second code segment (if present) is executed whenever the checkbox is clicked, so that you can perform programmed responses or intercept and override the checkbox state based on complex logic using the TW core API or custom functions defined in plugins (e.g. testing a particular tiddler title to see if certain tags are set or setting some tags when the checkbox is clicked).

Note: if you want to use the default checkbox initialization processing with a custom onclick function, use this syntax: {{{ [x=id{}{javascript}] }}} 
<<<
!!!!! Macro usage
<<<
In addition to embedded checkboxes using the wiki syntax described above, a ''macro-based syntax'' is also provided, for use in templates where wiki syntax cannot be directly used.  This macro syntax can also be used in tiddler content, as an alternative to the wiki syntax.  When embedded in [[PageTemplate]], [[ViewTemplate]], or [[EditTemplate]] (or custom alternative templates), use the following macro syntax:
//{{{
<span macro="checkbox target checked id onInit onClick"></span>
//}}}
or, when embedded in tiddler content, use the following macro syntax:
//{{{
<<checkbox target checked id onInit onClick>>
//}}}
where:
''target''
>is either a tag reference (e.g., ''tagname|tiddlername'') or a field reference (e.g. ''fieldname@tiddlername''), as described above.
''checked'' (optional)
>is a keyword that sets the initial state of the checkbox to "checked".  When omitted, the default checkbox state is "unchecked".
''id'' (optional)
>specifies an internal config.options.* ID, as described above.  If the ID begins with "chk", a cookie-based persistent value will be created to track the checkbox state in between sessions.
''onInit'' (optional)
>contains a javascript event handler to be performed when the checkbox is initially rendered (see details above).
''onClick'' (optional)
>contains a javascript event handler to be performed each time the checkbox is clicked (see details above).
>//note: to use the default onInit handler with a custom onClick handler, use "" (empty quotes) as a placeholder for the onInit parameter//
<<<
!!!!!Examples
<<<
''checked and unchecked static default ("inline X") values:''
//{{{
[X] label
[_] label
//}}}
>[X] label
>[_] label
''document-based value (id='demo', no cookie):''
//{{{
[_=demo] label
//}}}
>[_=demo] label
''cookie-based value  (id='chkDemo'):''
//{{{
[_=chkDemo] label
//}}}
>[_=chkDemo] label
''tag-based value (TogglyTagging):''
//{{{
[_(CheckboxPlugin|demotag)]
[_(CheckboxPlugin|demotag){this.refresh.tagged=this.refresh.container=false}]
//}}}
>[_(CheckboxPlugin|demotag)] toggle 'demotag' (and refresh tiddler display)
>[_(CheckboxPlugin|demotag){this.refresh.tagged=this.refresh.container=false}] toggle 'demotag' (no refresh)
''field-based values:''
//{{{
[_(demofield@CheckboxPlugin)] demofield@CheckboxPlugin
[_(demofield@)] demofield@ (equivalent to demonfield@ current tiddler)
[_(checked@CheckboxPlugin)] checked@CheckboxPlugin
[_(@CheckboxPlugin)] @CheckboxPlugin
[_(@)] @ (equivalent to checked@ current tiddler)
//}}}
>[_(demofield@CheckboxPlugin)] demofield@CheckboxPlugin
>[_(demofield@)] demofield@ (current tiddler)
>[_(checked@CheckboxPlugin)] checked@CheckboxPlugin
>[_(@CheckboxPlugin)] @CheckboxPlugin
>[_(@)] toggle field: @ (defaults to "checked@here")
>click to view current: <<toolbar fields>>
''custom init and onClick functions:''
//{{{
[X{this.checked=true}{alert(this.checked?"on":"off")}] message box with checkbox state
//}}}
>[X{this.checked=true}{alert(this.checked?"on":"off")}] message box with checkbox state
''retrieving option values:''
>config.options['demo']=<script>return config.options['demo']?"true":"false";</script>
>config.options['chkDemo']=<script>return config.options['chkDemo']?"true":"false";</script>
<<<
!!!!!Configuration
<<<
Normally, when a checkbox state is changed, the affected tiddlers are automatically re-rendered, so that any checkbox-dependent dynamic content can be updated.  There are three possible tiddlers to be re-rendered, depending upon where the checkbox is placed, and what kind of storage method it is using.
*''container'': the tiddler in which the checkbox is displayed. (e.g., this tiddler)
*''tagged'': the tiddler that is being tagged (e.g., "~MyTask" when tagging "~MyTask:done")
*''tagging'': the "tag tiddler" (e.g., "~done" when tagging "~MyTask:done")
You can set the default refresh handling for all checkboxes in your document by using the following javascript syntax either in a systemConfig plugin, or as an inline script.  (Substitute true/false values as desired):
{{{config.checkbox.refresh = { tagged:true, tagging:true, container:true };}}}

You can also override these defaults for any given checkbox by using an initialization function to set one or more of the refresh options.  For example:
{{{[_{this.refresh.container=false}]}}}
<<<
!!!!!Installation
<<<
import (or copy/paste) the following tiddlers into your document:
''CheckboxPlugin'' (tagged with <<tag systemConfig>>)
<<<
!!!!!Revision History
<<<
2007.08.06 - 2.2.5 supress automatic refresh of any tiddler that is currently being edited.  Ensures that current tiddler edit sessions are not prematurely discarded (losing any changes).  However, if checkbox changes a tag on a tiddler being edited, update the "tags" input field (if any) so that saving the edited tiddler correctly reflects any changes due to checkbox activity... see refreshEditorTagField().
2007.07.13 - 2.2.4 in handler(), fix srctid reference (was "w.tiddler", should have been "w.tiddler.title").  This fixes broken 'inline X' plus fatal macro error when using PartTiddlerPlugin.  Thanks to cmari for reporting the problem and UdoBorkowski for finding the code error.
2007.06.21 - 2.2.3 suppress automatic refresh of tiddler when using macro-syntax to prevent premature end of tiddler editing session.
2007.06.20 - 2.2.2 fixed handling for 'inline X' when checkboxes are contained in a 'trancluded' tiddler.  Now, regardless of where an inline X checkbox appears, the X will be placed in the originating source tiddler, rather than the tiddler in which the checkbox appears.
2007.06.17 - 2.2.1 Refactored code to add checkbox //macro// syntax for use in templates (e.g., {{{macro="checkbox ..."}}}. Also, code cleanup of existing tag handling.
2007.06.16 - 2.2.0 added support for tracking checkbox states using tiddler fields via "(fieldname@tiddlername)" syntax.
2006.05.04 - 2.1.3 fix use of findContainingTiddler() to check for a non-null return value, so that checkboxes won't crash when used outside of tiddler display context (such as in header, sidebar or mainmenu)
2006.03.11 - 2.1.2 added "|" as delimiter to tag-based storage syntax (e.g. "tiddler|tag") to avoid parsing ambiguity when tiddler titles or tag names contain ":".   Using ":" as a delimiter is still supported but is deprecated in favor of the new "|" usage.  Based on a problem reported by JeffMason.
2006.02.25 - 2.1.0 added configuration options to enable/disable forced refresh of tiddlers when toggling tags
2006.02.23 - 2.0.4 when toggling tags, force refresh of the tiddler containing the checkbox.
2006.02.23 - 2.0.3 when toggling tags, force refresh of the 'tagged tiddler' so that tag-related tiddler content (such as "to-do" lists) can be re-rendered.
2006.02.23 - 2.0.2 when using tag-based storage, allow use [[ and ]] to quote tiddler or tag names that contain spaces:
{{{[x([[Tiddler with spaces]]:[[tag with spaces]])]}}}
2006.01.10 - 2.0.1 when toggling tags, force refresh of the 'tagging tiddler'.  For example, if you toggle the "systemConfig" tag on a plugin, the corresponding "systemConfig" TIDDLER will be automatically refreshed (if currently displayed), so that the 'tagged' list in that tiddler will remain up-to-date.
2006.01.04 - 2.0.0 update for ~TW2.0
2005.12.27 - 1.1.2 Fix lookAhead regExp handling for {{{[x=id]}}}, which had been including the "]" in the extracted ID.  
Added check for "chk" prefix on ID before calling saveOptionCookie()
2005.12.26 - 1.1.2 Corrected use of toUpperCase() in tiddler re-write code when comparing {{{[X]}}} in tiddler content with checkbox state. Fixes a problem where simple checkboxes could be set, but never cleared.
2005.12.26 - 1.1.0 Revise syntax so all optional parameters are included INSIDE the [ and ] brackets.  Backward compatibility with older syntax is supported, so content changes are not required when upgrading to the current version of this plugin.   Based on a suggestion by GeoffSlocock
2005.12.25 - 1.0.0 added support for tracking checkbox state using tags ("TogglyTagging")
Revised version number for official post-beta release.
2005.12.08 - 0.9.3 support separate 'init' and 'onclick' function definitions.
2005.12.08 - 0.9.2 clean up lookahead pattern
2005.12.07 - 0.9.1 only update tiddler source content if checkbox state is actually different.  Eliminates unnecessary tiddler changes (and 'unsaved changes' warnings)
2005.12.07 - 0.9.0 initial BETA release
<<<
!!!!!Credits
<<<
This feature was created by EricShulman from [[ELS Design Studios|http:/www.elsdesign.com]]
<<<
!!!!!Code
***/
//{{{
version.extensions.CheckboxPlugin = {major: 2, minor: 2, revision:5 , date: new Date(2007,8,6)};
//}}}

//{{{
config.checkbox = { refresh: { tagged:true, tagging:true, container:true } };
config.formatters.push( {
	name: "checkbox",
	match: "\\[[xX_ ][\\]\\=\\(\\{]",
	lookahead: "\\[([xX_ ])(=[^\\s\\(\\]{]+)?(\\([^\\)]*\\))?({[^}]*})?({[^}]*})?\\]",
	handler: function(w) {
		var lookaheadRegExp = new RegExp(this.lookahead,"mg");
		lookaheadRegExp.lastIndex = w.matchStart;
		var lookaheadMatch = lookaheadRegExp.exec(w.source)
		if(lookaheadMatch && lookaheadMatch.index == w.matchStart) {
			// get params
			var checked=(lookaheadMatch[1].toUpperCase()=="X");
			var id=lookaheadMatch[2];
			var target=lookaheadMatch[3];
			if (target) target=target.substr(1,target.length-2).trim(); // trim off parentheses
			var fn_init=lookaheadMatch[4];
			var fn_click=lookaheadMatch[5];
			var tid=story.findContainingTiddler(w.output);  if (tid) tid=tid.getAttribute("tiddler");
			var srctid=w.tiddler?w.tiddler.title:null;
			config.macros.checkbox.create(w.output,tid,srctid,w.matchStart+1,checked,id,target,config.checkbox.refresh,fn_init,fn_click);
			w.nextMatch = lookaheadMatch.index + lookaheadMatch[0].length;
		}
	}
} );
config.macros.checkbox = {
	handler: function(place,macroName,params,wikifier,paramString,tiddler) {
		if(!(tiddler instanceof Tiddler)) { // if no tiddler passed in try to find one
			var here=story.findContainingTiddler(place);
			if (here) tiddler=store.getTiddler(here.getAttribute("tiddler"))
		}
		var srcpos=0; // "inline X" not applicable to macro syntax
		var target=params.shift(); if (!target) target="";
		var defaultState=params[0]=="checked"; if (defaultState) params.shift();
		var id=params.shift(); if (id && !id.length) id=null;
		var fn_init=params.shift(); if (fn_init && !fn_init.length) fn_init=null;
		var fn_click=params.shift(); if (fn_click && !fn_click.length) fn_click=null;
		var refresh={ tagged:true, tagging:true, container:false };
		this.create(place,tiddler.title,tiddler.title,0,defaultState,id,target,refresh,fn_init,fn_click);
	},
	create: function(place,tid,srctid,srcpos,defaultState,id,target,refresh,fn_init,fn_click) {
		// create checkbox element
		var c = document.createElement("input");
		c.setAttribute("type","checkbox");
		c.onclick=this.onClickCheckbox;
		c.srctid=srctid; // remember source tiddler
		c.srcpos=srcpos; // remember location of "X"
		c.container=tid; // containing tiddler (may be null if not in a tiddler)
		c.tiddler=tid; // default target tiddler 
		c.refresh = {};
		c.refresh.container = refresh.container;
		c.refresh.tagged = refresh.tagged;
		c.refresh.tagging = refresh.tagging;
		place.appendChild(c);
		// set default state
		c.checked=defaultState;
		// track state in config.options.ID
		if (id) {
			c.id=id.substr(1); // trim off leading "="
			if (config.options[c.id]!=undefined)
				c.checked=config.options[c.id];
			else
				config.options[c.id]=c.checked;
		}
		// track state in (tiddlername|tagname) or (fieldname@tiddlername)
		if (target) {
			var pos=target.indexOf("@");
			if (pos!=-1) {
				c.field=pos?target.substr(0,pos):"checked"; // get fieldname (or use default "checked")
				c.tiddler=target.substr(pos+1); // get specified tiddler name (if any)
				if (!c.tiddler || !c.tiddler.length) c.tiddler=tid; // if tiddler not specified, default == container
				if (store.getValue(c.tiddler,c.field)!=undefined)
					c.checked=(store.getValue(c.tiddler,c.field)=="true"); // set checkbox from saved state
			} else {
				var pos=target.indexOf("|"); if (pos==-1) var pos=target.indexOf(":");
				c.tag=target;
				if (pos==0) c.tag=target.substr(1); // trim leading "|" or ":"
				if (pos>0) { c.tiddler=target.substr(0,pos); c.tag=target.substr(pos+1); }
				if (!c.tag.length) c.tag="checked";
				var t=store.getTiddler(c.tiddler);
				if (t && t.tags)
					c.checked=t.isTagged(c.tag); // set checkbox from saved state
			}
		}
		if (fn_init) c.fn_init=fn_init.trim().substr(1,fn_init.length-2); // trim off surrounding { and } delimiters
		if (fn_click) c.fn_click=fn_click.trim().substr(1,fn_click.length-2);
		c.init=true; c.onclick(); c.init=false; // compute initial state and save in tiddler/config/cookie
	},
	onClickCheckbox: function(event) {
		if (this.fn_init)
			// custom function hook to set initial state (run only once)
			{ try { eval(this.fn_init); this.fn_init=null; } catch(e) { displayMessage("Checkbox init error: "+e.toString()); } }
		else if (this.fn_click)
			// custom function hook to override or react to changes in checkbox state
			{ try { eval(this.fn_click) } catch(e) { displayMessage("Checkbox click error: "+e.toString()); } }
		if (this.id)
			// save state in config AND cookie (only when ID starts with 'chk')
			{ config.options[this.id]=this.checked; if (this.id.substr(0,3)=="chk") saveOptionCookie(this.id); }
		if (this.srctid && this.srcpos>0 && (!this.id || this.id.substr(0,3)!="chk") && !this.tag && !this.field) {
			// save state in tiddler content only if not using cookie, tag or field tracking
			var t=store.getTiddler(this.srctid); // put X in original source tiddler (if any)
			if (t && this.checked!=(t.text.substr(this.srcpos,1).toUpperCase()=="X")) { // if changed
				t.set(null,t.text.substr(0,this.srcpos)+(this.checked?"X":"_")+t.text.substr(this.srcpos+1),null,null,t.tags);
				if (!story.isDirty(t.title)) story.refreshTiddler(t.title,null,true);
				store.setDirty(true);
			}
		}
		if (this.field) {
			if (this.checked && !store.tiddlerExists(this.tiddler))
				store.saveTiddler(this.tiddler,this.tiddler,"",config.options.txtUserName,new Date());
			// set the field value in the target tiddler
			store.setValue(this.tiddler,this.field,this.checked?"true":"false");
			// DEBUG: displayMessage(this.field+"@"+this.tiddler+" is "+this.checked);
		}
		if (this.tag) {
			if (this.checked && !store.tiddlerExists(this.tiddler))
				store.saveTiddler(this.tiddler,this.tiddler,"",config.options.txtUserName,new Date());
			var t=store.getTiddler(this.tiddler);
			if (t) {
				var tagged=(t.tags && t.tags.find(this.tag)!=null);
				if (this.checked && !tagged) { t.tags.push(this.tag); store.setDirty(true); }
				if (!this.checked && tagged) { t.tags.splice(t.tags.find(this.tag),1); store.setDirty(true); }
			}
			// if tag state has been changed, update display of corresponding tiddlers (unless they are in edit mode...)
			if (this.checked!=tagged) {
				if (this.refresh.tagged) {
					if (!story.isDirty(this.tiddler)) story.refreshTiddler(this.tiddler,null,true); // the TAGGED tiddler in view mode
					else config.macros.checkbox.refreshEditorTagField(this.tiddler,this.tag,this.checked); // the TAGGED tiddler in edit mode (with tags field)
				}
				if (this.refresh.tagging)
					if (!story.isDirty(this.tag)) story.refreshTiddler(this.tag,null,true); // the TAGGING tiddler
			}
		}
		// refresh containing tiddler (but not during initial rendering, or we get an infinite loop!) (and not when editing container)
		if (!this.init && this.refresh.container && this.container!=this.tiddler)
			if (!story.isDirty(this.container)) story.refreshTiddler(this.container,null,true); // the tiddler CONTAINING the checkbox
		return true;
	},
	refreshEditorTagField: function(title,tag,set) {
		var tagfield=story.getTiddlerField(title,"tags");
		if (!tagfield||tagfield.getAttribute("edit")!="tags") return; // if no tags field in editor (i.e., custom template)
		var tags=tagfield.value.readBracketedList();
		if (tags.contains(tag)==set) return; // if no change needed
		if (set) tags.push(tag); // add tag
		else tags.splice(tags.indexOf(tag),1); // remove tag
		for (var t=0;t<tags.length;t++) tags[t]=String.encodeTiddlyLink(tags[t]);
		tagfield.value=tags.join(" "); // reassemble tag string (with brackets as needed)
		return;
	}
}
//}}}
!Coding Assignments

/%
!!
<html><div style="color: rgb(100, 100, 150); font-family: Monaco;"><big><b>
PROJECT 02, due Wednesday, 10 DEC</html>''Microbial Genome Analyses'' 
In this assignment you will compare two microbial genomes of at least 4 MB in total size and at least 2,000 genes. Use the working code modules to calculate the following metrics per gene for each genome:
* GC Content
* Nucleotide Frequency
* Amino Acid Frequency
* Codon Frequency
* Entropy H'
** Amino Acid
** Codon
** Nucleotide (note: you will have to code this)
* Codon Adaptation Index
* Protein Isoelectric Point
* Protein Mass
** Total Amino Acid Nitrogen
** Total Amino Acid Mass
** Ratio AA Nitrogen to AA Mass (note: you will have to code this)

These metric values all need to be written to a data table for plotting in R. A simple R plot script is posted on DropBox along with a sample data table. Plot these variables in as many combinations you can think of. Choose 4 of those plots to compare between the two genomes (so each of the 4 figures will have two panels, one for each genome). BE SURE TO SELECT PLOTS THAT SHOW DIFFERENCES BETWEEN THE GENOMES THAT YOU CAN DISCUSS. If your plots all look the same, then you'll need to select new genomes.

Submission Requirement:
Analysis Report:
* Introduction
** Some background on microbe one
** Some background on microbe two
** Some rationale for why you selected these two
* Results
** Figure 1 and a paragraph description of what is plotted and how it differs between genomes
** Figure 2 and a paragraph description of what is plotted and how it differs between genomes
** Figure 3 and a paragraph description of what is plotted and how it differs between genomes
** Figure 4 and a paragraph description of what is plotted and how it differs between genomes
* Summary
** An overall conclusion of results
** Your overall assessment of your bioinformatic skills and ideas

Upload a PDF with your embedded figures all as one file to the ~DropBox folder named ~10-Project2. The target folder for uploading will be available on the due date.


!!
<html><div style="color: rgb(100, 100, 150); font-family: Monaco;"><big><b>
PROJECT 01, due Wednesday, 19 NOV</html>''PubMed Keyword Analysis'' 
As discussed in class, select a broad keyword (A) for a PubMed search and download the results including abstracts. Use the parsing scripts to categorize publications by year and then conduct a "joint" word analysis using 3 other key words (B, C, D). The end result should be an annual %Frequency of pubs with keywords A and B normalized to the annual occurrence of pubs with keyword A. Here's an example plot from Michael: 

<html><img src="2014/99-Colgan-PLOT-FreqTermsvsYear.png" style="height:300px"></html>

Submission Requirement:
Upload a PDF with your embedded graphic and a paragraph description of your project all as one document. The target folder for uploading will be available on the due date.



!!
<html><div style="color: rgb(100, 100, 150); font-family: Monaco;"><big><b>
Assignment 08, due Monday, 03 NOV</html>''Restriction Digest: Multi Genomes Analysis'' 
From the subroutine modules listed on the "Working Code" page of the course website, select two subroutines to plug into the worker script we've developed, debug any input/output issues, generate a data table comparing 3 genomes, load and plot your two variables using the R script. Submit plot figure on Monday plus the worker code script (as usual).


!!
<html><div style="color: rgb(100, 100, 150); font-family: Monaco;"><big><b>
Assignment 07, due Monday, 20 OCT</html>''Restriction Digest: Multi Genomes x GC content'' 
* Compare 4 genomes x 4 Restriction Endonucleases
* Use the NCBI bacterial genomes you used previously:
* Use the script developed in class (~06-~RestrictionDigest-GC) to calculate %GC for fragments and write values to table output file.
* Use the R script to plot x= ~FragLength and y=%GC. (Use #3. GC Size Plot in R script)
* Submit code (perl) AND a PNG file of your output. 
* REQUIRED: Include the RE abbreviations in the TITLE line of your plot.  



!!
<html><div style="color: rgb(100, 100, 150); font-family: Monaco;"><big><b>
Assignment 06, due Monday, 13 OCT</html>''Restriction Digest: Multi Genomes'' 
* Compare 4 genomes x 4 Restriction Endonucleases
* Use the NCBI bacterial genome FTP site to obtain genome seq data:
** ftp://ftp.ncbi.nih.gov/genomes/Bacteria/
** Connect as GUEST
** Browse species folders and select 4
** Inside a target folder, select the largest GBK (*.gbk) file there and ~download/copy to your local computer.
** Open the GBK file in an editor and delete all the information from the top down to the ORIGIN marker where the sequence data actually begins. Add a header line that contains enough info to identify the genome sequence (see one of my input files as an example).
* Use the script developed in class to run the 4 x 4 analysis and generate a fragment table output file.
* Use the R script to plot the data
* Submit code (perl) AND a PNG file of your output. REQUIRED: Include the RE abbreviations in the TITLE line of your plot.  
%/

!!
<html><div style="color: rgb(100, 100, 150); font-family: Monaco;"><big><b>
PROJECT 02, due Wednesday, 16 DEC</html>''Microbial Genome Analyses'' 
In this assignment you will compare two microbial genomes, Acinetobacter and Psuedomonas. Use the working code modules available on the course web site, calculate the following metrics per gene for each genome:
* GC Content
* Amino Acid Frequency
* Codon Frequency
* Entropy H'
** Amino Acid
** Codon
* Codon Adaptation Index
* Protein Isoelectric Point
* Protein Mass
** Total Amino Acid Nitrogen
** Total Amino Acid Mass

These metric values are calculated for each gene within each genome. The metric values for each gene result all need to be written to a data table for plotting in R. A simple R plot script is posted on ~DropBox along with a sample data table that was generated in class. Plot these variables in as many combinations you can think of using the Rscript to EXPLORE. The most fruitful x-axis variables to concentrate on are going to be GC content and any of the protein specific metrics. Choose 4 plots that compare x,y metrics between the two genomes (so each of the 4 figures will have two panels, one for each genome). BE SURE TO SELECT PLOTS THAT SHOW DIFFERENCES BETWEEN THE GENOMES THAT YOU CAN DISCUSS. 

Submission Requirement:
Analysis Report:
* Introduction (100 words)
** Overview of the methods you employed
** Description of the range of metrics you explored
* Results
** Figure 1 and a paragraph (100 words) description of what is plotted and how it differs between genomes
** Figure 2 and a paragraph (100 words) description of what is plotted and how it differs between genomes
** Figure 3 and a paragraph (100 words) description of what is plotted and how it differs between genomes
** Figure 4 and a paragraph (100 words) description of what is plotted and how it differs between genomes
* Summary (100 words)
** An overall conclusion of results
** Description of the coding challenges you faced and solved

Upload a PDF with your embedded figures all as one file to the ~DropBox folder named ~P02-GenomeMetrics. 

If you need help: email me.


!!
<html><div style="color: rgb(100, 100, 150); font-family: Monaco;"><big><b>
Assignment 07, due Wednesday, 09 DEC</html>''REGEX Motif Count:'' Use the PsuedoAerug-uid162173 genome file as the DNA source. Design a regex motif to match each group of sequences that is in your target regex file (1 to 20). Iterate the ~GenomeRegex script so that each group of motifs is counted in the genome file with the following output format:
{{{print "$m. There are $mcount of $motif.\n";}}}
Where $m is the motif group count (1 to 20), $mcount is the count of how many occurrences there are of the members in the motif group, and $motif is the regex expression that you used to execute the search. You will submit your script in the designated HW folder.  No pdf plots or report.  


!!
<html><div style="color: rgb(100, 100, 150); font-family: Monaco;"><big><b>
PROJECT 01, due Monday, 07 DEC</html>''PubMed Keyword Analysis'' 
As discussed in class, select a broad keyword (A) for a PubMed search and download the results including abstracts. Use the parsing scripts to categorize publications by year and then conduct a "joint" word analysis using 3 other key words (B, C, D). The end result should be an annual %Frequency of pubs with keywords B, C & D normalized to the annual occurrence of pubs with keyword A. Here's an example plot: 
<html><img src="2014/99-Colgan-PLOT-FreqTermsvsYear.png" style="height:300px"></html>

Submission Requirement:
Upload a 2 page PDF with your graphic and a 500 word summary description of what you did and what you found (all as one document). The target folder for uploading will be available on the due date.

!!
<html><div style="color: rgb(100, 100, 150); font-family: Monaco;"><big><b>
Assignment 06, due Monday, 26 OCT</html>''~RandomWords:'' Submit a PDF figure on 1 page that presents the ~Nmer word distributions for two microbial genomes for 3, 4, 5, and 6 mer word lengths. Use the script developed in class to iterate over ~Nmer values and now iterate over two genomes; write all iteration data to the same data file; read that data in to the provided R script; generate the plot. Submit a 1 page PDF document with your result plot and appropriate titles and figure legend description.  

!!
<html><div style="color: rgb(100, 100, 150); font-family: Monaco;"><big><b>
Assignment 05, due Monday, 19 OCT</html>''~RandomWords:'' Submit a PDF figure on 1 page that presents the ~Nmer word distributions in a random genome for 3, 4, and 5 mer word lengths. Use the script developed in class to iterate over ~Nmer values; write all iteration data to the same data file; read that data in to the provided R script; generate the plot.  

!!
<html><div style="color: rgb(100, 100, 150); font-family: Monaco;"><big><b>
Assignment 04, due Monday, 05 OCT</html>''~Repetitive Matches Tic Tac Toe:'' Add another layer of iteration to the TTT script so that those 100 games in Assignment 3 are now repeated 1000 times so that you have 1000 repeat observations of the win frequency of 100 games. Output results to a Table. Use the R script to plot. Submit a 1 page PDF document with your result plot and appropriate titles and figure legend description.   

!!
<html><div style="color: rgb(100, 100, 150); font-family: Monaco;"><big><b>
Assignment 03, due Monday, 28 SEP, in class</html>''~TicTacToe Stat Analysis:'' Modify the program code discussed in class to iterate 100 random tic tac toe games, counting the number of X wins, O wins and D non-wins (draws), then out put the results to one row of a data table, then iterate 1000 times to build a 1000 row table on TTT game outcomes. There should be no active print statements in your game loop when you submit the assignment (just comment-out any ones you have used). At the end of your script you need to print to screen the GRAND mean results across the 1000 iterations in the following  format:
{{{
Avg number games with X winner = xxx
Avg number games with O winner = yyy
Avg number games with D winner = zzz
}}}
//NOTE: where xxx, yyy and zzz are the mean number of wins rounded to 1 decimal place.//


!!
<html><div style="color: rgb(100, 100, 150); font-family: Monaco;"><big><b>
Assignment 02, due Monday, 21 SEP, in class</html>''~TicTacToe:'' Modify the program code discussed in class last Wednesday to iterate 1000 random tic tac toe games and count the number of X wins, Y wins and Draws (ties). There should be no active print statements in our game loop when you submit the assignment (just comment-out any ones you have used). At the end of your script you need to print to screen the following information in this exact format:
{{{
1. Games with X winner  = xxx
2. Games with O winner  = yyy
3. Games with no winner = zzz
}}}
//NOTE: where xxx, yyy and zzz are the integer counts of the number of games in each category, not a percent or fractional number.//


!!
<html><div style="color: rgb(100, 100, 150); font-family: Monaco;"><big><b>
Assignment 01, due Monday, 14 SEP</html>''FOREACH LOOP INVADERS:'' Submit a simple script that will display the following on screen:
# an increasing " . . . . . . N" string for a random number of iterations, where "dot+space" increments with N increments as we have done in class.
# a decreasing ". . . . . . N" string for a random number of iterations, where "dot+space" decrements with N decrements as we have done in class.
# then repeat the process 1,000 times, using new random numbers for each N.
!
[[<Back|BoneYard]]
!Codon Frequency

Requires &~LoadCodonTable.

{{{
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
sub CodonFreq
{	print "   Codon frequencies . . . \n";
	my $GenDict = $_[0];
	foreach my $id (keys %{$GenDict})
	{	my $seq = ${$GenDict}{$id}{'ntseq'};
		my $N = length($seq)/3;
		if ($N < 1) { print "\n\nError in aaseq length; see sub &CodonFreq\n\n"; die; }
		while ($seq =~ s/^(...)//) 
		{	${$GenDict}{$id}{'CDfreq'}{'n'.$1} += 1/$N;  }
		foreach my $codon (keys %CodonTable)
		{	${$GenDict}{$id}{'CDfreq'}{'n'.$codon} = &RoundOff(${$GenDict}{$id}{'CDfreq'}{'n'.$codon}, 4); }
	}
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
}}}
Background: #fff
Foreground: #000
PrimaryPale: #ddeeaa
PrimaryLight: #ddeeaa
PrimaryMid: #666633
PrimaryDark: #014
SecondaryPale: #bbdd88
SecondaryLight: #fe8
SecondaryMid: #db4
SecondaryDark: #666633
TertiaryPale: #eee
TertiaryLight: #ccc
TertiaryMid: #999
TertiaryDark: #aacc88
Error: #f88
[[<Back to Lecture Index|Lecture Index]]|[[Complexity>|Complexity01]]
!Lecture: Information Complexity
# [[Sequence Complexity|Complexity01]]
# [[What is Complexity 1?|Complexity02]]
# [[What is Complexity 2?|Complexity03]]
# [[Complexity = Information 1|Complexity04]]
# [[Complexity = Information 2|Complexity05]]
# [[Information Concepts: Entropy|Complexity06]]
# [[Complexity in Amino Acid Usage|Complexity07]]
# [[Information Concepts: Uncertainty|Complexity08]]
# [[Information Extraction/Expansion|Complexity09]]
# [[Nicotania benthamiana|Complexity10]]
# [[Gene Entropy|Complexity11]]
# [[Gene Entropy|Complexity12]]
# [[Darwin's Dogs]]
!
<[[BACK|Complexity00]]|[[MAIN|Complexity00]]|[[NEXT|Complexity02]]>
!!!
!Sequence Complexity

Work of a former student, Ryan Dale (now a Bioinformatics Analyst at NIH), focused on describing the sequence complexity and information content of genomes at different levels of organization: nucleotides, codons, proteins.

!!!Figure: The fractional representation of each Amino Acid in the proteome of microbial genomes as a function of the G+C nucleotide composition of a genome. 
<html><img src="01/RD-aafreq-vs-gc.png" style="height:250px"></html>


!!!Figure: Difference in sequence Entropy between nucleotide codons and amino acid residues as a function of genome size and genome G+C composition.
<html><img src="01/Hcodon-Haa-real.jpg" style="height:600px"></html>

!
<[[BACK|Complexity01]]|[[MAIN|Complexity00]]|[[NEXT|Complexity03]]>
!!!
!What Is Complexity?

!!!What is the information content of this image?
50 pixels x 50 pixels, values = 1 or 0
<html><img src="01/Rand1x.png" style="height:500px"></html>

!!!

!
<[[BACK|Complexity02]]|[[MAIN|Complexity00]]|[[NEXT|Complexity04]]>
!!!
!What Is Complexity?

!!!What is the information content of this image?
50 pixels x 50 pixels, values = 1 or 0
<html><img src="01/Rand2.png" style="height:500px"></html>

!!!
<[[BACK|Complexity03]]|[[MAIN|Complexity00]]|[[NEXT|Complexity05]]>
!!!
!Complexity = Information

<html><table><tr>
<td><img src="01/Rand1x.png" style="height:250px"></td>
<td><img src="01/Rand2.png" style="height:250px"></td>
</tr></table></html>

We could measure information or complexity by the file size of the image itself . . . the units 'kb' a measure of information size afterall:

| !FORMAT | !Image 1 | !Image 2|
| TIFF | 670.5 kb | 670.5 kb |
| JPG | 72.1 kb | 42.3 kb |
| PNG |  4.5 kb | 3.1 kb |

!
<[[BACK|Complexity04]]|[[MAIN|Complexity00]]|[[NEXT|Complexity06]]>
!!!
!Complexity = Information

''Two Components to information:''
* an ABSOLUTE content
** tif
** jpg
** png
* a RELATIVE expression
** distribution of elements
** abundance of elements
!!!
Consider the compressed file formats as a reduced set of instructions required to reproduce the original image. 
<html>
<img src="01/Rand1x.png" style="height:150px">
<img src="01/Rand2.png" style="height:150px">
</html>
// In this context, consider the image file as a  @@phenotype@@ and the underlying digital file format as it's corresponding @@genotype@@.//

| Absolute Content = genotype|
| Relative Content = phenotype |

Information is translated from one level to another.

!!!
<[[BACK|Complexity05]]|[[MAIN|Complexity00]]|[[NEXT|Complexity07]]>
!!!
!Information Concepts 1
Information is loosely referred to by several concepts . . . 
# ''Entropy''
** ~Shannon-Weaver formulation
*** H = -1 * sum{ p~~i~~ * log~~2~~(p~~i~~) }
*** where p~~i~~ = the proportion of the i^^th^^ event or state in a system 
**  Serves as a proxy for a distribution test 
*** sensitive to the distribution and relative abundance of all p~~i~~
*** maximal when highly organized, predictable 
*** minimal when fully random, unpredictable or chaotic
** Amino Acid entropy:
*** consider an amino acid frequency distribution where all 20 AA's were equally represented
*** p(A) = p(C) = p(D) . . . . . = p(Y) = 0.05 
*** but amino acids in genomes are not evenly distributed . . . 


!
<[[BACK|Complexity06]]|[[MAIN|Complexity00]]|[[NEXT|Complexity08]]>
!!!
!Information Complexity in Amino Acid Usage


!!!Distribution of amino acids
[img[01/AAprofiles.png]]
!!!AA Entropy vs Genome Size
[img[01/AAentropy_mb.png]]
!!!AA Entropy vs G+C content
[img[01/AAentropy_gc.png]]
<[[BACK|Complexity07]]|[[MAIN|Complexity00]]|[[NEXT|Complexity09]]>
!!!
!Information Concepts 2

* ''Uncertainty''
** Information tells you about parts of a system
** More information about parts provides better knowledge of the total system
** High entropy = higher certainty that knowing one part of the system, you can guess another
<html>
<img src="01/Rand1x.png" style="height:200px">
<img src="01/Rand2.png" style="height:200px">
</html>

* ''Complexity''
** The more complex a system is, the more unpredictable the state of its parts.
** Low entropy = low certainty = higher complexity
** Amino Acid word usage patterns
!!!An information complexity metric is plotted for each AA dictionary (1- to 12-mer) for 150 free-living microbial genomes. 
The organizational structure of local amino acid word usage can be captured in a quantitative statistic derived from the ~Shannon-Weaver entropy formulation. The log scale on the y-axis is indicative of the wide differences that exist among these genomes in terms of how amino acid ‘motifs’ are utilized within a whole genome. The red reference line represents an environmental genome ‘community’ from a hydrothermal vent sample.
<html><img src="01/AAcomplexity.png" style="height:300px"></html>

All word patterns do not contribute evenly to the information complexity of the protein phenotype: [[Entropy Movie|01/Entropy.mov]]

!
<[[BACK|Complexity08]]|[[MAIN|Complexity00]]|[[NEXT|Complexity10]]>
!!!
!Bioinformatics = Information Extraction/Expansion

//Nicotania benthamiana//
<html><img src="01/Niben/Niben_plant.jpg" style="height:200px"></html>

Nucleotide FASTA file of unique, nonredundant, protein genes: @@4.8 MB@@
|{{{-rw-r--r--  1 agm  staff   4.8M May 16  2012 Niben-SGNv1-cd95.fnt}}}|

Analysis of nucleotide and amino acid motif usage patterns: @@223 MB in 23 files@@
{{{
-r--r--r--  1 agm  staff   545B May 16  2012 Niben-SGNv1-01.txt
-r--r--r--  1 agm  staff    23K May 16  2012 Niben-SGNv1-02.txt
-r--r--r--  1 agm  staff   411K May 16  2012 Niben-SGNv1-03.txt
-r--r--r--  1 agm  staff   1.8K May 16  2012 Niben-SGNv1-03nt.txt
-r--r--r--  1 agm  staff   6.0M May 16  2012 Niben-SGNv1-04.txt
-r--r--r--  1 agm  staff    16M May 16  2012 Niben-SGNv1-05.txt
-r--r--r--  1 agm  staff   9.0M May 16  2012 Niben-SGNv1-06.txt
-r--r--r--  1 agm  staff   212K May 16  2012 Niben-SGNv1-06nt.txt
-r--r--r--  1 agm  staff   5.5M May 16  2012 Niben-SGNv1-07.txt
-r--r--r--  1 agm  staff   4.9M May 16  2012 Niben-SGNv1-08.txt
-r--r--r--  1 agm  staff   4.7M May 16  2012 Niben-SGNv1-09.txt
-r--r--r--  1 agm  staff   9.0M May 16  2012 Niben-SGNv1-09nt.txt
-r--r--r--  1 agm  staff   4.7M May 16  2012 Niben-SGNv1-10.txt
-r--r--r--  1 agm  staff   4.6M May 16  2012 Niben-SGNv1-11.txt
-r--r--r--  1 agm  staff   4.6M May 16  2012 Niben-SGNv1-12.txt
-r--r--r--  1 agm  staff    13M May 16  2012 Niben-SGNv1-12nt.txt
-r--r--r--  1 agm  staff   6.0M May 16  2012 Niben-SGNv1-15nt.txt
-r--r--r--  1 agm  staff   4.7M May 16  2012 Niben-SGNv1-18nt.txt
-r--r--r--  1 agm  staff   4.6M May 16  2012 Niben-SGNv1-21nt.txt
-r--r--r--  1 agm  staff   4.6M May 16  2012 Niben-SGNv1-24nt.txt
-r--r--r--  1 agm  staff    45M May 16  2012 Niben-SGNv1-ObsExp-nt.txt
-r--r--r--  1 agm  staff    64M May 16  2012 Niben-SGNv1-ObsExp.txt
-rw-r--r--  1 agm  staff   1.6M May 16  2012 Niben-SGNv1-cd95.faa
}}}

!
<[[BACK|Complexity09]]|[[MAIN|Complexity00]]|[[NEXT|Complexity11]]>
!!!
!@@What Can You Get Out of a 4.8 MB Text File?@@

!Motif Usage Information (N = 725,453)
<html><img src="01/Niben/Rplot-xmastree.jpg" style="height:500px"></html>
Comparison of Observed vs. Expected (null selection model) motif frequencies. Positive residuals = over-represented motifs. 

!
<[[BACK|Complexity10]]|[[MAIN|Complexity00]]|[[NEXT|Complexity12]]>
!!!
!@@What Can You Get Out of a 4.8 MB Text File?@@

!Gene GC Composition
<html><img src="01/Niben/Rplot-GCdist.jpg" style="height:300px"></html>

!Entropy Levels: Codon & Protein by Gene
<html><table><tr>
<td><img src="01/Niben/Rplot-Haa-vs-GC.jpg" style="height:400px"></td>
<td><img src="01/Niben/Rplot-Hcd-vs-GC.jpg" style="height:400px"></td>
</tr></table></html>

!
<[[BACK|Complexity11]]|[[MAIN|Complexity00]]|[[NEXT|Darwin's Dogs]]>
!!!
!@@What Can You Get Out of a 4.8 MB Text File?@@

!Entropy: AA vs. Codon
<html><img src="01/Niben/Rplot-Haa-vs-Hcd.jpg" style="height:500px"></html>

!Entropy: NT vs. GC
<html><img src="01/Niben/Rplot-Hnt-vs-GC.jpg" style="height:500px"></html>


!
# Group ENTRIES by a common tag, 'xxxx'.
# Create subtopic menu:
** rename as ''//xxxx//SubtopicMenu''
** enter the ENTRY titles into the table cells
# Create the viewtemplate
** rename as ''//xxxx//ViewTemplate''
** edit this line in the body, to this syntax using the 'xxxx' tag name:
{{{
<class='xxxx' macro='tiddler xxxxSubtopicMenu'>
}}}
!!SUBTOPIC PAGE CONTENT
{{{
<html>
<div style="color: rgb(100, 100, 150); font-family: Monaco;"><big><b>
TITLE OR HEADER OR DESCRIPTOR . . . .. 
</html>
1. [[x |1.11]]
2. [[y |1.12]]
3. [[z |1.13]]
!!
}}}
!!PLOT PAGE CONTENT
{{{
//header title//
<html><img src="00/xxxx.png" style="height:400px"></html>
[[BACK|XXTAGNAMEXX]]
!!!
}}}
!!
[[BACK To Syllabus|Syllabus]]

!Project Time Lines
* FEB:
** Organized Objectives
** Establish Statistical Hypothesis
** Identified Big Data Resources
** Coding for data observation collection
* MAR:
** Quantitative algorithm development
** Implementation
** Preliminary Data Check Point
** Can we test the guiding hypothesis?
* APR:
** Full Code
*** Development
*** Implement
** Analysis
*** Hypothesis Testing
*** Data Compilation/Polishing
* MAY:
** Manuscript Text
** Manuscript Analysis
** Manuscript Figures
** Manuscript Discussion/References

!
/***
|''Name:''|CryptoFunctionsPlugin|
|''Description:''|Support for cryptographic functions|
***/
//{{{
if(!version.extensions.CryptoFunctionsPlugin) {
version.extensions.CryptoFunctionsPlugin = {installed:true};

//--
//-- Crypto functions and associated conversion routines
//--

// Crypto "namespace"
function Crypto() {}

// Convert a string to an array of big-endian 32-bit words
Crypto.strToBe32s = function(str)
{
	var be = Array();
	var len = Math.floor(str.length/4);
	var i, j;
	for(i=0, j=0; i<len; i++, j+=4) {
		be[i] = ((str.charCodeAt(j)&0xff) << 24)|((str.charCodeAt(j+1)&0xff) << 16)|((str.charCodeAt(j+2)&0xff) << 8)|(str.charCodeAt(j+3)&0xff);
	}
	while (j<str.length) {
		be[j>>2] |= (str.charCodeAt(j)&0xff)<<(24-(j*8)%32);
		j++;
	}
	return be;
};

// Convert an array of big-endian 32-bit words to a string
Crypto.be32sToStr = function(be)
{
	var str = "";
	for(var i=0;i<be.length*32;i+=8)
		str += String.fromCharCode((be[i>>5]>>>(24-i%32)) & 0xff);
	return str;
};

// Convert an array of big-endian 32-bit words to a hex string
Crypto.be32sToHex = function(be)
{
	var hex = "0123456789ABCDEF";
	var str = "";
	for(var i=0;i<be.length*4;i++)
		str += hex.charAt((be[i>>2]>>((3-i%4)*8+4))&0xF) + hex.charAt((be[i>>2]>>((3-i%4)*8))&0xF);
	return str;
};

// Return, in hex, the SHA-1 hash of a string
Crypto.hexSha1Str = function(str)
{
	return Crypto.be32sToHex(Crypto.sha1Str(str));
};

// Return the SHA-1 hash of a string
Crypto.sha1Str = function(str)
{
	return Crypto.sha1(Crypto.strToBe32s(str),str.length);
};

// Calculate the SHA-1 hash of an array of blen bytes of big-endian 32-bit words
Crypto.sha1 = function(x,blen)
{
	// Add 32-bit integers, wrapping at 32 bits
	add32 = function(a,b)
	{
		var lsw = (a&0xFFFF)+(b&0xFFFF);
		var msw = (a>>16)+(b>>16)+(lsw>>16);
		return (msw<<16)|(lsw&0xFFFF);
	};
	// Add five 32-bit integers, wrapping at 32 bits
	add32x5 = function(a,b,c,d,e)
	{
		var lsw = (a&0xFFFF)+(b&0xFFFF)+(c&0xFFFF)+(d&0xFFFF)+(e&0xFFFF);
		var msw = (a>>16)+(b>>16)+(c>>16)+(d>>16)+(e>>16)+(lsw>>16);
		return (msw<<16)|(lsw&0xFFFF);
	};
	// Bitwise rotate left a 32-bit integer by 1 bit
	rol32 = function(n)
	{
		return (n>>>31)|(n<<1);
	};

	var len = blen*8;
	// Append padding so length in bits is 448 mod 512
	x[len>>5] |= 0x80 << (24-len%32);
	// Append length
	x[((len+64>>9)<<4)+15] = len;
	var w = Array(80);

	var k1 = 0x5A827999;
	var k2 = 0x6ED9EBA1;
	var k3 = 0x8F1BBCDC;
	var k4 = 0xCA62C1D6;

	var h0 = 0x67452301;
	var h1 = 0xEFCDAB89;
	var h2 = 0x98BADCFE;
	var h3 = 0x10325476;
	var h4 = 0xC3D2E1F0;

	for(var i=0;i<x.length;i+=16) {
		var j,t;
		var a = h0;
		var b = h1;
		var c = h2;
		var d = h3;
		var e = h4;
		for(j = 0;j<16;j++) {
			w[j] = x[i+j];
			t = add32x5(e,(a>>>27)|(a<<5),d^(b&(c^d)),w[j],k1);
			e=d; d=c; c=(b>>>2)|(b<<30); b=a; a = t;
		}
		for(j=16;j<20;j++) {
			w[j] = rol32(w[j-3]^w[j-8]^w[j-14]^w[j-16]);
			t = add32x5(e,(a>>>27)|(a<<5),d^(b&(c^d)),w[j],k1);
			e=d; d=c; c=(b>>>2)|(b<<30); b=a; a = t;
		}
		for(j=20;j<40;j++) {
			w[j] = rol32(w[j-3]^w[j-8]^w[j-14]^w[j-16]);
			t = add32x5(e,(a>>>27)|(a<<5),b^c^d,w[j],k2);
			e=d; d=c; c=(b>>>2)|(b<<30); b=a; a = t;
		}
		for(j=40;j<60;j++) {
			w[j] = rol32(w[j-3]^w[j-8]^w[j-14]^w[j-16]);
			t = add32x5(e,(a>>>27)|(a<<5),(b&c)|(d&(b|c)),w[j],k3);
			e=d; d=c; c=(b>>>2)|(b<<30); b=a; a = t;
		}
		for(j=60;j<80;j++) {
			w[j] = rol32(w[j-3]^w[j-8]^w[j-14]^w[j-16]);
			t = add32x5(e,(a>>>27)|(a<<5),b^c^d,w[j],k4);
			e=d; d=c; c=(b>>>2)|(b<<30); b=a; a = t;
		}

		h0 = add32(h0,a);
		h1 = add32(h1,b);
		h2 = add32(h2,c);
		h3 = add32(h3,d);
		h4 = add32(h4,e);
	}
	return Array(h0,h1,h2,h3,h4);
};


}
//}}}
[[<Bask to Lecture Main|Complexity00]]
!!!
!Darwin's Dogs

//A whinging pack of barking Science quotations . . . //

Android App now available on Google Play:
[[https://play.google.com/store/apps/details?id=com.graymarshbio.darwinquotes|https://play.google.com/store/apps/details?id=com.graymarshbio.darwinquotes]]

<html><table><tr>
<td><img src="01/DarwinsDogs/DD01.png" style="height:200px"></td>
<td><img src="01/DarwinsDogs/DD02.png" style="height:200px"></td>
</tr></table></html>
<html><img src="01/DarwinsDogs/DD03.png" style="height:300px"></html>
[[FrontPage]]
/***
|''Name:''|DeprecatedFunctionsPlugin|
|''Description:''|Support for deprecated functions removed from core|
***/
//{{{
if(!version.extensions.DeprecatedFunctionsPlugin) {
version.extensions.DeprecatedFunctionsPlugin = {installed:true};

//--
//-- Deprecated code
//--

// @Deprecated: Use createElementAndWikify and this.termRegExp instead
config.formatterHelpers.charFormatHelper = function(w)
{
	w.subWikify(createTiddlyElement(w.output,this.element),this.terminator);
};

// @Deprecated: Use enclosedTextHelper and this.lookaheadRegExp instead
config.formatterHelpers.monospacedByLineHelper = function(w)
{
	var lookaheadRegExp = new RegExp(this.lookahead,"mg");
	lookaheadRegExp.lastIndex = w.matchStart;
	var lookaheadMatch = lookaheadRegExp.exec(w.source);
	if(lookaheadMatch && lookaheadMatch.index == w.matchStart) {
		var text = lookaheadMatch[1];
		if(config.browser.isIE)
			text = text.replace(/\n/g,"\r");
		createTiddlyElement(w.output,"pre",null,null,text);
		w.nextMatch = lookaheadRegExp.lastIndex;
	}
};

// @Deprecated: Use <br> or <br /> instead of <<br>>
config.macros.br = {};
config.macros.br.handler = function(place)
{
	createTiddlyElement(place,"br");
};

// Find an entry in an array. Returns the array index or null
// @Deprecated: Use indexOf instead
Array.prototype.find = function(item)
{
	var i = this.indexOf(item);
	return i == -1 ? null : i;
};

// Load a tiddler from an HTML DIV. The caller should make sure to later call Tiddler.changed()
// @Deprecated: Use store.getLoader().internalizeTiddler instead
Tiddler.prototype.loadFromDiv = function(divRef,title)
{
	return store.getLoader().internalizeTiddler(store,this,title,divRef);
};

// Format the text for storage in an HTML DIV
// @Deprecated Use store.getSaver().externalizeTiddler instead.
Tiddler.prototype.saveToDiv = function()
{
	return store.getSaver().externalizeTiddler(store,this);
};

// @Deprecated: Use store.allTiddlersAsHtml() instead
function allTiddlersAsHtml()
{
	return store.allTiddlersAsHtml();
}

// @Deprecated: Use refreshPageTemplate instead
function applyPageTemplate(title)
{
	refreshPageTemplate(title);
}

// @Deprecated: Use story.displayTiddlers instead
function displayTiddlers(srcElement,titles,template,unused1,unused2,animate,unused3)
{
	story.displayTiddlers(srcElement,titles,template,animate);
}

// @Deprecated: Use story.displayTiddler instead
function displayTiddler(srcElement,title,template,unused1,unused2,animate,unused3)
{
	story.displayTiddler(srcElement,title,template,animate);
}

// @Deprecated: Use functions on right hand side directly instead
var createTiddlerPopup = Popup.create;
var scrollToTiddlerPopup = Popup.show;
var hideTiddlerPopup = Popup.remove;

// @Deprecated: Use right hand side directly instead
var regexpBackSlashEn = new RegExp("\\\\n","mg");
var regexpBackSlash = new RegExp("\\\\","mg");
var regexpBackSlashEss = new RegExp("\\\\s","mg");
var regexpNewLine = new RegExp("\n","mg");
var regexpCarriageReturn = new RegExp("\r","mg");

}
//}}}
/***
|!''Name:''|!''E''asily ''A''daptable ''S''ource ''E''ditor|
|''Description:''|this framework allows you to easily create commands that work on the current tiddler text selection in edit mode|
|''Version:''|0.1.0|
|''Date:''|13/01/2007|
|''Source:''|http://yann.perrin.googlepages.com/twkd.html#E.A.S.E|
|''Author:''|[[Yann Perrin|YannPerrin]]|
|''License:''|[[BSD open source license]]|
|''~CoreVersion:''|2.x|
|''Browser:''|Firefox 1.0.4+; Firefox 1.5; InternetExplorer 6.0|
***/
////Messages Definition
//{{{
config.messages.Ease = {
noselection:"nothing selected",
asktitle:"enter the new tiddler title",
exists:" already exists, please enter another title",
askForTagsLabel:"enter the new tiddler tags",
tiddlercreated:" tiddler created"
}
//}}}
////
//{{{
if (!window.TWkd) window.TWkd={context:{}};
if (!TWkd.Ease)
 TWkd.Ease = function (text,tooltip){
 this.text = text;
 this.tooltip = tooltip;
 this.modes = [];
 this.addMode = function(modeDefinition) {this.modes.push(modeDefinition);};
 this.handler = function(event,src,title) {
 TWkd.context.command = this;
 TWkd.context.selection=this.getSelection(title);
 if (this.modes.length==1) {
 this.modes[0].operation();
 }
 else {
 var popup = Popup.create(src);
 if(popup) {
 for (var i=0; i<this.modes.length; i++) {
 createTiddlyButton(createTiddlyElement(popup,"li"), this.modes[i].name, this.modes[i].tooltip, this.OperateFromButton, null, 'id'+i, null);
 }
 Popup.show(popup,false);
 event.cancelBubble = true;
 if (event.stopPropagation) event.stopPropagation();
 return false;
 }
 }
 };
 };

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

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

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

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

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

if (!TWkd.Mode)
 TWkd.Mode = function (name,tooltip,ask,operation) {
 this.name = name;
 this.tooltip = tooltip;
 this.ask = ask;
 this.operation = operation;
 };
//}}}
<div class="toolbar" macro="toolbar +saveTiddler closeOthers -cancelTiddler deleteTiddler"></div>
<div class="title" macro="view title"></div>
<div class="editLabel">Title</div><div class="editor" macro="edit title"></div>
<div class="editLabel">Tags</div><div class="editor" macro="edit tags"></div>
<div class="editorFooter"><span macro="message views.editor.tagPrompt"></span><span macro="tagChooser"></span></div>
<div macro='hideWhen ((tiddler.tags.contains("Contacts"))||(tiddler.title=="New Contact"))'>[[EditToolbar]]<div class='editor' macro='edit text'></div></div>
<div macro='showWhen ((tiddler.tags.contains("Contacts"))||(tiddler.title=="New Contact"))'><div class='editor'>
<table width='100%'>
<tr><th>Name</th><td><span macro='edit ContactFirstName'></span><span macro='edit ContactLastName'></span></td><td rowspan='4' width='50%' macro='edit text'></td></tr>
<tr><th>Adress</th><td><span macro='edit ContactStreetNumber'></span><span macro='edit ContactStreetName'></span><span macro='edit ContactZipCode'></span><span macro='edit ContactCity'></span></td></tr>
<tr><th>Phone</th><td><span macro='edit ContactPhone'></span></td></tr>
<tr><th>Email</th><td><span macro='edit ContactMail'><span></td></tr>
</table>
</div></div>
<div macro='toolbar Format Greek Hebrew Indent Notes Color Highlighting Tables'></div>
[[< Back to Resources|Resource Index]]
!~Mark-Up Script Editors:
!!!1. Java Edit
''jEdit'' is a feature-rich programmer's text editor built on Java that will run on all computers with JRE (java runtime environment). To download, install, and set up jEdit as quickly and painlessly as possible, go to the [[Quick Start page | http://www.jedit.org/index.php?page=quickstart]].
<html><img src="00/jedit.png" style="height:300px"></html>

!!!2. Crimson Editor
''CE'' is a syntax mark-up editor for MS Windows. Folder navigation is pretty easy using this tool. It can be setup as a pass-through interface to the command terminal so running and editing scripts can all be done in one GUI. To download and install got to [[Crimson Editor | http://www.crimsoneditor.com/]].
<html><img src="00/crimsonedit.png" style="height:300px"></html>

!!!3. Komodo
''KOMODO EDIT'' is a feature code editor from Active State. They sell a high-octane version of the editor Komodo-IDE which is geared to professional coders. The freeware version Komodo-Editor still has more features than you will ever probably require.  To download and install got to [[Komodo | http://www.activestate.com/Products/]], and select ''Komodo-Edit'', not ''Komodo-IDE''.
<html><img src="00/komodo.png" style="height:300px"></html>

!!!4. Vim
Vim is a highly configurable text editor built to enable efficient text editing. It is an improved version of the vi editor distributed with most UNIX systems. Vim is often called a "programmer's editor," and so useful for programming that many consider it an entire IDE. It's not just for programmers, though. Vim is perfect for all kinds of text editing, from composing email to editing configuration files. Vim can be configured to work in a very simple (Notepad-like) way, called evim or Easy Vim.
[[VIM download|http://www.vim.org/index.php]]
!
[[<Back to Index|BoneYard]]
!~Shannon-Weaver Entropy Calculation

{{{
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
sub Hentropy
{	print "   Entropy calculation . . . \n";
	my @AAx = qw | A C D E F G H I K L M N P Q R S T V W Y |;
	my $GenDict = $_[0];
	foreach my $id (keys %{$GenDict})
	{	# 1. Calculate Haa . . . . . . .
		my $haa = 0;
		foreach my $aa (@AAx)
		{	my $pi = ${$GenDict}{$id}{'AAfreq'}{'p'.$aa};
			if ($pi > 0)
			{	$haa += -1 * ($pi * log($pi)); }
		}
		${$GenDict}{$id}{'Haa'} = &RoundOff(10**$haa, 2);
		# &DUMP(${$GenDict}{$id}{'Haa'});
		
		# 2. Calculate Hcd . . . . . . .
		my $hcd = 0;
		foreach my $codon (keys %CodonTable)
		{	my $pi = ${$GenDict}{$id}{'CDfreq'}{'n'.$codon};
			if ($pi > 0)
			{	$hcd += -1 * ($pi * log($pi)); }
		}
		${$GenDict}{$id}{'Hcd'} = &RoundOff(10**$hcd, 2);
		# &DUMP(${$GenDict}{$id}{'Hcd'});
	}
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
}}}
[[<Back to MAIN|Lecture Index]] | [[Next>|ShakespearesMonkeys]]
!Entropy

The field of bioinformatics is more than just quantitative derivitization of existing biological sequence data. There is a direct experimental component to it as well that uses computational power and statistics to describe biological processes.

''Recombinometrics'' is a branch of statistical mathematics that essentially attempts to describe what components of a biological system appear by random chance vs. those that appear by non-random selective processes. 

We are going to introduce recombinometrics only so far as we can talk about ENTROPY and how one measures or obtains the entropy value of a biological sequence. 

!
[[<Back to Lecture|REGEX-03]]
!FASTA Motif Counter

{{{
#!/usr/bin/perl
use strict;

# - - - - - H E A D E R - - - - - - - - - - - - - - - - -
# GOAL: Analyze the GC content and 'CG' motif distribution 
# XYZ-2012



# - - - - - U S E R    V A R I A B L E S - - - - - - - -
my $path     = "00-Data";
my $infile   = "Acidianus_hospitalis_W1_uid66875.ffn";
my $outfile  = "Genome-OutData.txt";
my $htmlfile = "ResultPlots.html";

# - - - - - G L O B A L  V A R I A B L E S  - - - - - -
my %Genes;
my %RGenes;

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# - - - - - M A I N - - - - - - - - - - - - - - - - - - - -
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
print "\n\nWorking for the man every night and day . . .\n\n";

#----------------------------------------------
my $pathfile = $path . "/" . $infile;
&FASTAread($pathfile);
#----------------------------------------------

# 0 Generate Random Control gene sequences . . . . . .
foreach my $id (keys %Genes)
{
	$RGenes{$id}{'head'} = $id;
	$RGenes{$id}{'seq'}  = FYshuffle($Genes{$id}{'seq'});
}


# 1 = count nucleotides and calc %GC. . . . . . . . 
foreach my $id (keys %Genes)
{	my @nts = split(//,$Genes{$id}{'seq'});
	foreach my $n (@nts)
	{	$Genes{$id}{$n} += 1; }
	$Genes{$id}{'%GC'} = ($Genes{$id}{'G'} + $Genes{$id}{'C'})/$Genes{$id}{'len'};
}


# 2 = count CG motifs . . . .
foreach my $id (keys %Genes)
{	my $cgcount = 0;
	my $position = index($Genes{$id}{'seq'}, 'CG', 0);
	while($position > -1)
	{	$cgcount += 1;
		$position = index($Genes{$id}{'seq'}, 'CG', $position+2);
	}
	$Genes{$id}{'CpG'} = $cgcount/$Genes{$id}{'len'};
}

# 2.5 = count GC motifs . . . . . .
foreach my $id (keys %Genes)
{	my $gccount = 0;
	my $seq = $Genes{$id}{'seq'};	
	while($seq =~ s/^.+?GC//)
	{	$gccount += 1; }	
	$Genes{$id}{'GpC'} = $gccount/$Genes{$id}{'len'};
}


# 3. Output fancy analysis
open(OUT, ">$outfile");
print OUT "ID\tSIZE\tGC\tCpG\tGpC\n";
foreach my $id (keys %Genes)
{	print OUT "$id\t$Genes{$id}{'len'}\t$Genes{$id}{'%GC'}\t$Genes{$id}{'CpG'}\t$Genes{$id}{'GpC'}\n";  }
close(OUT);

print "\n\n\n* * * *   D O N E   * * * * \n\n\n";
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# - - - - - S U B R O U T I N E S - - - - - - - - - - -
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
sub FASTAread
{	
	# 1. Load FIlE . . . . . . . . . .
	$/=">";
	my $xfile = $_[0];
	open(IN, "<$xfile") or die "\n\nNADA $xfile you FOOL!!!\n\n";
	my @DATA = <IN>; close(IN); shift(@DATA);
	
	# 2. Parse sequence data . . . . . . . . . . . . .
	my $unid = 10000;
	foreach my $entry (@DATA)
	{	my @data = split('\n', $entry);
		my $head = $data[0];
		my $seq = '';
		foreach my $i (1..$#data)
		{	$seq .= $data[$i];  }
		$seq =~ s/>//;
		$Genes{$unid}{'head'} = $head;
		$Genes{$unid}{'seq'}  = uc($seq);
		$Genes{$unid}{'len'}  = length($seq);
		$unid += 1;
	}
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
}}}
[[<Back to Index|BoneYard]]
!INPUT FASTA FILE

!!!CALL: 
{{{
FASTAread($pathfile);
}}}
. . . where //$pathfile// is a qualified variable name that contains the folder path (from the current working directory) and the input filename.

!!!DEPENDENCY:  
{{{
my %Genes;
}}}
 . . . . must be declared as a global variable.

!!!SUB
{{{
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
sub FASTAread
{	print "   Reading file . . . \n";
	# 1. Load FIlE . . . . . . . . . .
	$/=">";                                     # set input break string
	my $infile = $_[0];
	open(IN, "<$infile") or die "\n\nNADA $infile you FOOL!!!\n\n";
	my @DATA = <IN>; close(IN); shift(@DATA);	
	# 2. Parse sequence data . . . . . . . . . . . . .
	my $unid = 10000;                           # string to generate unique ids
	foreach my $entry (@DATA)
	{	my @data = split('\n', $entry);
		my $seq = '';
		foreach my $i (1..$#data)
		{	$seq .= $data[$i];  }
		$seq =~ s/>//;
		unless ($seq =~ /[RWYSKMBDHVN\.\-]/i)          # filter for non ATGC base pairs
		{	$Genes{$unid}{'HEAD'}    = $data[0];       # store header
			$Genes{$unid}{'ntseq'}   = uc($seq);       # store sequence
			$Genes{$unid}{'SIZE'}    = length($seq);   # store length
			$unid += 1;
		}
	}
	$/="\n";
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
}}}

!
[[<Back|BoneYard]]
!FASTApipe

Script to link all the basic bioinformatic characterization scripts together into one pipe.

{{{
#!/usr/bin/perl
use strict;

# - - - - - H E A D E R - - - - - - - - - - - - - - - - -
# MAIN FASTA PIPE
# Compile general metrics on the annotated ORFs in a microbial genome.
# Vars for each genome: header, ntseq, aaseq, size, GC, 
# MAST698-2013

# - - - - - U S E R    V A R I A B L E S - - - - - - - -
my $genome = "Acaryochloris_marina_MBIC11017_uid58167-cd90.fnt";
my $folder = "00-Data";

# - - - - - G L O B A L  V A R I A B L E S  - - - - - -
my %Genes;                                  # Dicitionary with all profile stats
my %CodonTable;                             # translation table

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# - - - - - M A I N - - - - - - - - - - - - - - - - - - - -
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

print "\n\nRunning Profile Calcs on genome:\n      $genome\n\n";

# 1. Run the profile calculations . . . . . . . . . . .
&FASTAread($folder."/".$genome);   # Defines head, ntseq, size
&GCcalc(\%Genes);                  # Defines GC
&TranslateFasta(\%Genes);          # Defines aaseq                                > (requires LoadCodonTable)
&AAfreq(\%Genes);                  # Defines AAfreq.pX where X = each amino acid  > (requires TranslateFasta)
&AAmass(\%Genes);                  # Defines AAmass                               > (requires AAfreq)
&AAnitrogen(\%Genes);		   # Defines protein sidechain nitrogen req       > (requires AAfreq)
&CodonFreq(\%Genes);               # Defines CDfreq.pXXX where XXX = each codon   > (requires LoadCodonTable)
&CAI(\%Genes);                     # Defines CAI  = codon adaptation index        > (requires CodonFreq)
&Hentropy(\%Genes);                # Defines Haa, Hcd                             > (requires AAfreq, CodonFreq)
&IsoElectricPoint(\%Genes);        # Defines IEP                                  > (requires AAfreq)
&SKEW(\%Genes);                    # Defines SKaa, SKcd

# 2. Output results . . . . . . .
my @ColID = qw | SIZE GC AAmass AAnitrogen CAI Haa Hcd IEP SKaa SKcd |;
my @format = qw | STD AA CD |;       # < options: STD, AA, CD;  each results in a separate output file
foreach my $outform (@format)
{	&DataTable(\%Genes, $genome, \@ColID, $outform); }   # Inputs to DataTable: Dict, genome, cols, format


print "\n\n*  *  *  *  *    D  O  N  E     *  *  *  * \n\n";

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
# - - - - - S U B R O U T I N E S - - - - - - - - - - - - - - - - - - - - - - -
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
sub FASTAread
{	print "   Reading file . . . \n";
	# 1. Load FIlE . . . . . . . . . .
	$/=">";                                     # set input break string
	my $infile = $_[0];
	open(IN, "<$infile") or die "\n\nNADA $infile you FOOL!!!\n\n";
	my @DATA = <IN>; close(IN); shift(@DATA);	
	# 2. Parse sequence data . . . . . . . . . . . . .
	my $unid = 10000;                           # string to generate unique ids
	foreach my $entry (@DATA)
	{	my @data = split('\n', $entry);
		my $seq = '';
		foreach my $i (1..$#data)
		{	$seq .= $data[$i];  }
		$seq =~ s/>//;
		unless ($seq =~ /[RWYSKMBDHVN\.\-]/i)          # filter for non ATGC base pairs
		{	$Genes{$unid}{'HEAD'}    = $data[0];       # store header
			$Genes{$unid}{'ntseq'}   = uc($seq);       # store sequence
			$Genes{$unid}{'SIZE'}    = length($seq);   # store length
			$unid += 1;
		}
	}
	$/="\n";
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
sub TranslateFasta
{	print "   Amino Acid translation . . . \n";
	&LoadCodonTable();
	my $GenDict = $_[0];
	foreach my $id (keys %{$GenDict})
	{	my $prot = '';
		my $gene = ${$GenDict}{$id}{'ntseq'};
		while ($gene =~ s/^(...)//)
		{	$prot .= $CodonTable{$1}; }
		$prot =~ s/\*$//;   # drop terminal stop codon
		${$GenDict}{$id}{'aaseq'} = $prot;
	}
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
sub GCcalc
{	print "   Counting GCs . . . \n";
	my $GenDict = $_[0];
	foreach my $id (keys %{$GenDict})
	{	my $count = 0;
		$count = ${$GenDict}{$id}{'ntseq'} =~ tr/GC/GC/;
		$count = $count/${$GenDict}{$id}{'SIZE'};
		${$GenDict}{$id}{'GC'} = &RoundOff($count,3);
	}
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
sub CodonFreq
{	print "   Codon frequencies . . . \n";
	my $GenDict = $_[0];
	foreach my $id (keys %{$GenDict})
	{	my $seq = ${$GenDict}{$id}{'ntseq'};
		my $N = length($seq)/3;
		if ($N < 1) { print "\n\nError in aaseq length; see sub &CodonFreq\n\n"; die; }
		while ($seq =~ s/^(...)//) 
		{	${$GenDict}{$id}{'CDfreq'}{'n'.$1} += 1/$N;  }
		foreach my $codon (keys %CodonTable)
		{	${$GenDict}{$id}{'CDfreq'}{'n'.$codon} = &RoundOff(${$GenDict}{$id}{'CDfreq'}{'n'.$codon}, 4); }
	}
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
sub AAfreq
{	print "   Amino Acid frequencies . . . \n";
	my @AAx = qw | A C D E F G H I K L M N P Q R S T V W Y |;
	my $GenDict = $_[0];
	foreach my $id (keys %{$GenDict})
	{	my $seq = ${$GenDict}{$id}{'aaseq'};
		my $N = length($seq);
		if ($N < 1) { print "\n\nError in aaseq length; see sub &AAfreq\n\n"; die; }
		while ($seq =~ s/^(.)//) 
		{	${$GenDict}{$id}{'AAfreq'}{'p'.$1} += 1/$N;  }
		foreach my $aa (@AAx)
		{	${$GenDict}{$id}{'AAfreq'}{'p'.$aa} = &RoundOff(${$GenDict}{$id}{'AAfreq'}{'p'.$aa}, 4); }
	}
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
sub AAmass
{	print "   Protein mass . . . \n";
	my @AAx = qw | A C D E F G H I K L M N P Q R S T V W Y |;
	my %mass = qw | A	71.0788 R	156.1875	N	114.1038	D	115.0886	C	103.1388	E	129.1155	Q	128.1307	G	57.0519	H	137.1411	I	113.1594	L	113.1594	K	128.1741	M	131.1926	F	147.1766	P	97.1167	S	87.0782	T	101.1051	W	186.2132	Y	163.1760	V	99.1326 |;
	my $GenDict = $_[0];
	foreach my $id (keys %{$GenDict})
	{	my $N = length(${$GenDict}{$id}{'aaseq'});
		${$GenDict}{$id}{'AAmass'} = 0;
		foreach my $aa (@AAx)
		{	${$GenDict}{$id}{'AAmass'} += &RoundOff(0.001 * ${$GenDict}{$id}{'AAfreq'}{'p'.$aa} * $N * $mass{$aa}, 2); }
		#&DUMP(${$GenDict}{$id}{'AAmass'});
	}
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
sub AAnitrogen
{	print "   Protein nitrogen requirement . . . \n";
	my @AAx = qw | A C D E F G H I K L M N P Q R S T V W Y |;
	my %nitrog = qw | R	 3	N	1	Q	1	H	2	K	1	P	1	W	1  |;
	my $GenDict = $_[0];
	foreach my $id (keys %{$GenDict})
	{	my $W = length(${$GenDict}{$id}{'aaseq'});
		${$GenDict}{$id}{'AAnitrogen'} = 0;
		foreach my $aa (@AAx)
		{	${$GenDict}{$id}{'AAnitrogen'} += &RoundOff(0.001 * ${$GenDict}{$id}{'AAfreq'}{'p'.$aa} * $W * $nitrog{$aa}, 2); }
		#&DUMP(${$GenDict}{$id}{'AAnitrogen'});
	}
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
sub CAI
{	print "   Codon Adaptation Index . . . \n";
	my $GenDict = $_[0];
	foreach my $id (keys %{$GenDict})
	{	# 1. Find maxfj = max(fi) for any group of synonymous codons (i.e., codons with the same AA)
		my %maxfj;
		my @AAx = qw | A C D E F G H I K L M N P Q R S T V W Y |;
		foreach my $aa (@AAx)                                                     # < Look at each AA . . . . 
		{	my $max = -1;                                                         # < Initialize with min value . . 
			$maxfj{$aa} = 0;                                                      # < Initialize with min value . . 
			foreach my $codon (keys %CodonTable)                                  # < Look at each Codon . . . 
			{	if ($CodonTable{$codon} == $aa)                                   # < When current codon = current AA . . . 
				{	if (${$GenDict}{$id}{'CDfreq'}{'n'.$codon} > $max)            # < Check if codon freq is max . . .
					{	$maxfj{$aa} = ${$GenDict}{$id}{'CDfreq'}{'n'.$codon}; }
				}
			}
		}
		# 2. CAI Calculation . . . . . . .
		my $seq = ${$GenDict}{$id}{'ntseq'};
		my $N = length(${$GenDict}{$id}{'aaseq'});  # total codons
		my $cai = 0;
		while($seq =~ s/^(...)//)
		{	my $fi = ${$GenDict}{$id}{'CDfreq'}{'n'.$1};
			my $aa = $CodonTable{$1};
			if ($maxfj{$aa} > 0 && $fi > 0)
			{	$cai += log($fi/$maxfj{$aa}); }
		}
		$cai = exp($cai/$N);
		${$GenDict}{$id}{'CAI'} = &RoundOff($cai, 3);
		#&DUMP(${$GenDict}{$id}{'CAI'}); 
	}
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
sub Hentropy
{	print "   Entropy calculation . . . \n";
	my @AAx = qw | A C D E F G H I K L M N P Q R S T V W Y |;
	my $GenDict = $_[0];
	foreach my $id (keys %{$GenDict})
	{	# 1. Calculate Haa . . . . . . .
		my $haa = 0;
		foreach my $aa (@AAx)
		{	my $pi = ${$GenDict}{$id}{'AAfreq'}{'p'.$aa};
			if ($pi > 0)
			{	$haa += -1 * ($pi * log($pi)); }
		}
		${$GenDict}{$id}{'Haa'} = &RoundOff(10**$haa, 2);
		# &DUMP(${$GenDict}{$id}{'Haa'});
		
		# 2. Calculate Hcd . . . . . . .
		my $hcd = 0;
		foreach my $codon (keys %CodonTable)
		{	my $pi = ${$GenDict}{$id}{'CDfreq'}{'n'.$codon};
			if ($pi > 0)
			{	$hcd += -1 * ($pi * log($pi)); }
		}
		${$GenDict}{$id}{'Hcd'} = &RoundOff(10**$hcd, 2);
		# &DUMP(${$GenDict}{$id}{'Hcd'});
	}
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
sub IsoElectricPoint
{	print "   Protein isoelectric point . . . \n";
	my $GenDict = $_[0];
	foreach my $id (keys %{$GenDict})
	{	my $N      = length(${$GenDict}{$id}{'aaseq'});
		my $pH     = 6.5;           # starting point pI = 6.5 - theoretically it should be 7, but
		my $pHlow  = 0.0;
		my $pHhigh = 14.0;  
		my $std    = 0.01;          # [pI = pH ± std]
		my $temp   = 0.0;
		(my $QN1, my $QN2, my $QN3, my $QN4, my $QN5, my $QP1, my $QP2, my $QP3, my $QP4, my $NQ) = (0,0,0,0,0,0,0,0,0,0);
		my $SOLVED = 0;
		my $looper = 0;
		while($SOLVED == 0)
		{	# 1. Calculate charge balance coefficient $NQ . . . . . .   
			$QN1 = -1/(1+10**(3.65-$pH));                                        
			$QN2 = (-1 * ${$GenDict}{$id}{'AAfreq'}{'pD'} * $N)/(1+10**(3.90-$pH));           
			$QN3 = (-1 * ${$GenDict}{$id}{'AAfreq'}{'pE'} * $N)/(1+10**(4.07-$pH));           
			$QN4 = (-1 * ${$GenDict}{$id}{'AAfreq'}{'pC'} * $N)/(1+10**(8.18-$pH));           
			$QN5 = (-1 * ${$GenDict}{$id}{'AAfreq'}{'pY'} * $N)/(1+10**(10.46-$pH));        
			$QP1 = (+1 * ${$GenDict}{$id}{'AAfreq'}{'pH'} * $N)/(1+10**($pH-6.040));            
			$QP2 = 1/(1+10**($pH-8.2));                
			$QP3 = (+1 * ${$GenDict}{$id}{'AAfreq'}{'pK'} * $N)/(1+10**($pH-10.54));           
			$QP4 = (+1 * ${$GenDict}{$id}{'AAfreq'}{'pR'} * $N)/(1+10**($pH-12.48));            
			$NQ = $QN1+$QN2+$QN3+$QN4+$QN5+$QP1+$QP2+$QP3+$QP4;
			
			# 2. Iteratively adjust pH value . . . . . . . .  .
			if ($NQ < 0)              # out of range, thus the new pH value must be smaller    
			{  $temp = $pH;
				$pH = $pH-(($pH-$pHlow)/2);
				$pHhigh = $temp;
			}
			else                      # pH value is too low, needs to be increased
			{   $temp = $pH;
				$pH = $pH + (($pHhigh-$pH)/2);
				$pHlow = $temp;
			}
			
			# 3. Check/Monitor progress . . . . . . . . . . . . . . . .  .. . .. 
			# Error, so stop trying to calculate, exit for loop
			if ($pH >= 14)
			{	${$GenDict}{$id}{'IEP'} = 'NA';
				$SOLVED = -1;
			} 
			# Iterative Solution: terminal condition, isoelectric point is within the given precision $std
			if (($pH-$pHlow < $std) && ($pHhigh-$pH < $std)) 
			{	${$GenDict}{$id}{'IEP'} = &RoundOff($pH, 3);
				$SOLVED = 1;
			}
			# Deadman switch to stop infinite loop . . . .
			if ($looper == 1000)
			{	${$GenDict}{$id}{'IEP'} = 'NA';
				$SOLVED = -1;
			}
			else
			{	$looper += 1; }
		} # end while loop . . . . . . . 
		# &DUMP(${$GenDict}{$id}{'IEP'});
	} # end foreach gene loop . . . . . . . . .. .  . .
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
sub SKEW                           # Requires the SKEWcalc subroutines . . 
{	print "   Skew calculation . . . \n";
	my @AAx = qw | A C D E F G H I K L M N P Q R S T V W Y |;
	my $GenDict = $_[0];
	foreach my $id (keys %{$GenDict})
	{	# 1. Calculate SKaa . . . . . . .
		my @pAA;
		foreach my $aa (@AAx)
		{	push(@pAA, ${$GenDict}{$id}{'AAfreq'}{'p'.$aa}); }
		${$GenDict}{$id}{'SKaa'} = &SKEWcalc(\@pAA);
		# &DUMP(${$GenDict}{$id}{'SKaa'});
		
		# 2. Calculate SKcd . . . . . . .
		my @nCD;
		foreach my $codon (keys %CodonTable)
		{	push(@nCD,${$GenDict}{$id}{'CDfreq'}{'n'.$codon}); }
		${$GenDict}{$id}{'SKcd'} = &SKEWcalc(\@nCD);
		# &DUMP(${$GenDict}{$id}{'SKcd'});
	}
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
sub DataTable
{	my $GenDict = $_[0];
	my $outfile = $_[1];
	my $colid   = $_[2];
	my $job     = $_[3];
	my @AAx = qw | A C D E F G H I K L M N P Q R S T V W Y |;
	print "   Data dump to file . . . $job\n";
	
	# 1. Set the output file name . . . . . . . . . 
	if ($job eq 'STD')
	{	$outfile =~ s/\.fnt/-data.txt/; }
	elsif ($job eq 'AA')
	{	$outfile =~ s/\.fnt/-AAfreq.txt/; }
	elsif ($job eq 'CD')
	{	$outfile =~ s/\.fnt/-CDfreq.txt/; }
	else
	{	print "\n\nFAIL: no file output!!\n&DataTable() takes 4 arguments: Dict, genome, colids, dataset\n\n"; }
	
	# 2. Print out the col headers for this data table . . . . . . . . . . 
	open(OUT,">$outfile");
	print OUT "ID";                       # first col header on line
	for my $var (@{$colid})              # now loop through each remaining col header
	{	print OUT "\t$var"; }    # need to print a tab-char '\t' and then new header
# What is the data output format?
	if ($job eq 'AA')
	{	foreach my $aa (@AAx) {	print OUT "\tp$aa"; } }
	elsif ($job eq 'CD')
	{	foreach my $codon (keys %CodonTable) {	print OUT "\tn$codon"; } }	
	print OUT "\n";                          # once complete, need to end the header line with a line-feed \n
	
	# 3. Now print the data/gene rows . . . . . . . . . 
	foreach my $id (keys %{$GenDict})
	{	print OUT "$id";
		foreach my $var (@{$colid})
		{	print OUT "\t${$GenDict}{$id}{$var}"; }
	# What is the data output format?
		if ($job eq 'AA')
		{	foreach my $aa (@AAx) {	print OUT "\t${$GenDict}{$id}{'AAfreq'}{'p'.$aa}"; } }
		elsif ($job eq 'CD')
		{	foreach my $codon (keys %CodonTable) {	print OUT "\t${$GenDict}{$id}{'CDfreq'}{'n'.$codon}"; } }	
		print OUT "\n";       # once row is complete, need to end the gene line with a line-feed \n		
	}
	close(OUT);
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
sub SKEWcalc                        # Requires the MEAN & MEDIAN subroutines . . 
{	my $array = $_[0];
	my $mean = &MEAN(\@{$array});
	my $median = &MEDIAN(\@{$array});
	# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
	my $skew = &RoundOff(200*($median - $mean)/($mean + $median), 3);
	# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
	return $skew;
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
sub MEAN                          # called by SKEW . . . . . . . . . . . . . . .
{	my $array = $_[0];
	my $N = scalar(@{$array});
	my $sum = 0;
	foreach my $data (@{$array})
	{	$sum += $data; }
	return &RoundOff($sum/$N, 4);
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
sub MEDIAN                        # called by SKEW . . . . . . . . . . . . . . .
{	my $array = $_[0];
	my $N = scalar(@{$array});
	my @SORT = sort{$a<=>$b}(@{$array});
	my $mid = int($N/2);
	return &RoundOff($SORT[$mid], 4);
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
sub LoadCodonTable
{	my @bases = ('T', 'C', 'A', 'G');
	my @aa = split(//,"FFLLSSSSYY**CC*WLLLLPPPPHHQQRRRRIIIMTTTTNNKKSSRRVVVVAAAADDEEGGGG");
	foreach my $a (@bases)
	{	foreach my $b (@bases)
		{	foreach my $c (@bases)
			{	$CodonTable{$a.$b.$c}=shift(@aa); }
		}
	}
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
sub LOG10
{	my $n = shift;
    return log($n)/log(10);
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
sub RoundOff
{	my $num = shift(@_);
	my $decimals = shift(@_);
	my $roundnum = int(($num * 10**$decimals) + 0.5)/(10**$decimals);
	return $roundnum;
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
sub DUMP
{	my $var = $_[0];
	print "\n\n>> $var << \n\n";
	die; 
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
# - - - - - EOF - - - - - - - - - - - - - - - - - - - - - -

}}}
[[< Back|FastaRead-05]]|[[Next>|FastaAnalyze-02]]
!FASTA Analyze:
The task of reading a FASTA file can now be assigned to a simply subroutine function: [[(see FASTA read subroutine here)|FASTA read subroutine]]. The sequence data for individual genes is loaded into a dictionary structure named @@{{{%Genes}}}@@ that provides flexibility for adding more variables during downstream processing/analyses.

In this exercise, we will compile data for gene size (bp), gene G+C content, and gene 'CG' motif frequency.

!!!Gene Size:
This information is obtained in the FASTA read subroutine loop simply using PERL's //length// function:
{{{
$Genes{$unid}{'len'}  = length($seq);   # store length
}}}

!!!G+C Content:
We use the nucleotide code letters to represent variable names in the %Genes dictionary that correspond to integer counters for the abundance of each nucleotide in the sequence. Thus, when iterating through the characters in the @nts array, when an "A" is found, the $Genes{$id}{'A'} counter is incremented by 1 because $n will equal 'A'. 
{{{
# 1 = count nucleotides and calc %GC. . . . . . . . 
foreach my $id (keys %Genes)
{	my @nts = split(//,$Genes{$id}{'seq'});    # convert seq string to char array of nts
	foreach my $n (@nts)                       # iterate through the char array derived from seq
	{	$Genes{$id}{$n} += 1; }            # count +1 the presence of nt 'N'
	$Genes{$id}{'%GC'} = ($Genes{$id}{'G'} + $Genes{$id}{'C'})/$Genes{$id}{'len'};
}
}}}

!!!CG motifs
We use the PERL function @@{{{index}}}@@ to locate whether a search string (here 'CG') is present in a larger target string (here $Genes{$id}{'seq'}). It uses this syntax: {{{ index(target, search, start)}}}, where start indicates the position in the target string where PERL will begin looking for a match. If a match is found, the position of the match is returned (positive integer). If a match is not found, a '-1' is returned. We use this -1 default as a signal for determining whether or not we are done searching through the target string, adjusting //start position// after each successful find:
{{{
# 2 = count CG motifs . . . .
foreach my $id (keys %Genes)
{	my $cgcount = 0;
	my $position = index($Genes{$id}{'seq'}, 'CG', 0);
	while($position > -1)
	{	$cgcount += 1;
		$position = index($Genes{$id}{'seq'}, 'CG', $position+2);
	}
	$Genes{$id}{'CpG'} = $cgcount/$Genes{$id}{'len'};
}
}}}

!

[[< Back|FastaAnalyze-01]]|[[Next>|FastaAnalyze-03]]
!FASTA Analyze:
The dictionary data is now written to tab-delimited text file, "~Genome-OutData.txt"
{{{
# 3. Output analysis results
open(OUT, ">$outfile");
print OUT "ID\tSIZE\tGC\tCpG\n";
foreach my $id (keys %Genes)
{	print OUT "$id\t$Genes{$id}{'len'}\t$Genes{$id}{'%GC'}\t$Genes{$id}{'CpG'}\n";  }
close(OUT);
}}}

And the output file looks like this . . . . 
{{{
ID	SIZE	GC	                CpG
11412	864	0.344907407407407	0.025462962962963
11002	495	0.381818181818182	0.0202020202020202
10882	276	0.307971014492754	0.0036231884057971
10309	1389	0.406767458603312	0.0223182145428366
10122	1809	0.325041459369818	0.0149253731343284
12317	804	0.342039800995025	0.0161691542288557
 . . . . .
}}}


!
[[< Back|FastaAnalyze-02]]|[[Next>|FastaAnalyze-04]]
!R Script:
Now we can use an R script to analyze/plot the data in the text output file. 
Download this R script: [[02-PLOT-FastaSize-GC.R|01/02-PLOT-FastaSize-GC.R ]].

However, rather than working with R in an interactive session, we are going to use PERL to directly run the R script using the @@{{{system()}}}@@ function to send a command directly to the operating system. Here R stats will be loaded and then the 02 script file will be executed in full, generating 4 plot files:
{{{
#-------------------------------------------------------
# 4. Run R Analysis Script . . . . .
system('R --vanilla <02-PLOT-FastaSize-GC.R');
#-------------------------------------------------------
}}}

!!!Plots:
<html><table>
<tr>
<td><img src="02/PLOT-Fig1-SIZE.jpg" style="height:300px"></td>
<td><img src="02/PLOT-Fig2-GC.jpg" style="height:300px"></td>
</tr>
<tr>
<td><img src="02/PLOT-Fig3-SIZEvsGC.jpg" style="height:300px"></td>
<td><img src="02/PLOT-Fig4-GCvsCpG.jpg" style="height:300px"></td>
</tr>
</table></html>

!
[[< Back|FastaAnalyze-03]]|[[Next>|FastaAnalyze-05]]
!HTML Report:
But now we are going to finish the Fasta Analyze script by generating and HTML report file that will integrate the essential information and plots of our work. The html file itself is just a flat ascii text file with simple hypertext markup language code characters [[(see HTML Read Script)|HTMLread-01]]. We just use simple print statements to compose the file so that it looks like this:
{{{
<html>
<title>My Data Results</title>
<body>
 . . . . now we put what ever text, tables, plots (as embedded images) will be displayed . . . 
</body>
</html>
}}}

Here's how to embed an image file: {{{ <img src="00/xxxx.png" style="height:300px"> }}}

Here's how to make a table:
{{{
<table>
   <tr>
      <td> . . . info row1 col1 . . . . </td>
      <td> . . . info row1 col2 . . . . </td>
      <td> . . . info row1 col3 . . . . </td>
   </tr>
   <tr>
      <td> . . . info row2 col1 . . . . </td>
      <td> . . . info row2 col2 . . . . </td>
      <td> . . . info row2 col3 . . . . </td>
</table>
}}}

But in HTML, the white space is irrelevant for formatting, so we just run all the info together using sequential print statement:
{{{
# 5. Print HTML Report . . . . . . . . . . . . . . . . .  
open(OUT,">$htmlfile");
print OUT "<html>\n<title>Genome Profiles</title>\n<body>\n";
print OUT "Data for free-living microbial genomes were obtained from file <b>\"$infile\"</b>.";
print OUT "A parsing srcipt was used to extract the genome size and %GC content observations, and then \n";
print OUT "this information is presented below.<br><br>\n";
print OUT "Distribution profiles for Genome Size and %GC in the data set.<br>\n";
print OUT "<table><tr><td><img src=\"PLOT-Fig1-SIZE.jpg\" style=\"height:300px\"></td><td><img src=\"PLOT-Fig2-GC.jpg\" style=\"height:300px\"></td></tr></table><br>\n";
print OUT "<br><hr><br><b>Correlation SIZE vs. GC Content</b><br>\n";
print OUT "<img src=\"PLOT-Fig3-SIZEvsGC.jpg\" style=\"height:500px\"><br><hr>\n";
print OUT "<br><br><b>Correlation GC Content vs. CpG motifs</b><br>\n";
print OUT "<img src=\"PLOT-Fig4-GCvsCpG.jpg\" style=\"height:500px\"><br><hr><br>\n";
print OUT "</body>\n</html>\n";
close(OUT);
}}}


!
[[< Back|FastaAnalyze-04]]|[[Next: Working Script|FastaAnalyze-06]]
!FINAL HTML Report:

The final compilation of HTML file and plot files looks like this:
<html><img src="02/screenshot_64.png" style="height:500px"></html>

 . . . and they can be viewed here: [[Analysis Report HTML|02/ResultPlots.html]]
!
[[< Back|FastaAnalyze-05]]|
!FASTA Pipe:
Working script for opening a nucleotide FASTA file, calculating some bioinformatic metrics, writing that new data to a file, running an R script on the fly, generating a final HTML report that integrates information from the run.

{{{
#!/usr/bin/perl
use strict;

# - - - - - H E A D E R - - - - - - - - - - - - - - - - -
# GOAL: Analyze the GC content and 'CG' motif distribution in the genes 
#   of a microbial genome
#        1. Read FASTA
#        2. Calculate bioinfo metrics
#        3. Write new data file
#        4. Execute R script
#        5. Compile all results in HTML report file 
# MAST698-2013

# - - - - - U S E R    V A R I A B L E S - - - - - - - -
my $path     = "00-Data";
my $infile   = "Acidianus_hospitalis_W1_uid66875.ffn";
my $outfile  = "Genome-OutData.txt";
my $htmlfile = "ResultPlots.html";

# - - - - - G L O B A L  V A R I A B L E S  - - - - - -
my %Genes;

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# - - - - - M A I N - - - - - - - - - - - - - - - - - - - -
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
print "\n\nWorking for the man every night and day . . .\n\n";

#----------------------------------------------
my $pathfile = $path . "/" . $infile;
&FASTAread($pathfile);
#----------------------------------------------

# 1 = count nucleotides and calc %GC. . . . . . . . 
foreach my $id (keys %Genes)
{	my @nts = split(//,$Genes{$id}{'seq'});
	foreach my $n (@nts)
	{	$Genes{$id}{$n} += 1; }
	#if ($Genes{$id}{'len'} == 0){ print "ID=",$id,"; H=",$Genes{$id}{'head'},"; L=",$Genes{$id}{'len'},"\n"; die; }
	$Genes{$id}{'%GC'} = ($Genes{$id}{'G'} + $Genes{$id}{'C'})/$Genes{$id}{'len'};
}

# 2 = count CG motifs . . . .
foreach my $id (keys %Genes)
{	my $cgcount = 0;
	my $position = index($Genes{$id}{'seq'}, 'CG', 0);
	while($position > -1)
	{	$cgcount += 1;
		$position = index($Genes{$id}{'seq'}, 'CG', $position+2);
	}
	$Genes{$id}{'CpG'} = $cgcount/$Genes{$id}{'len'};
}


# 3. Output fancy analysis
open(OUT, ">$outfile");
print OUT "ID\tSIZE\tGC\tCpG\n";
foreach my $id (keys %Genes)
{	print OUT "$id\t$Genes{$id}{'len'}\t$Genes{$id}{'%GC'}\t$Genes{$id}{'CpG'}\n";  }
close(OUT);

#-------------------------------------------------------
# 5. Run R Analysis Script . . . . .
system('R --vanilla <02-PLOT-FastaSize-GC.R');
#-------------------------------------------------------

# 6. Print HTML Report . . . . . . . . . . . . . . . . .  
open(OUT,">$htmlfile");
print OUT "<html>\n<title>Genome Profiles</title>\n<body>\n";
print OUT "Data for free-living microbial genomes were obtained from file <b>\"$infile\"</b>.<br><br>";
print OUT "A parsing srcipt was used to extract the genome size and %GC content observations, and then \n";
print OUT "this information is presented below.<br><br>\n";
print OUT "Distribution profiles for Genome Size and %GC in the data set.<br>\n";
print OUT "<table><tr><td><img src=\"PLOT-Fig1-SIZE.jpg\" style=\"height:300px\"></td><td><img src=\"PLOT-Fig2-GC.jpg\" style=\"height:300px\"></td></tr></table><br>\n";
print OUT "<br><hr><br><b>Correlation SIZE vs. GC Content</b><br>\n";
print OUT "<img src=\"PLOT-Fig3-SIZEvsGC.jpg\" style=\"height:500px\"><br><hr>\n";
print OUT "<br><br><b>Correlation GC Content vs. CpG motifs</b><br>\n";
print OUT "<img src=\"PLOT-Fig4-GCvsCpG.jpg\" style=\"height:500px\"><br><hr><br>\n";
print OUT "</body>\n</html>\n";
close(OUT);

print "\n\n\n* * * *   D O N E   * * * * \n\n\n";
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# - - - - - S U B R O U T I N E S - - - - - - - - - - -
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
sub FASTAread
{	
	# 1. Load FIlE . . . . . . . . . .
	$/=">";
	my $xfile = $_[0];
	open(IN, "<$xfile") or die "\n\nNADA $xfile you FOOL!!!\n\n";
	my @DATA = <IN>; close(IN); shift(@DATA);
	
	# 2. Parse sequence data . . . . . . . . . . . . .
	my $unid = 10000;
	foreach my $entry (@DATA)
	{	my @data = split('\n', $entry);
		my $head = $data[0];
		my $seq = '';
		foreach my $i (1..$#data)
		{	$seq .= $data[$i];  }
		$seq =~ s/>//;
		$Genes{$unid}{'head'} = $head;
		$Genes{$unid}{'seq'}  = uc($seq);
		$Genes{$unid}{'len'}  = length($seq);
		$unid += 1;
	}
	$/="\n";
}

# - - - - - EOF - - - - - - - - - - - - - - - - - - - - - -
}}}

!


[[< Back|Lecture Index]]|[[Next>|FastaRead-02]]
!FASTA Files:
The standard file format for storing sequence data is the FASTA file (pronounced “~FAST-A” such that the “A” rhymes with “hay”). In this format, the first data line starts with the character ‘>’ and then is followed by a text string of header information that generally conveys the identity and source of the sequence that follows. On the next line, the sequence begins using single letter codes for either nucleotides (gene sequence) or amino acids (protein sequence).
{{{
>YP_001520052.1|5870820|5871593|(-)|[Acaryochloris_marina_MBIC11017_uid58167]
ATGCAAATCCACCGACTACCGGCCTTTTCCGATAACTACATTTTTGTCCTCCATGATCCTGGGCAGAATA
TTGCCGCCGTGGTTGATCCAGCCGATCCTCAGCCCGTACTGAAGAAATTGGCAGAGTTGGGGGCTGAGCT
GGTCGCCATCTTCAATACCCATCACCATTCGGATCATGTGGGGGGCAATCGAACCCTCCTCCAGGCTTTT
CCCAACACCGTTGTTTATGGAGGAGAGCAGGATCGAGGTCGGATTCCCGGCCAGCAACACTTTCTAAAAG
AAGGCGATCAA
}}}
This format provides a mechanism for putting many sequences into one file while still being able to easily separate those sequences when read into a computer script using the ‘>’ character as a signal flag for the break between where one sequence is over and the next sequence begins. This organization originally appeared in 1985 in an alignment program called “FASTP” and quickly became the standard format for handling sequence files:

{{engindent{{{engindent{//Lipman, DJ, and Pearson, WR (1985). “Rapid and sensitive protein similarity searches”. Science 227: 14351441.//}}}}}}

!
[[< Back|FastaRead-01]]|[[Next>|FastaRead-03]]
!FASTA Files:
When ever you are faced with a specific task to code, generate a controlled test file to use that has these two features: 1) you already know what the answer will be using the test file; 2) the test file is small so all the debugging goes quickly. These advantages are obvious, but another benefit is that while developing code on test files you will often think of other things to add to the code that will make the output more useful to you. There’s definitely a feedback process in terms of watching code run and thinking of minor tweaks to add. Often those minor tweaks are the ‘features’ that you would never attend to if you were just trying to bull your way through a one-draft script to crunch a big file (see lesson number one above).
{{{
>gene-1A
AGCTAGCT
>gene-2B
AGCTAGCTAGCTAGCTAGCTAGCTAGCTAGCT
>gene-3C
AGCTAGCTAGCTAGCTAGCTAGCTAGCTAGCT
AGCTAGCTAGCTAGCTAGCTAGCTAGCTAGCT
AGCTAGCTAGCTAGCTAGCTAGCTAGCTAGCT
>gene-4D
AGCTAGCTAGCTAGCTAGCTAGCT
AGCTAGCTAGCTAGCTAGCTAGCTAGCTAGCT
AGCTAGCTAGCTAGCTAGCTAGCTAGCTAGCT
AGCTAGCTAGCTAGCTAGCTAGCTAGCTAGCTAGCTAGCT
AGCTAGCTAGCTAGCTAGCTAGCTAGCTAGCTAGCTAGCTAGCTAGCTAGCTAGCTAGCTAGCT
AGCTAGCTAGCTAGCTAGCTAGCTAGCTAGCTAGCTAGCTAGCT
AGCTAGCTAGCTAGCTAGCT
}}}
These all use a basic sequence repeat “AGCT” with different length variations and different line-break (‘\n’) locations. The header contains the gene sequence name. Please note that at the end of every line, there is a line-break character that is not displayed, so technically each line of sequence ends like this: “. . . AGCT\n”. 
!
[[< Back|FastaRead-02]]|[[Next>|FastaRead-04]]
!FASTA Files:
The key to parsing any file is to recognize it's structure in terms of repetitive units and then utilize that repeat pattern as a mechanism to dissect the entire file into component parts. For FASTA files, we key in on the use of the '>' character to signal the start of a header line, but keep in mind that at the same time this '>' character also signals the end of the previous group of sequence lines. 

PERL has a reserved system variable designated '' '$/' '' that is defined as the //input break string//. By default, {{{$/ = '\n'}}} so that when reading the IO stream, the input is separated by lines defined by the line-break character. We can set the //input break string// to anything that exhibits a repetitive pattern in the text file, so here we use:
{{{
$/ = '>';
}}}
. . . to divide the IO stream into units whenever the '>' character is encountered.

{{{
# 1. Load FIlE . . . . . . . . . .
my $pathfile = $path . "/" . $infile;
$/='>';
open(IN, "<$pathfile") or die "\n\nNADA $pathfile you FOOL!!!\n\n";
my @DATA = <IN>;
close(IN);
print "$pathfile opened with ", $#DATA + 1," lines input to memory.\n\n";
shift(@DATA);

# Display contents of the @DATA entries . . . . . . . . .  
foreach my $i (0..$#DATA)
{	print "***************************\n";
	print "$i:\n<START>\n";
	print $DATA[$i];
	print "\n<END>\n";
}
}}}
Here are the first few elements in @DATA:
{{{
***************************
0:
<START>
 Test Fasta 001
agctcgatcgatggcgcgatatagcgcgtatagcgctagggatcgcgcgatagcgatagc
>
<END>
***************************
1:
<START>
 Test Fasta 002
agctcgatcgatggcgcgatatagcgcgtatagcgctagggatcgcgcgatagcgatagc
agctcgatcgatggcgcgatatagcgcgtatagcgctagggatcgcgcgatagcgatagc
>
<END>
***************************
2:
<START>
 Test Fasta 003
agctcgatcgatggcgcgatatagcgcgtatagcgctagggatcgcgcgatagcgatagc
agctcgatcgatggcgcgatatagcgcgtatagcgctagggatcgcgcgatagcgatagc
agctcgatcgatggcgcgatatagcgcgtatagcgctagggatcgcgcgatagcgatagc
>
<END>

}}}

!

[[< Back|FastaRead-03]]|[[Next>|FastaRead-05]]
!FASTA Files:

Now we parse each 'entry' in @DATA for the header and sequence information we need to extract. Use the split command to divide the entry into separate lines: 

{{{
foreach my $entry (@DATA)
{	my @data = split('\n', $entry);
        # Display the contents of @data after split . . . . . . . . . . . 
	foreach my $i (0..$#data)
	{	print "***************************\n";
	   print "$i:\n<START>\n";
	   print $data[$i];
	   print "\n<END>\n";
	}
	die;
}
}}}
. . . . which generates this output:
{{{
***************************
0:
<START>
 Test Fasta 001
<END>
***************************
1:
<START>
agctcgatcgatggcgcgatatagcgcgtatagcgctagggatcgcgcgatagcgatagc
<END>
***************************
2:
<START>
>
<END>
}}}

So now we can access all this information from memory because we know:
* $data[0] = header info = "Test Fasta 001"
* $data[1] = sequence info = "agctcgatcgatggcgcgatatagcgcgtatagcgctagggatcgcgcgatagcgatagc"
* $data[2] = input break character = '>'
 



!
[[< Back|FastaRead-04]]|[[Return to Lecture Index|Lecture Index]]|[[NEXT = FASTA ANALYZE>>|FastaAnalyze-01]]
!FASTA Files:
A working FASTA read script"

{{{
#!/usr/bin/perl
use strict;

# - - - - - H E A D E R - - - - - - - - - - - - - - - - -
# GOAL: Read FASTA sequence format 
# XYZ-2012

# - - - - - U S E R    V A R I A B L E S - - - - - - - -
my $path    = "00-Data";
my $infile  = "TestFasta.txt";

# - - - - - G L O B A L  V A R I A B L E S  - - - - - -
my %Genes;

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# - - - - - M A I N - - - - - - - - - - - - - - - - - - - -
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
print "\n\nWorking for the man every night and day . . .\n\n";

# 1. Load FIlE . . . . . . . . . .
my $pathfile = $path . "/" . $infile;
$/='>';
open(IN, "<$pathfile") or die "\n\nNADA $pathfile you FOOL!!!\n\n";
my @DATA = <IN>;
close(IN);
print "$pathfile opened with ", $#DATA + 1," lines input to memory.\n\n";
shift(@DATA);

# 2. Parse sequence data . . . . . . . . . . . . . 
foreach my $entry (@DATA)
{	my @data = split('\n', $entry);
 	my $head = $data[0];
	my $seq = '';
	foreach my $i (1..$#data)
	{	$seq .= $data[$i];  }
	$seq =~ s/>//;	
	$Genes{$head}{'seq'} = uc($seq);
	$Genes{$head}{'len'} = length($seq);
}


print "\n\nSorted Values:\n";
my @sortedkeys = sort {$Genes{$b}{'len'} <=> $Genes{$a}{'len'} } (keys %Genes);
foreach my $id (@sortedkeys)
{	print "     $id => length: $Genes{$id}{'len'}\n";  }



print "\n\n\n* * * *   D O N E   * * * * \n\n\n";


## - - - - - EOF - - - - - - - - - - - - - - - - - - - - - -

}}}



!


/***
|Name|FontSizePlugin|
|Created by|SaqImtiaz|
|Location|http://tw.lewcid.org/#FontSizePlugin|
|Version|1.0|
|Requires|~TW2.x|
!Description:
Resize tiddler text on the fly. The text size is remembered between sessions by use of a cookie.
You can customize the maximum and minimum allowed sizes.
(only affects tiddler content text, not any other text)

Also, you can load a TW file with a font-size specified in the url.
Eg: http://tw.lewcid.org/#font:110

!Demo:
Try using the font-size buttons in the sidebar, or in the MainMenu above.

!Installation:
Copy the contents of this tiddler to your TW, tag with systemConfig, save and reload your TW.
Then put {{{<<fontSize "font-size:">>}}} in your SideBarOptions tiddler, or anywhere else that you might like.

!Usage
{{{<<fontSize>>}}} results in <<fontSize>>
{{{<<fontSize font-size: >>}}} results in <<fontSize font-size:>>

!Customizing:
The buttons and prefix text are wrapped in a span with class fontResizer, for easy css styling.
To change the default font-size, and the maximum and minimum font-size allowed, edit the config.fontSize.settings section of the code below.

!Notes:
This plugin assumes that the initial font-size is 100% and then increases or decreases the size by 10%. This stepsize of 10% can also be customized.

!History:
*27-07-06, version 1.0 : prevented double clicks from triggering editing of containing tiddler.
*25-07-06,  version 0.9

!Code
***/

//{{{
config.fontSize={};

//configuration settings
config.fontSize.settings =
{
            defaultSize : 100,  // all sizes in %
            maxSize : 200,
            minSize : 40,
            stepSize : 10
};

//startup code
var fontSettings = config.fontSize.settings;

if (!config.options.txtFontSize)
            {config.options.txtFontSize = fontSettings.defaultSize;
            saveOptionCookie("txtFontSize");}
setStylesheet(".tiddler .viewer {font-size:"+config.options.txtFontSize+"%;}\n","fontResizerStyles");
setStylesheet("#contentWrapper .fontResizer .button {display:inline;font-size:105%; font-weight:bold; margin:0 1px; padding: 0 3px; text-align:center !important;}\n .fontResizer {margin:0 0.5em;}","fontResizerButtonStyles");

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

               var sp = createTiddlyElement(place,"span",null,"fontResizer");
               sp.ondblclick=this.onDblClick;
               if (params[0])
                           createTiddlyText(sp,params[0]);
               createTiddlyButton(sp,"+","increase font-size",this.incFont);
               createTiddlyButton(sp,"=","reset font-size",this.resetFont);
               createTiddlyButton(sp,"–","decrease font-size",this.decFont);
}

config.macros.fontSize.onDblClick = function (e)
{
             if (!e) var e = window.event;
             e.cancelBubble = true;
             if (e.stopPropagation) e.stopPropagation();
             return false;
}

config.macros.fontSize.setFont = function ()
{
               saveOptionCookie("txtFontSize");
               setStylesheet(".tiddler .viewer {font-size:"+config.options.txtFontSize+"%;}\n","fontResizerStyles");
}

config.macros.fontSize.incFont=function()
{
               if (config.options.txtFontSize < fontSettings.maxSize)
                  config.options.txtFontSize = (config.options.txtFontSize*1)+fontSettings.stepSize;
               config.macros.fontSize.setFont();
}

config.macros.fontSize.decFont=function()
{

               if (config.options.txtFontSize > fontSettings.minSize)
                  config.options.txtFontSize = (config.options.txtFontSize*1) - fontSettings.stepSize;
               config.macros.fontSize.setFont();
}

config.macros.fontSize.resetFont=function()
{

               config.options.txtFontSize=fontSettings.defaultSize;
               config.macros.fontSize.setFont();
}

config.paramifiers.font =
{
               onstart: function(v)
                  {
                   config.options.txtFontSize = v;
                   config.macros.fontSize.setFont();
                  }
};
//}}}
/***
|''Name:''|ForEachTiddlerPlugin|
|''Version:''|1.0.8 (2007-04-12)|
|''Source:''|http://tiddlywiki.abego-software.de/#ForEachTiddlerPlugin|
|''Author:''|UdoBorkowski (ub [at] abego-software [dot] de)|
|''Licence:''|[[BSD open source license (abego Software)|http://www.abego-software.de/legal/apl-v10.html]]|
|''Copyright:''|&copy; 2005-2007 [[abego Software|http://www.abego-software.de]]|
|''TiddlyWiki:''|1.2.38+, 2.0|
|''Browser:''|Firefox 1.0.4+; Firefox 1.5; InternetExplorer 6.0|
!Description

Create customizable lists, tables etc. for your selections of tiddlers. Specify the tiddlers to include and their order through a powerful language.

''Syntax:'' 
|>|{{{<<}}}''forEachTiddler'' [''in'' //tiddlyWikiPath//] [''where'' //whereCondition//] [''sortBy'' //sortExpression// [''ascending'' //or// ''descending'']] [''script'' //scriptText//] [//action// [//actionParameters//]]{{{>>}}}|
|//tiddlyWikiPath//|The filepath to the TiddlyWiki the macro should work on. When missing the current TiddlyWiki is used.|
|//whereCondition//|(quoted) JavaScript boolean expression. May refer to the build-in variables {{{tiddler}}} and  {{{context}}}.|
|//sortExpression//|(quoted) JavaScript expression returning "comparable" objects (using '{{{<}}}','{{{>}}}','{{{==}}}'. May refer to the build-in variables {{{tiddler}}} and  {{{context}}}.|
|//scriptText//|(quoted) JavaScript text. Typically defines JavaScript functions that are called by the various JavaScript expressions (whereClause, sortClause, action arguments,...)|
|//action//|The action that should be performed on every selected tiddler, in the given order. By default the actions [[addToList|AddToListAction]] and [[write|WriteAction]] are supported. When no action is specified [[addToList|AddToListAction]]  is used.|
|//actionParameters//|(action specific) parameters the action may refer while processing the tiddlers (see action descriptions for details). <<tiddler [[JavaScript in actionParameters]]>>|
|>|~~Syntax formatting: Keywords in ''bold'', optional parts in [...]. 'or' means that exactly one of the two alternatives must exist.~~|

See details see [[ForEachTiddlerMacro]] and [[ForEachTiddlerExamples]].

!Revision history
* v1.0.8 (2007-04-12)
** Adapted to latest TiddlyWiki 2.2 Beta importTiddlyWiki API (introduced with changeset 2004). TiddlyWiki 2.2 Beta builds prior to changeset 2004 are no longer supported (but TiddlyWiki 2.1 and earlier, of cause)
* v1.0.7 (2007-03-28)
** Also support "pre" formatted TiddlyWikis (introduced with TW 2.2) (when using "in" clause to work on external tiddlers)
* v1.0.6 (2006-09-16)
** Context provides "viewerTiddler", i.e. the tiddler used to view the macro. Most times this is equal to the "inTiddler", but when using the "tiddler" macro both may be different.
** Support "begin", "end" and "none" expressions in "write" action
* v1.0.5 (2006-02-05)
** Pass tiddler containing the macro with wikify, context object also holds reference to tiddler containing the macro ("inTiddler"). Thanks to SimonBaird.
** Support Firefox 1.5.0.1
** Internal
*** Make "JSLint" conform
*** "Only install once"
* v1.0.4 (2006-01-06)
** Support TiddlyWiki 2.0
* v1.0.3 (2005-12-22)
** Features: 
*** Write output to a file supports multi-byte environments (Thanks to Bram Chen) 
*** Provide API to access the forEachTiddler functionality directly through JavaScript (see getTiddlers and performMacro)
** Enhancements:
*** Improved error messages on InternetExplorer.
* v1.0.2 (2005-12-10)
** Features: 
*** context object also holds reference to store (TiddlyWiki)
** Fixed Bugs: 
*** ForEachTiddler 1.0.1 has broken support on win32 Opera 8.51 (Thanks to BrunoSabin for reporting)
* v1.0.1 (2005-12-08)
** Features: 
*** Access tiddlers stored in separated TiddlyWikis through the "in" option. I.e. you are no longer limited to only work on the "current TiddlyWiki".
*** Write output to an external file using the "toFile" option of the "write" action. With this option you may write your customized tiddler exports.
*** Use the "script" section to define "helper" JavaScript functions etc. to be used in the various JavaScript expressions (whereClause, sortClause, action arguments,...).
*** Access and store context information for the current forEachTiddler invocation (through the build-in "context" object) .
*** Improved script evaluation (for where/sort clause and write scripts).
* v1.0.0 (2005-11-20)
** initial version

!Code
***/
//{{{

	
//============================================================================
//============================================================================
//		   ForEachTiddlerPlugin
//============================================================================
//============================================================================

// Only install once
if (!version.extensions.ForEachTiddlerPlugin) {

if (!window.abego) window.abego = {};

version.extensions.ForEachTiddlerPlugin = {
	major: 1, minor: 0, revision: 8, 
	date: new Date(2007,3,12), 
	source: "http://tiddlywiki.abego-software.de/#ForEachTiddlerPlugin",
	licence: "[[BSD open source license (abego Software)|http://www.abego-software.de/legal/apl-v10.html]]",
	copyright: "Copyright (c) abego Software GmbH, 2005-2007 (www.abego-software.de)"
};

// For backward compatibility with TW 1.2.x
//
if (!TiddlyWiki.prototype.forEachTiddler) {
	TiddlyWiki.prototype.forEachTiddler = function(callback) {
		for(var t in this.tiddlers) {
			callback.call(this,t,this.tiddlers[t]);
		}
	};
}

//============================================================================
// forEachTiddler Macro
//============================================================================

version.extensions.forEachTiddler = {
	major: 1, minor: 0, revision: 8, date: new Date(2007,3,12), provider: "http://tiddlywiki.abego-software.de"};

// ---------------------------------------------------------------------------
// Configurations and constants 
// ---------------------------------------------------------------------------

config.macros.forEachTiddler = {
	 // Standard Properties
	 label: "forEachTiddler",
	 prompt: "Perform actions on a (sorted) selection of tiddlers",

	 // actions
	 actions: {
		 addToList: {},
		 write: {}
	 }
};

// ---------------------------------------------------------------------------
//  The forEachTiddler Macro Handler 
// ---------------------------------------------------------------------------

config.macros.forEachTiddler.getContainingTiddler = function(e) {
	while(e && !hasClass(e,"tiddler"))
		e = e.parentNode;
	var title = e ? e.getAttribute("tiddler") : null; 
	return title ? store.getTiddler(title) : null;
};

config.macros.forEachTiddler.handler = function(place,macroName,params,wikifier,paramString,tiddler) {
	// config.macros.forEachTiddler.traceMacroCall(place,macroName,params,wikifier,paramString,tiddler);

	if (!tiddler) tiddler = config.macros.forEachTiddler.getContainingTiddler(place);
	// --- Parsing ------------------------------------------

	var i = 0; // index running over the params
	// Parse the "in" clause
	var tiddlyWikiPath = undefined;
	if ((i < params.length) && params[i] == "in") {
		i++;
		if (i >= params.length) {
			this.handleError(place, "TiddlyWiki path expected behind 'in'.");
			return;
		}
		tiddlyWikiPath = this.paramEncode((i < params.length) ? params[i] : "");
		i++;
	}

	// Parse the where clause
	var whereClause ="true";
	if ((i < params.length) && params[i] == "where") {
		i++;
		whereClause = this.paramEncode((i < params.length) ? params[i] : "");
		i++;
	}

	// Parse the sort stuff
	var sortClause = null;
	var sortAscending = true; 
	if ((i < params.length) && params[i] == "sortBy") {
		i++;
		if (i >= params.length) {
			this.handleError(place, "sortClause missing behind 'sortBy'.");
			return;
		}
		sortClause = this.paramEncode(params[i]);
		i++;

		if ((i < params.length) && (params[i] == "ascending" || params[i] == "descending")) {
			 sortAscending = params[i] == "ascending";
			 i++;
		}
	}

	// Parse the script
	var scriptText = null;
	if ((i < params.length) && params[i] == "script") {
		i++;
		scriptText = this.paramEncode((i < params.length) ? params[i] : "");
		i++;
	}

	// Parse the action. 
	// When we are already at the end use the default action
	var actionName = "addToList";
	if (i < params.length) {
	   if (!config.macros.forEachTiddler.actions[params[i]]) {
			this.handleError(place, "Unknown action '"+params[i]+"'.");
			return;
		} else {
			actionName = params[i]; 
			i++;
		}
	} 
	
	// Get the action parameter
	// (the parsing is done inside the individual action implementation.)
	var actionParameter = params.slice(i);


	// --- Processing ------------------------------------------
	try {
		this.performMacro({
				place: place, 
				inTiddler: tiddler,
				whereClause: whereClause, 
				sortClause: sortClause, 
				sortAscending: sortAscending, 
				actionName: actionName, 
				actionParameter: actionParameter, 
				scriptText: scriptText, 
				tiddlyWikiPath: tiddlyWikiPath});

	} catch (e) {
		this.handleError(place, e);
	}
};

// Returns an object with properties "tiddlers" and "context".
// tiddlers holds the (sorted) tiddlers selected by the parameter,
// context the context of the execution of the macro.
//
// The action is not yet performed.
//
// @parameter see performMacro
//
config.macros.forEachTiddler.getTiddlersAndContext = function(parameter) {

	var context = config.macros.forEachTiddler.createContext(parameter.place, parameter.whereClause, parameter.sortClause, parameter.sortAscending, parameter.actionName, parameter.actionParameter, parameter.scriptText, parameter.tiddlyWikiPath, parameter.inTiddler);

	var tiddlyWiki = parameter.tiddlyWikiPath ? this.loadTiddlyWiki(parameter.tiddlyWikiPath) : store;
	context["tiddlyWiki"] = tiddlyWiki;
	
	// Get the tiddlers, as defined by the whereClause
	var tiddlers = this.findTiddlers(parameter.whereClause, context, tiddlyWiki);
	context["tiddlers"] = tiddlers;

	// Sort the tiddlers, when sorting is required.
	if (parameter.sortClause) {
		this.sortTiddlers(tiddlers, parameter.sortClause, parameter.sortAscending, context);
	}

	return {tiddlers: tiddlers, context: context};
};

// Returns the (sorted) tiddlers selected by the parameter.
//
// The action is not yet performed.
//
// @parameter see performMacro
//
config.macros.forEachTiddler.getTiddlers = function(parameter) {
	return this.getTiddlersAndContext(parameter).tiddlers;
};

// Performs the macros with the given parameter.
//
// @param parameter holds the parameter of the macro as separate properties.
//				  The following properties are supported:
//
//						place
//						whereClause
//						sortClause
//						sortAscending
//						actionName
//						actionParameter
//						scriptText
//						tiddlyWikiPath
//
//					All properties are optional. 
//					For most actions the place property must be defined.
//
config.macros.forEachTiddler.performMacro = function(parameter) {
	var tiddlersAndContext = this.getTiddlersAndContext(parameter);

	// Perform the action
	var actionName = parameter.actionName ? parameter.actionName : "addToList";
	var action = config.macros.forEachTiddler.actions[actionName];
	if (!action) {
		this.handleError(parameter.place, "Unknown action '"+actionName+"'.");
		return;
	}

	var actionHandler = action.handler;
	actionHandler(parameter.place, tiddlersAndContext.tiddlers, parameter.actionParameter, tiddlersAndContext.context);
};

// ---------------------------------------------------------------------------
//  The actions 
// ---------------------------------------------------------------------------

// Internal.
//
// --- The addToList Action -----------------------------------------------
//
config.macros.forEachTiddler.actions.addToList.handler = function(place, tiddlers, parameter, context) {
	// Parse the parameter
	var p = 0;

	// Check for extra parameters
	if (parameter.length > p) {
		config.macros.forEachTiddler.createExtraParameterErrorElement(place, "addToList", parameter, p);
		return;
	}

	// Perform the action.
	var list = document.createElement("ul");
	place.appendChild(list);
	for (var i = 0; i < tiddlers.length; i++) {
		var tiddler = tiddlers[i];
		var listItem = document.createElement("li");
		list.appendChild(listItem);
		createTiddlyLink(listItem, tiddler.title, true);
	}
};

abego.parseNamedParameter = function(name, parameter, i) {
	var beginExpression = null;
	if ((i < parameter.length) && parameter[i] == name) {
		i++;
		if (i >= parameter.length) {
			throw "Missing text behind '%0'".format([name]);
		}
		
		return config.macros.forEachTiddler.paramEncode(parameter[i]);
	}
	return null;
}

// Internal.
//
// --- The write Action ---------------------------------------------------
//
config.macros.forEachTiddler.actions.write.handler = function(place, tiddlers, parameter, context) {
	// Parse the parameter
	var p = 0;
	if (p >= parameter.length) {
		this.handleError(place, "Missing expression behind 'write'.");
		return;
	}

	var textExpression = config.macros.forEachTiddler.paramEncode(parameter[p]);
	p++;

	// Parse the "begin" option
	var beginExpression = abego.parseNamedParameter("begin", parameter, p);
	if (beginExpression !== null) 
		p += 2;
	var endExpression = abego.parseNamedParameter("end", parameter, p);
	if (endExpression !== null) 
		p += 2;
	var noneExpression = abego.parseNamedParameter("none", parameter, p);
	if (noneExpression !== null) 
		p += 2;

	// Parse the "toFile" option
	var filename = null;
	var lineSeparator = undefined;
	if ((p < parameter.length) && parameter[p] == "toFile") {
		p++;
		if (p >= parameter.length) {
			this.handleError(place, "Filename expected behind 'toFile' of 'write' action.");
			return;
		}
		
		filename = config.macros.forEachTiddler.getLocalPath(config.macros.forEachTiddler.paramEncode(parameter[p]));
		p++;
		if ((p < parameter.length) && parameter[p] == "withLineSeparator") {
			p++;
			if (p >= parameter.length) {
				this.handleError(place, "Line separator text expected behind 'withLineSeparator' of 'write' action.");
				return;
			}
			lineSeparator = config.macros.forEachTiddler.paramEncode(parameter[p]);
			p++;
		}
	}
	
	// Check for extra parameters
	if (parameter.length > p) {
		config.macros.forEachTiddler.createExtraParameterErrorElement(place, "write", parameter, p);
		return;
	}

	// Perform the action.
	var func = config.macros.forEachTiddler.getEvalTiddlerFunction(textExpression, context);
	var count = tiddlers.length;
	var text = "";
	if (count > 0 && beginExpression)
		text += config.macros.forEachTiddler.getEvalTiddlerFunction(beginExpression, context)(undefined, context, count, undefined);
	
	for (var i = 0; i < count; i++) {
		var tiddler = tiddlers[i];
		text += func(tiddler, context, count, i);
	}
	
	if (count > 0 && endExpression)
		text += config.macros.forEachTiddler.getEvalTiddlerFunction(endExpression, context)(undefined, context, count, undefined);

	if (count == 0 && noneExpression) 
		text += config.macros.forEachTiddler.getEvalTiddlerFunction(noneExpression, context)(undefined, context, count, undefined);
		

	if (filename) {
		if (lineSeparator !== undefined) {
			lineSeparator = lineSeparator.replace(/\\n/mg, "\n").replace(/\\r/mg, "\r");
			text = text.replace(/\n/mg,lineSeparator);
		}
		saveFile(filename, convertUnicodeToUTF8(text));
	} else {
		var wrapper = createTiddlyElement(place, "span");
		wikify(text, wrapper, null/* highlightRegExp */, context.inTiddler);
	}
};


// ---------------------------------------------------------------------------
//  Helpers
// ---------------------------------------------------------------------------

// Internal.
//
config.macros.forEachTiddler.createContext = function(placeParam, whereClauseParam, sortClauseParam, sortAscendingParam, actionNameParam, actionParameterParam, scriptText, tiddlyWikiPathParam, inTiddlerParam) {
	return {
		place : placeParam, 
		whereClause : whereClauseParam, 
		sortClause : sortClauseParam, 
		sortAscending : sortAscendingParam, 
		script : scriptText,
		actionName : actionNameParam, 
		actionParameter : actionParameterParam,
		tiddlyWikiPath : tiddlyWikiPathParam,
		inTiddler : inTiddlerParam, // the tiddler containing the <<forEachTiddler ...>> macro call.
		viewerTiddler : config.macros.forEachTiddler.getContainingTiddler(placeParam) // the tiddler showing the forEachTiddler result
	};
};

// Internal.
//
// Returns a TiddlyWiki with the tiddlers loaded from the TiddlyWiki of 
// the given path.
//
config.macros.forEachTiddler.loadTiddlyWiki = function(path, idPrefix) {
	if (!idPrefix) {
		idPrefix = "store";
	}
	var lenPrefix = idPrefix.length;
	
	// Read the content of the given file
	var content = loadFile(this.getLocalPath(path));
	if(content === null) {
		throw "TiddlyWiki '"+path+"' not found.";
	}
	
	var tiddlyWiki = new TiddlyWiki();

	// Starting with TW 2.2 there is a helper function to import the tiddlers
	if (tiddlyWiki.importTiddlyWiki) {
		if (!tiddlyWiki.importTiddlyWiki(content))
			throw "File '"+path+"' is not a TiddlyWiki.";
		tiddlyWiki.dirty = false;
		return tiddlyWiki;
	}
	
	// The legacy code, for TW < 2.2
	
	// Locate the storeArea div's
	var posOpeningDiv = content.indexOf(startSaveArea);
	var posClosingDiv = content.lastIndexOf(endSaveArea);
	if((posOpeningDiv == -1) || (posClosingDiv == -1)) {
		throw "File '"+path+"' is not a TiddlyWiki.";
	}
	var storageText = content.substr(posOpeningDiv + startSaveArea.length, posClosingDiv);
	
	// Create a "div" element that contains the storage text
	var myStorageDiv = document.createElement("div");
	myStorageDiv.innerHTML = storageText;
	myStorageDiv.normalize();
	
	// Create all tiddlers in a new TiddlyWiki
	// (following code is modified copy of TiddlyWiki.prototype.loadFromDiv)
	var store = myStorageDiv.childNodes;
	for(var t = 0; t < store.length; t++) {
		var e = store[t];
		var title = null;
		if(e.getAttribute)
			title = e.getAttribute("tiddler");
		if(!title && e.id && e.id.substr(0,lenPrefix) == idPrefix)
			title = e.id.substr(lenPrefix);
		if(title && title !== "") {
			var tiddler = tiddlyWiki.createTiddler(title);
			tiddler.loadFromDiv(e,title);
		}
	}
	tiddlyWiki.dirty = false;

	return tiddlyWiki;
};


	
// Internal.
//
// Returns a function that has a function body returning the given javaScriptExpression.
// The function has the parameters:
// 
//	 (tiddler, context, count, index)
//
config.macros.forEachTiddler.getEvalTiddlerFunction = function (javaScriptExpression, context) {
	var script = context["script"];
	var functionText = "var theFunction = function(tiddler, context, count, index) { return "+javaScriptExpression+"}";
	var fullText = (script ? script+";" : "")+functionText+";theFunction;";
	return eval(fullText);
};

// Internal.
//
config.macros.forEachTiddler.findTiddlers = function(whereClause, context, tiddlyWiki) {
	var result = [];
	var func = config.macros.forEachTiddler.getEvalTiddlerFunction(whereClause, context);
	tiddlyWiki.forEachTiddler(function(title,tiddler) {
		if (func(tiddler, context, undefined, undefined)) {
			result.push(tiddler);
		}
	});
	return result;
};

// Internal.
//
config.macros.forEachTiddler.createExtraParameterErrorElement = function(place, actionName, parameter, firstUnusedIndex) {
	var message = "Extra parameter behind '"+actionName+"':";
	for (var i = firstUnusedIndex; i < parameter.length; i++) {
		message += " "+parameter[i];
	}
	this.handleError(place, message);
};

// Internal.
//
config.macros.forEachTiddler.sortAscending = function(tiddlerA, tiddlerB) {
	var result = 
		(tiddlerA.forEachTiddlerSortValue == tiddlerB.forEachTiddlerSortValue) 
			? 0
			: (tiddlerA.forEachTiddlerSortValue < tiddlerB.forEachTiddlerSortValue)
			   ? -1 
			   : +1; 
	return result;
};

// Internal.
//
config.macros.forEachTiddler.sortDescending = function(tiddlerA, tiddlerB) {
	var result = 
		(tiddlerA.forEachTiddlerSortValue == tiddlerB.forEachTiddlerSortValue) 
			? 0
			: (tiddlerA.forEachTiddlerSortValue < tiddlerB.forEachTiddlerSortValue)
			   ? +1 
			   : -1; 
	return result;
};

// Internal.
//
config.macros.forEachTiddler.sortTiddlers = function(tiddlers, sortClause, ascending, context) {
	// To avoid evaluating the sortClause whenever two items are compared 
	// we pre-calculate the sortValue for every item in the array and store it in a 
	// temporary property ("forEachTiddlerSortValue") of the tiddlers.
	var func = config.macros.forEachTiddler.getEvalTiddlerFunction(sortClause, context);
	var count = tiddlers.length;
	var i;
	for (i = 0; i < count; i++) {
		var tiddler = tiddlers[i];
		tiddler.forEachTiddlerSortValue = func(tiddler,context, undefined, undefined);
	}

	// Do the sorting
	tiddlers.sort(ascending ? this.sortAscending : this.sortDescending);

	// Delete the temporary property that holds the sortValue.	
	for (i = 0; i < tiddlers.length; i++) {
		delete tiddlers[i].forEachTiddlerSortValue;
	}
};


// Internal.
//
config.macros.forEachTiddler.trace = function(message) {
	displayMessage(message);
};

// Internal.
//
config.macros.forEachTiddler.traceMacroCall = function(place,macroName,params) {
	var message ="<<"+macroName;
	for (var i = 0; i < params.length; i++) {
		message += " "+params[i];
	}
	message += ">>";
	displayMessage(message);
};


// Internal.
//
// Creates an element that holds an error message
// 
config.macros.forEachTiddler.createErrorElement = function(place, exception) {
	var message = (exception.description) ? exception.description : exception.toString();
	return createTiddlyElement(place,"span",null,"forEachTiddlerError","<<forEachTiddler ...>>: "+message);
};

// Internal.
//
// @param place [may be null]
//
config.macros.forEachTiddler.handleError = function(place, exception) {
	if (place) {
		this.createErrorElement(place, exception);
	} else {
		throw exception;
	}
};

// Internal.
//
// Encodes the given string.
//
// Replaces 
//	 "$))" to ">>"
//	 "$)" to ">"
//
config.macros.forEachTiddler.paramEncode = function(s) {
	var reGTGT = new RegExp("\\$\\)\\)","mg");
	var reGT = new RegExp("\\$\\)","mg");
	return s.replace(reGTGT, ">>").replace(reGT, ">");
};

// Internal.
//
// Returns the given original path (that is a file path, starting with "file:")
// as a path to a local file, in the systems native file format.
//
// Location information in the originalPath (i.e. the "#" and stuff following)
// is stripped.
// 
config.macros.forEachTiddler.getLocalPath = function(originalPath) {
	// Remove any location part of the URL
	var hashPos = originalPath.indexOf("#");
	if(hashPos != -1)
		originalPath = originalPath.substr(0,hashPos);
	// Convert to a native file format assuming
	// "file:///x:/path/path/path..." - pc local file --> "x:\path\path\path..."
	// "file://///server/share/path/path/path..." - FireFox pc network file --> "\\server\share\path\path\path..."
	// "file:///path/path/path..." - mac/unix local file --> "/path/path/path..."
	// "file://server/share/path/path/path..." - pc network file --> "\\server\share\path\path\path..."
	var localPath;
	if(originalPath.charAt(9) == ":") // pc local file
		localPath = unescape(originalPath.substr(8)).replace(new RegExp("/","g"),"\\");
	else if(originalPath.indexOf("file://///") === 0) // FireFox pc network file
		localPath = "\\\\" + unescape(originalPath.substr(10)).replace(new RegExp("/","g"),"\\");
	else if(originalPath.indexOf("file:///") === 0) // mac/unix local file
		localPath = unescape(originalPath.substr(7));
	else if(originalPath.indexOf("file:/") === 0) // mac/unix local file
		localPath = unescape(originalPath.substr(5));
	else // pc network file
		localPath = "\\\\" + unescape(originalPath.substr(7)).replace(new RegExp("/","g"),"\\");	
	return localPath;
};

// ---------------------------------------------------------------------------
// Stylesheet Extensions (may be overridden by local StyleSheet)
// ---------------------------------------------------------------------------
//
setStylesheet(
	".forEachTiddlerError{color: #ffffff;background-color: #880000;}",
	"forEachTiddler");

//============================================================================
// End of forEachTiddler Macro
//============================================================================


//============================================================================
// String.startsWith Function
//============================================================================
//
// Returns true if the string starts with the given prefix, false otherwise.
//
version.extensions["String.startsWith"] = {major: 1, minor: 0, revision: 0, date: new Date(2005,11,20), provider: "http://tiddlywiki.abego-software.de"};
//
String.prototype.startsWith = function(prefix) {
	var n =  prefix.length;
	return (this.length >= n) && (this.slice(0, n) == prefix);
};



//============================================================================
// String.endsWith Function
//============================================================================
//
// Returns true if the string ends with the given suffix, false otherwise.
//
version.extensions["String.endsWith"] = {major: 1, minor: 0, revision: 0, date: new Date(2005,11,20), provider: "http://tiddlywiki.abego-software.de"};
//
String.prototype.endsWith = function(suffix) {
	var n = suffix.length;
	return (this.length >= n) && (this.right(n) == suffix);
};


//============================================================================
// String.contains Function
//============================================================================
//
// Returns true when the string contains the given substring, false otherwise.
//
version.extensions["String.contains"] = {major: 1, minor: 0, revision: 0, date: new Date(2005,11,20), provider: "http://tiddlywiki.abego-software.de"};
//
String.prototype.contains = function(substring) {
	return this.indexOf(substring) >= 0;
};

//============================================================================
// Array.indexOf Function
//============================================================================
//
// Returns the index of the first occurance of the given item in the array or 
// -1 when no such item exists.
//
// @param item [may be null]
//
version.extensions["Array.indexOf"] = {major: 1, minor: 0, revision: 0, date: new Date(2005,11,20), provider: "http://tiddlywiki.abego-software.de"};
//
Array.prototype.indexOf = function(item) {
	for (var i = 0; i < this.length; i++) {
		if (this[i] == item) {
			return i;
		}
	}
	return -1;
};

//============================================================================
// Array.contains Function
//============================================================================
//
// Returns true when the array contains the given item, otherwise false. 
//
// @param item [may be null]
//
version.extensions["Array.contains"] = {major: 1, minor: 0, revision: 0, date: new Date(2005,11,20), provider: "http://tiddlywiki.abego-software.de"};
//
Array.prototype.contains = function(item) {
	return (this.indexOf(item) >= 0);
};

//============================================================================
// Array.containsAny Function
//============================================================================
//
// Returns true when the array contains at least one of the elements 
// of the item. Otherwise (or when items contains no elements) false is returned.
//
version.extensions["Array.containsAny"] = {major: 1, minor: 0, revision: 0, date: new Date(2005,11,20), provider: "http://tiddlywiki.abego-software.de"};
//
Array.prototype.containsAny = function(items) {
	for(var i = 0; i < items.length; i++) {
		if (this.contains(items[i])) {
			return true;
		}
	}
	return false;
};


//============================================================================
// Array.containsAll Function
//============================================================================
//
// Returns true when the array contains all the items, otherwise false.
// 
// When items is null false is returned (even if the array contains a null).
//
// @param items [may be null] 
//
version.extensions["Array.containsAll"] = {major: 1, minor: 0, revision: 0, date: new Date(2005,11,20), provider: "http://tiddlywiki.abego-software.de"};
//
Array.prototype.containsAll = function(items) {
	for(var i = 0; i < items.length; i++) {
		if (!this.contains(items[i])) {
			return false;
		}
	}
	return true;
};


} // of "install only once"

// Used Globals (for JSLint) ==============
// ... DOM
/*global 	document */
// ... TiddlyWiki Core
/*global 	convertUnicodeToUTF8, createTiddlyElement, createTiddlyLink, 
			displayMessage, endSaveArea, hasClass, loadFile, saveFile, 
			startSaveArea, store, wikify */
//}}}


/***
!Licence and Copyright
Copyright (c) abego Software ~GmbH, 2005 ([[www.abego-software.de|http://www.abego-software.de]])

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 abego Software 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER OR CONTRIBUTORS 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.
***/

!Format menu
|''bold''|@@highlight@@|
|//italic//|[[hyperlink]]|
|__underline__||
!Greek menu
|{{greek{κλητοι̂ς}}}|{{gkindent{{{gkindent{{{gkindent{κλητοι̂ς}}}}}}}}}|
|{{gkindent{κλητοι̂ς}}}|{{gkindent{{{gkindent{{{gkindent{{{gkindent{κλητοι̂ς}}}}}}}}}}}}|
|{{gkindent{{{gkindent{κλητοι̂ς}}}}}}|{{gkindent{{{gkindent{{{gkindent{{{gkindent{{{gkindent{κλητοι̂ς}}}}}}}}}}}}}}}|
!!Hebrew menu
{{hebrewNoAlign{וַיָּקָם}}}
{{hebrewRightAlign{וַיָּקָם}}}
{{hebAlignAndIndent{וַיָּקָם}}}
{{hebAlignAndIndent{{{hebAlignAndIndent{וַיָּקָם}}}}}}
{{hebAlignAndIndent{{{hebAlignAndIndent{{{hebAlignAndIndent{וַיָּקָם}}}}}}}}}
{{hebAlignAndIndent{{{hebAlignAndIndent{{{hebAlignAndIndent{{{hebAlignAndIndent{וַיָּקָם}}}}}}}}}}}}
{{hebAlignAndIndent{{{hebAlignAndIndent{{{hebAlignAndIndent{{{hebAlignAndIndent{{{hebAlignAndIndent{וַיָּקָם}}}}}}}}}}}}}}}
!Indent menu
{{engindent{Text}}}
{{engindent{{{engindent{Text}}}}}}
{{engindent{{{engindent{{{engindent{Text}}}}}}}}}
{{engindent{{{engindent{{{engindent{{{engindent{Text}}}}}}}}}}}}
{{engindent{{{engindent{{{engindent{{{engindent{{{engindent{Text}}}}}}}}}}}}}}}
!Notes menu
((syntax(add note here))) &#149; ((translation(add note here))) &#149; ((text(add note here))) &#149; ((gram(add note here))) ((Popup: your text here(your popup text here)))
!Color menu
{{red{Red}}} {{blue{Blue}}} {{green{Green}}} {{gold{Gold}}} {{gray{Gray}}} {{magenta{Magenta}}} {{purple{Purple}}} {{teal{Teal}}} {{burgundy{Burgundy}}}
!Highlighting menu
@@bgcolor(#ff6666):Red@@ @@bgcolor(#ccccff):Blue@@ @@Yellow@@ @@bgcolor(#99ff99):Green@@ @@bgcolor(#cc9966):Brown@@ @@bgcolor(#cccc99):Gray@@ @@bgcolor(#ff9933):Orange@@
!Tables menu
Invisible table: {{invisiblecomm{
|!Invisible table header|!Invisible table header|!invisible table header|
|data|data|data|
|data|data|data|
|data|data|data|
}}}
Sortable table:
|sortable|k
|Header1|Header2|Header3|h
|Aa|B3|data7|
|Ab|B2|data2|
|Ac|B1|data8|
Standard table:
|!Header|!Header|!Header|
|data|data|data|
|data|data|data|
|data|data|data|
Table cell colors:
|!Below is a light gray cell|!Below is a dark gray cell|!Below are regular cells|
|bgcolor(#eeeeee):text here|||
||bgcolor(#cccccc):text there||
|||text anywhere|
[[< Back|Mechanics-01]]|[[Next>|Formatting-02]]
!Formats:
Here's a version of the ~TicTacToe WINNER script with all the white space formatting removed: no tabs, no line breaks, no comments, etc.
{{{
#!/usr/bin/perl
use strict;my @cells = qw | 1 2 3 4 5 6 7 8 9 |; my @markers = qw 
| X O |;my $GameOver = 'FALSE';&BOARD;foreach my $move (1..9){ 
if ($GameOver eq 'FALSE') { my $turn = shift(@markers); push(@markers,
 $turn); print "\nWhere does the $turn marker go: ";  my $z = <STDIN>; 
chomp $z; $cells[$z-1] = $turn; &BOARD; &WINNER; } else { print "\n\n
WINNER!\n\n Game Over\n\n"; last; }}sub BOARD{ system('clear');  print
 "\n\n\nThis is my TicTacToe Game\n\n\n"; my $position = 0;  foreach 
(1..3)  { print " |";  foreach (1..3)  { print "_$cells[$position]_|";  $position
 += 1;  } print "\n";  } }sub WINNER{ my $s = 3; my @gamemarkers; my $WIN;
  foreach my $n (0..$s-1) { my $start = $n*3; foreach my $m (0..2) { 
$gamemarkers[$m] = $cells[$start + $m]; } $WIN = CheckIt(@gamemarkers);
 if ($WIN eq 'YES') { $GameOver = 'TRUE'; print "\n>>",@gamemarkers,"<<\n";
 last; } }  if ($GameOver eq 'FALSE') {  foreach my $n (0..$s-1) { my $start =
 $n; foreach my $m (0..2) { $gamemarkers[$m] = $cells[$start + $m*3]; } 
$WIN = CheckIt(@gamemarkers); if ($WIN eq 'YES') { $GameOver = 'TRUE'; last;
 } } if ($GameOver eq 'FALSE') {  foreach my $n (0..1) { my $start = $n*2; 
foreach my $m (0..2) { $gamemarkers[$m] = $cells[$start + $m*4 - $n*$m*2]; }
 $WIN = CheckIt(@gamemarkers); if ($WIN eq 'YES') { $GameOver = 'TRUE'; last; }
 } } }}sub CheckIt{ my @gm = @_; my $sumcheck = 0; foreach my $n (0..1) { 
if ($gm[$n] eq $gm[$n+1]) { $sumcheck += 1; } } if ($sumcheck == 2) { return 
"YES"; } else { return "NO"; } }
}}}

This script is perfectly executable by the PERL interpreter. It reads all the characters as a single string and parses out the instructions to be followed. 

| @@'' What are the RULES for PERL Formatting ? ''@@ |

!


[[< Back|Formatting-01]]|[[Next>|Formatting-03]]
!Rules:

| @@'' Rule Number One for PERL Formatting = There are no rules. ''@@ |

Basically, Rule number one is simply that YOU have to make the rules. And by that, you are responsible for ensuring that when you write code, you can clearly understand it several months later when you look at it again. 

''Most Important Advice: Write Code For YOU - you are the audience''


!
[[< Back|Formatting-02]]|[[Next>|Formatting-04]]
!Rules:

# Name variables so you understand what they contain
# Use indentation liberally to visually separate components of your code
# Align paired braces ''{'' at the same indentation level ''}'' so you can spot NESTING
# Adhere to a rigorous structure for writing code:
** Header Section
** User defined run-time variables
** Global defined fixed variables
** Main Script
** Subroutines
# Be consistently consistent
# Use detailed comments

!
[[< Back|Formatting-03]]|[[Return to Index>|Mechanics-01]]
!Question Authority:

You will find a near universal adherence to BRACE placement like this:
{{{
          foreach my $i (0..9) {
                  print $i;
          }
}}}

Fight It! Fight anything that doesn't make sense to you. It is your code. Develop your style.

| @@''Free your code, and Free your mind''@@|
!!!
Simple choice between GOOD:
{{{
foreach (0..9)
{     <code line 1>
      <code line 2>
      <code line 3>
}
}}}
and EVIL:
{{{
print("".(($line=join("",<>))=~s/.*\n/$h{$&}++?"":$&/ge,$line));
}}}

!

!!FALL 2015

<html><div style="color: rgb(100, 100, 150); font-family: Monaco;"><big><big><big><b><center> 
<b>Bioinformatics Programming <br><br>for Biologists</b>
<br> 
<br> 
</big>MAST 497/697
<br>
<br>
Dr. Adam G. Marsh
<br><br></big>
College of Earth, Ocean and Environment<br>
School of Marine Science and Policy<br.<br>
<br>
</html>
PERL is a very efficient  scripting language for handling text strings, and is ideally suited for the manipulation, analysis and formatting of genetic information. This course focuses on introducing biologists with no prior computer programming experience to working with PERL for bioinformatic applications. The idea is to teach students general PERL syntax for handling basic logical tasks within a computer program to enable editing and trouble-shooting of existing PERL software tools.    
!!Contact
/%
[img[00/00-anim-codingpain.gif]]
%/
''Adam Marsh'', amarsh@udel.edu, 302.645.4367
!
[[<BACK|MoreMonkeys]] | [[NEXT>|GA-01]]
!Genetic Algorithms:

1. Genetic algortihm for bicycle design- http://boxcar2d.com
2. Directed Evolution of Enzymes - http://biomedicalcomputationreview.org/content/computing-better-enzymes-optimizing-directed-evolution
[[BACK to Working Code|BoneYard]]
!Calculate %GC content by gene

Reads nucleotide (uppercase) sequences from the dictionary hash @@{{{%Genes}}}@@. Calculates the %G+C content for each gene sequence.

{{{
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
sub GCcalc
{	print "   Counting GCs . . . \n";
	my $GenDict = $_[0];
	foreach my $id (keys %{$GenDict})
	{	my $count = 0;
		$count = ${$GenDict}{$id}{'ntseq'} =~ tr/GC/GC/;
		$count = $count/${$GenDict}{$id}{'SIZE'};
		${$GenDict}{$id}{'GC'} = &RoundOff($count,3);
	}
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
}}}
[[<Back to Index|BoneYard]]
!INPUT GENBANK GENOME FILE

!!!CALL: 
{{{
my $SEQ = GBKread($pathfile);
}}}
. . . where //$pathfile// is a qualified variable name that contains the folder path (from the current working directory) and the input filename. Subroutine returns a character string containing the nucleotide sequence of the entire genome.


!!!SUB
{{{
sub GBKread
{   my $file = $_[0];
    my $seq = '';
    open(GBK,"<$file") or die "\n\n\nNADA $file . . . . OUCH!!!\n\n\n";
    my @FILE = <GBK>;
    close(GBK);
    my $start = 0;
    foreach my $line (@FILE)
    {   #print $line;
        if ($start == 0)
        {   if ($line =~ m/ORIGIN/)
            {   $start = 1; }
        }
        else
        {   $line =~ s/\d+//g;         # remove digits
            $line =~ s/\s+//g;         # remove white space
            $line =~ s/\///g;          # remove terminal '//'
            $line =~ tr/agtc/AGTC/;    # tranlaste to uppercase
            # $line = uc($line);       # built-in uppercase conversion
            $seq = $seq . $line;
        }
    }
    my $N = length($seq) + 1;
    my $seqtest = substr($seq,1,1000);
    print "\nThere are $N bp in the file: $file\n";
    print "First 1000 bp => \n                 $seqtest . . . . . \n\n";
    return $seq;
}
}}}
!
[[< Back to Resource Index|Resource Index]]
!Advanced Reference Book:
If you begin to like this course, then this is a great resource to pursue to further develop your PERL bioinformatic skills.

''Rex A. Dwyer, //Genomic Perl: From Bioinformatics Basics to Working Code.//''
<html><img src="00/dwyergenperl.png" style="height:200px"></html>
From Amazon.com: //In this introduction to computational molecular biology, Rex Dwyer explains many basic computational problems and gives concise, working programs to solve them in the Perl programming language. With minimal prerequisites, he covers the biological background for each problem, develops a model for the solution, and then introduces the Perl concepts needed to implement the solution. The chapters discuss pairwise and multiple sequence alignment, fast database searches for homologous sequences, protein motif identification, genome rearrangement, physical mapping, phylogeny reconstruction, satellite identification, sequence assembly, gene finding, and RNA secondary structure. Concrete examples and a step-by-step approach enable readers to grasp the computational and statistical methods.// 
[[< Back|Lecture Index]]|[[Next>|HTMLread-02]]
!HTML Files:
Files commonly displayed in web browsers are based on a ''Hyper Text Markup Language'' that consists of simple ASCII character signals to control how text is displayed. As such, these files tend to be highly structured and predictable that allow for easy parsing into smaller information units. 

Consider an example HTML table file: [[GenBankData-110302.html|01/GenBankData-110302.html]].

The HTML display of this table looks like this:
<html><img src="01/screenshot_62.png" style="height:400px"></html>

The text contained in the file looks like this:
<html><img src="01/screenshot_63.png" style="height:500px"></html>

!
[[< Back|HTMLread-01]]|[[Next>|HTMLread-03]]
!HTML Files:
In the HTML script/code, there are two basic control character sequences that we can utilize to break down the lines into their component information:
* <tr> = starts a new TABLE ROW
* <td> = starts a new TABLE CELL within a row
These simple code features can be exploited to parse the ASCII lines into manageable units for data processing/extraction

Looking for repetitive patterns to separate ROWS into independent units, we can set the //input break string// as:
{{{
$/='<tr bgcolor';
}}}

And then once we have the row as a separate string in an array, we can then split it into its component cells:
{{{
my @data = split('</td><td ', $entry);
}}}

Given the objective of extracting the Genome Size and %GC content data for each genome in the table, the parsing loop is simple once we establish that the SIZE data will be in the 5th column (index = 4 in array) and the %GC data will be in the 7th column (index = 6 in the array). Using regex //MATCHING// expressions to save the numeric entries in memory ($1), we can quickly isolate and extract the target data:
{{{
# 2. Parse columns containing GC content and Genome size.
foreach my $entry (@DATA)
{	my @data = split('</td><td ', $entry);
	$data[0] =~ m/>(.+)<\/a>$/;
	my $organism = $1;
	$data[4] =~ m/([\d\.]+)$/;
	$Genomes{$organism}{'size'} = $1;
	$data[6] =~ m/>([\d\.]+)/;
	$Genomes{$organism}{'gc'} = $1;	
}
}}}



!

[[< Back|HTMLread-02]]|[[Return to Lecture Index|Lecture Index]]
!HTML Files:
Here's an agressive HTML parsing script that accomplishes the following goals:
#          Parse htlm for genom size and GC content
#          Run an R script to plot the data
#          Generate an HTML report with embedded plots

The input HTML Table  is here: [[GenBankData-110302.html|01/GenBankData-110302.html]].
The R script that is called by the program is here: [[ 02-PLOT-Size-GC.R|01/02-PLOT-Size-GC.R]]
Example output is here: [[ResultsPlot.html|01/ResultsPlot.html]]

{{{
#!/usr/bin/perl
use strict;

# - - - - - H E A D E R - - - - - - - - - - - - - - - - -
# Goal: 
#          1. Parse htlm for genom size and GC content
#          2. Run an R script to plot the data
#          3. Generate an HTML report with embedded plots
# MAST698-2013

# - - - - - U S E R    V A R I A B L E S - - - - - - - -
my $infile   = "GenBankData-110302.html";
my $folder   = "00-Data";
my $outfile  = "GenomeSizeGC-data.txt";
my $htmlfile = "ResultsPlot.html";

# - - - - - G L O B A L  V A R I A B L E S  - - - - - -
my %Genomes;

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# - - - - - M A I N - - - - - - - - - - - - - - - - - - - -
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
print "\n\nThere must be some way out of here . . . \n";

# 1. Load the file.
my $folderin_file = $folder ."/". $infile;
$/='tr bgcolor=';
open(IN, "<$folderin_file") or die "\n\nNADA $folderin_file you FOOL!!!\n\n";
my @DATA = <IN>;
close(IN);
print "\n\n$folderin_file opened with ", $#DATA + 1," lines input to memory.\n\n";
shift(@DATA);
shift(@DATA);


# 2. Parse columns containing GC content and Genome size.
my $count = 10000;
foreach my $entry (@DATA)
{	my @data = split('</td><td ', $entry);
	$data[0] =~ m/>(.+)<\/a>$/;
	my $organism = $1;
	$data[4] =~ m/([\d\.]+)$/;
	my $size = $1;
	$data[5] =~ m/>([\d\.]+)/;
	my $gc = $1;
	if ($size > 0 && $gc > 0)
	{	$Genomes{$organism}{'size'} = $size;
		$Genomes{$organism}{'gc'}    = $gc;
	}
}


# 3. Print DATA output file . . . . .
open(OUT,">$outfile");
print OUT "Genome\tSIZE\tGC\n";
foreach my $genome (keys %Genomes)
{	print OUT "$genome\t$Genomes{$genome}{'size'}\t$Genomes{$genome}{'gc'}\n"; }
close(OUT);

#-------------------------------------------------------
# 4. Run R Analysis Script . . . . .
system('R --vanilla <02-PLOT-Size-GC.R');
#-------------------------------------------------------

# 5. Print HTML Report . . . . . . . . . . . . . . . . .  
open(OUT,">$htmlfile");
print OUT "<html>\n<title>Genome Profiles</title>\n<body>\n";
print OUT "Data for free-living microbial genomes were obtained from file <b>\"$infile\"</b>.<br><br>";
print OUT "A parsing srcipt was used to extract the genome size and %GC content observations, and then \n";
print OUT "this information is presented below.<br><br>\n";
print OUT "Distribution profiles for Genome Size and %GC in the data set.<br>\n";
print OUT "<table><tr><td><img src=\"PLOT-Fig1-SIZE.jpg\" style=\"height:300px\"></td><td><img src=\"PLOT-Fig2-GC.jpg\" style=\"height:300px\"></td></tr></table><br>\n";
print OUT "<br><b>Correlation SIZE vs. GC Content</b><br>\n";
print OUT "<img src=\"PLOT-Fig3-SIZEvsGC.jpg\" style=\"height:500px\"><br><hr>\n";
print OUT "</body>\n</html>\n";
close(OUT);

print "\n\n\n* * * *   D O N E   * * * *\n\n";

# - - - - - EOF - - - - - - - - - - - - - - - - - - - - - -
}}}


!
[[<BACK|CodeWork]]
!Down Load Data Text File

The text file for the ~HW03 Assignment [[(see CodeWork)|CodeWork]] uses a tab-delimited data file that is hyper-linked in the instruction page. 

# Click on the link and wait for the text file to be displayed in your browser in a new window.
# Use the "SELECT ALL" command in the browser window to make all the text active.
# Use the COPY command to load the active selected text into memory.
# Open a new blank file in Komodo Edit.
# Use the PASTE command to insert all the text from memory into the Komodo file (and remember that Komodo is just an intelligent text editor).
# Here's the only tricky part -- we need to make sure that the HTML transfer didn't screw with the terminal line break characters in the text:
## From the Komodo Main Menu, Select EDIT command options
## At the bottom of the options select "Current File Settings . . . "
## In the "File Settings" box:
### make sure that LINE ENDINGS are set to the "UNIX (\n)" option
### make sure that PRESERVE LINE ENDINGS is unchecked
# Now save the text file with the appropriate file name.
# Close the text window in Komodo
# DONE

!

 

!
/***
|Name:|HideWhenPlugin|
|Description:|Allows conditional inclusion/exclusion in templates|
|Version:|3.1 ($Rev: 3919 $)|
|Date:|$Date: 2008-03-13 02:03:12 +1000 (Thu, 13 Mar 2008) $|
|Source:|http://mptw.tiddlyspot.com/#HideWhenPlugin|
|Author:|Simon Baird <simon.baird@gmail.com>|
|License:|http://mptw.tiddlyspot.com/#TheBSDLicense|
For use in ViewTemplate and EditTemplate. Example usage:
{{{<div macro="showWhenTagged Task">[[TaskToolbar]]</div>}}}
{{{<div macro="showWhen tiddler.modifier == 'BartSimpson'"><img src="bart.gif"/></div>}}}
***/
//{{{

window.hideWhenLastTest = false;

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


merge(config.macros,{

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

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

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

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

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

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

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

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

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

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

	hideWhenTitleIs: { handler: function(place,macroName,params,wikifier,paramString,tiddler) {
		removeElementWhen( tiddler.title == params[0], place);
	}},

	showWhenTitleIs: { handler: function(place,macroName,params,wikifier,paramString,tiddler) {
		removeElementWhen( tiddler.title != params[0], place);
	}},

	'else': { handler: function(place,macroName,params,wikifier,paramString,tiddler) {
		removeElementWhen( !window.hideWhenLastTest, place);
	}}

});

//}}}

{{{
<html><div style="color: rgb(100, 100, 150); font-family: Monaco;"><big><b>
abcdefghijklmnopqrstuvwxyz
</html>
}}}
/***
|''Name:''|HistoryPlugin|
|''Description:''|Limits to only one tiddler open. Manages an history stack and provides macro to navigate in this history (<<history>><<back>><<forward>>).|
|''Version:''|1.0.0|
|''Date:''|2008-03-23|
|''Source:''|http://tiddlywiki.bidix.info/#HistoryPlugin|
|''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.3.0|
***/
//{{{
	Story.prototype.tiddlerHistory = [];
	Story.prototype.historyCurrentPos = -1;
	Story.prototype.currentTiddler = null;
	Story.prototype.maxPos = 11;

	Story.prototype.old_history_displayTiddler = Story.prototype.displayTiddler;
	Story.prototype.displayTiddler = function(srcElement,title,template,animate,slowly)
	{
		title = ((typeof title === "string") ? title : title.title);
		//SinglePageMode
		if (this.currentTiddler) this.closeTiddler(this.currentTiddler);
		if (template == 2) {
			//switch to Edit mode : don't manage
			story.old_history_displayTiddler(null,title,template,animate,slowly);
			return; 
		}
		// if same tiddler no change
		if (this.tiddlerHistory[this.historyCurrentPos] == title) {
			this.currentTiddler = title;
			story.old_history_displayTiddler(null,title,template,animate,slowly);
			return;
		}
		if (this.historyCurrentPos == this.tiddlerHistory.length -1) {
			// bottom of stack
	    	this.tiddlerHistory.push(title);
		   	if (this.tiddlerHistory.length > 11) {
	                 this.tiddlerHistory.shift();
	       	} else {
		    this.historyCurrentPos += 1;
	            }

		} else {
			// middle of stack
		    this.historyCurrentPos += 1;
			if (this.tiddlerHistory[this.historyCurrentPos] != title) {
				// path change => cut history
				this.tiddlerHistory[this.historyCurrentPos] = title;
				var a = [];
				for(var i = 0; i <= this.historyCurrentPos;i++) {
					a[i] = this.tiddlerHistory[i];
				}
				this.tiddlerHistory = a;
			}
		}
		this.currentTiddler = title;
		story.old_history_displayTiddler(null,title,template,animate,true);
	        scrollTo(0, 1);
	}

	Story.prototype.old_history_closeTiddler = Story.prototype.closeTiddler;
	Story.prototype.closeTiddler = function(title,animate,slowly)
	{
		this.currentTiddler = null;
	    story.old_history_closeTiddler.apply(this,arguments);
	}

	config.macros.history = {};
	config.macros.history.action = function(event) {
	var popup = Popup.create(this);
		if(popup)
			{
	        if (!story.tiddlerHistory.length)
	            createTiddlyText(popup,"No history");
	        else
	           {
	           var c = story.tiddlerHistory.length;
			   for (i=0; i<c;i++ )
	               {
					var elmt = createTiddlyElement(popup,"li");
				   	var btn = createTiddlyButton(elmt,story.tiddlerHistory[i],story.tiddlerHistory[i],config.macros.history.onClick);
					btn.setAttribute("historyPos",i);
			       }
	           }
	        }
		Popup.show(popup,false);
		event.cancelBubble = true;
		if (event.stopPropagation) event.stopPropagation();
		return false;
	}
	config.macros.history.handler = function(place,macroName,params)
	{
		createTiddlyButton(place, 'history', 'history', config.macros.history.action);
	}

	config.macros.history.onClick = function(ev)
	{
		var e = ev ? ev : window.event;
		var historyPos = this.getAttribute("historyPos");
		story.historyCurrentPos = historyPos -1;
		story.displayTiddler(null,story.tiddlerHistory[historyPos]);
		return false;
	};

	config.macros.back = {};
	config.macros.back.action = function() {
	       if (story.historyCurrentPos > 0) {
				if (story.currentTiddler) story.closeTiddler(story.currentTiddler);
				story.historyCurrentPos = story.historyCurrentPos -2;
				story.displayTiddler(null,story.tiddlerHistory[story.historyCurrentPos+1]);
			} else {
				//if (story.currentTiddler) story.old_history_displayTiddler(null,story.currentTiddler);
				};
		return false;
	}
	config.macros.back.handler = function(place,macroName,params)
	{
		createTiddlyButton(place, '<<', 'back', config.macros.back.action,"backButton");
	}

	config.macros.forward = {};
	config.macros.forward.action = function() {
	       if (story.historyCurrentPos < story.tiddlerHistory.length -1) {
				if (story.currentTiddler) story.closeTiddler(story.currentTiddler);
				//story.historyCurrentPos = story.historyCurrentPos;
				story.displayTiddler(null,story.tiddlerHistory[story.historyCurrentPos+1]);
			} else {
				//if (story.currentTiddler) story.old_history_displayTiddler(null,story.currentTiddler);
			}
		return false;
	}
	config.macros.forward.handler = function(place,macroName,params)
	{
		createTiddlyButton(place, '>>', 'forward', config.macros.forward.action, "ibutton");
	}
//}}}
!~TicTacToe 4x4 

__''Objective:''__ //Edit 3x3 game code for a 4x4 game board.//

__''Rationale:''__ Exercise in editing existing code block to re-tool for a slightly different application. Identify the variables that determine grid layout and edit them.

!!Hint:
If you need a little help altering the cell print format so that the columns remain aligned on a 4x4 grid, here's one way to do it:

{{{
		foreach my $col (0..3)
		{	my $cellblock = "|__$cell[$pos]__";
		 
			if ($pos < 10)
			{	$cellblock = "|___$cell[$pos]__";}
			
			if ($pos >= 10 && $cell[$pos] =~ /[XO]/)
			{	$cellblock = "|___$cell[$pos]__";}
			
			print $cellblock;
			$pos = $pos + 1;
		}
}}}


!!Working Code:
A script that takes a grid size as input to draw different game boards is here: [[Grid NxN|TicTacToe-08]]

!
!WINNER
Flow Chart of logic structure for WINNER subroutine of [[TicTacToe|Mechanics-06]] code. 

__''Objective:''__ //Identify the logic flow within a code block and diagram how information flows.//

__''Rationale:''__ Before you can start to write code, you have to have a clear idea of the computational tasks/steps that must be accomplished. Flow charts can serve as that outline, although any standard outlining technique can work. Regardless of how you represent the steps of the program, you have to understand what those steps are before you can start typing out code.


<html><table>
<tr>
<td><img src="01/HW02/01.png" style="height:250px"></td>
<td><img src="01/HW02/06.png" style="height:250px"></td>
</tr>
<tr>
<td><img src="01/HW02/02.png" style="height:400px"></td>
<td><img src="01/HW02/03.png" style="height:400px"></td>
</tr>
<tr>
<td><img src="01/HW02/04.png" style="height:400px"></td>
<td><img src="01/HW02/05.png" style="height:400px"></td>
</tr>
</table></html>

!
!Plot of SORTED results:
Results of sorting routine from [[01c-SORT.pl|Sorting-10]] code. 

__''Objective:''__ //Sort and large series of numbers and then using a plotting result to view the results.//

__''Rationale:''__ Often bioinformatics problems deal with such large data sets that it is impossible for the user to read through all the results and digest them into an answer or conclusion. Being able to distill your informatics information into some form of numerical plot can provide a mechanism for rapidly scanning 'how your program worked.'

<html><table>
<tr>
<td><img src="01/HW03/01.png" style="height:250px"></td>
<td><img src="01/HW03/06.png" style="height:250px"></td>
</tr>
<tr>
<td><img src="01/HW03/02.png" style="height:250px"></td>
<td><img src="01/HW03/03.png" style="height:250px"></td>
</tr>
<tr>
<td><img src="01/HW03/04.png" style="height:250px"></td>
<td><img src="01/HW03/05.png" style="height:250px"></td>
</tr>
</table></html>

!
!Plot of NEW VARIABLE:
Results of sorting routine from [[01f-SORT.pl|Sorting-10]] code. 

__''Objective:''__ //Calculate a new variable from the input data and plot.//

__''Rationale:''__ Need to be able to generate //de novo// calculations/metrics during any kind of bioinformatic analysis. That NEW information needs to be organized and processed just as the original input data needs to be. Usually, this requires developing an output table structure that can be used for subsequent statistical analyses.
/%
<html><table>
<tr>
<td><img src="01/HW03/01.png" style="height:250px"></td>
<td><img src="01/HW03/06.png" style="height:250px"></td>
</tr>
<tr>
<td><img src="01/HW03/02.png" style="height:250px"></td>
<td><img src="01/HW03/03.png" style="height:250px"></td>
</tr>
<tr>
<td><img src="01/HW03/04.png" style="height:250px"></td>
<td><img src="01/HW03/05.png" style="height:250px"></td>
</tr>
</table></html>
%/

<html><img src="01/HW04/zhang-04b2-MEANDIST.png" style="height:600px"></html>
!Parse & Analyze:

__''Objective:''__ //Extract GC and Optimum Growth Temperature (Topt) data for microbial genomes from this NCBI data table ([[GenBankData-110302.html|01/GenBankData-110302.html]]) and analyze for any relationship between these two variables.//

__''Rationale:''__ We assume that there should be a relationship between environmental growth temperature and genome GC content, because genomes with higher %GC levels will (theoretically) be more stable at higher temperatures.

* An R script is provided for the analysis tasks: [[ 02-PLOT-Size-GC.R|01/02-PLOT-Size-GC.R]]
* Use the HTML parser code as the basis for utilizing a pipeline approach so just one script does:
**  the data extraction
** variable calculations
** writes new data table to file
** calls the R script to do the anlayses/plots
** generates a formatted HTML report to integrate the run data

!!Example Answer
In this example, the student filtered out the 37 C observations from the data set because there were so many of them that it highly impacted the GC vs. Topt analysis. Most of the 37 C bugs are human host-associated. 
<html><img src="07/screenshot_hw05-WZ.png" style="height:600px"></html>


!
!Directed Evolution:

__''Objective:''__ //Assess the relationship between the probability of randomly generating the amino acid sequence of a protein and the number of possible protein amino acids.//

__''Rationale:''__ Evolution appears to work against enormous odds in generating complexity in living systems. In this simple exercise, you will be taking a small look at what those odds may be, or more exactly, assessing if different genes/proteins within a genome have different odds of random fixation. 

* Choose a NT fasta file for a microbial genome out of the folder: /home/marsh/99-mast697/02-Genomes
* Implement a script to translate NTs into AA seqs
* Implement a directed evolution (monkeys) iteration to count the iterative cycles necessary to fix the AA sequence of each gene in that genome
* The R script file will generate two plots. Submit a word document with those plots and a 1 paragraph discussion describing your results. 

!!Hint:
You can get a copy of a microbial genome NT fasta file by using a terminal command:
{{{ prompt> cp /home/marsh/99-mast697/02-Genomes/<GENOMENAME>/<FASTAFILENAME> ./ }}}
where <GENOMENAME> and <FASTAFILENAME> are replaced with the targets that you want to copy.  

!!Example Answer



!
[[<Back|BoneYard]]
!Protein Isoelcetric Point

{{{
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
sub IsoElectricPoint
{	print "   Protein isoelectric point . . . \n";
	my $GenDict = $_[0];
	foreach my $id (keys %{$GenDict})
	{	my $N      = length(${$GenDict}{$id}{'aaseq'});
		my $pH     = 6.5;           # starting point pI = 6.5 - theoretically it should be 7, but
		my $pHlow  = 0.0;
		my $pHhigh = 14.0;  
		my $std    = 0.01;          # [pI = pH ± std]
		my $temp   = 0.0;
		(my $QN1, my $QN2, my $QN3, my $QN4, my $QN5, my $QP1, my $QP2, my $QP3, my $QP4, my $NQ) = (0,0,0,0,0,0,0,0,0,0);
		my $SOLVED = 0;
		my $looper = 0;
		while($SOLVED == 0)
		{	# 1. Calculate charge balance coefficient $NQ . . . . . .   
			$QN1 = -1/(1+10**(3.65-$pH));                                        
			$QN2 = (-1 * ${$GenDict}{$id}{'AAfreq'}{'pD'} * $N)/(1+10**(3.90-$pH));           
			$QN3 = (-1 * ${$GenDict}{$id}{'AAfreq'}{'pE'} * $N)/(1+10**(4.07-$pH));           
			$QN4 = (-1 * ${$GenDict}{$id}{'AAfreq'}{'pC'} * $N)/(1+10**(8.18-$pH));           
			$QN5 = (-1 * ${$GenDict}{$id}{'AAfreq'}{'pY'} * $N)/(1+10**(10.46-$pH));        
			$QP1 = (+1 * ${$GenDict}{$id}{'AAfreq'}{'pH'} * $N)/(1+10**($pH-6.040));            
			$QP2 = 1/(1+10**($pH-8.2));                
			$QP3 = (+1 * ${$GenDict}{$id}{'AAfreq'}{'pK'} * $N)/(1+10**($pH-10.54));           
			$QP4 = (+1 * ${$GenDict}{$id}{'AAfreq'}{'pR'} * $N)/(1+10**($pH-12.48));            
			$NQ = $QN1+$QN2+$QN3+$QN4+$QN5+$QP1+$QP2+$QP3+$QP4;
			
			# 2. Iteratively adjust pH value . . . . . . . .  .
			if ($NQ < 0)              # out of range, thus the new pH value must be smaller    
			{  $temp = $pH;
				$pH = $pH-(($pH-$pHlow)/2);
				$pHhigh = $temp;
			}
			else                      # pH value is too low, needs to be increased
			{   $temp = $pH;
				$pH = $pH + (($pHhigh-$pH)/2);
				$pHlow = $temp;
			}
			
			# 3. Check/Monitor progress . . . . . . . . . . . . . . . .  .. . .. 
			# Error, so stop trying to calculate, exit for loop
			if ($pH >= 14)
			{	${$GenDict}{$id}{'IEP'} = 'NA';
				$SOLVED = -1;
			} 
			# Iterative Solution: terminal condition, isoelectric point is within the given precision $std
			if (($pH-$pHlow < $std) && ($pHhigh-$pH < $std)) 
			{	${$GenDict}{$id}{'IEP'} = &RoundOff($pH, 3);
				$SOLVED = 1;
			}
			# Deadman switch to stop infinite loop . . . .
			if ($looper == 1000)
			{	${$GenDict}{$id}{'IEP'} = 'NA';
				$SOLVED = -1;
			}
			else
			{	$looper += 1; }
		} # end while loop . . . . . . . 
		# &DUMP(${$GenDict}{$id}{'IEP'});
	} # end foreach gene loop . . . . . . . . .. .  . .
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
}}}
<!--{{{-->
<div class='toolbar' macro='toolbar closeTiddler closeOthers +editTiddler > fields syncing permalink references jump'></div>
<div class='INTRO' macro='tiddler INTROSubtopicMenu'></div>
<div class='title' macro='view title'></div>
<div class='viewer' macro='view text wikified'></div><div class='tagClear'></div>
<!--}}}-->
{{{
<html><img src="00/xxxx.png" style="height:300px"></html>
}}}

{{{
<html><table><tr>
<td><img src="00/xxxx.png" style="height:300px"></td>
<td><img src="00/xxxx.png" style="height:300px"></td>
</tr></table></html>
}}}
/***
|Name|InlineJavascriptPlugin|
|Source|http://www.TiddlyTools.com/#InlineJavascriptPlugin|
|Documentation|http://www.TiddlyTools.com/#InlineJavascriptPluginInfo|
|Version|1.9.2|
|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||
|Description|Insert Javascript executable code directly into your tiddler content.|
''Call directly into TW core utility routines, define new functions, calculate values, add dynamically-generated TiddlyWiki-formatted output'' into tiddler content, or perform any other programmatic actions each time the tiddler is rendered.
!!!!!Documentation
>see [[InlineJavascriptPluginInfo]]
!!!!!Revisions
<<<
2008.03.03 [1.9.2] corrected declaration of wikifyPlainText() for 'TW 2.1.x compatibility fallback' (fixes Safari "parse error")
2008.02.23 [1.9.1] in onclick function, use string instead of array for 'bufferedHTML' attribute on link element (fixes IE errors)
2008.02.21 [1.9.0] 'onclick' scripts now allow returned text (or document.write() calls) to be wikified into a span that immediately follows the onclick link.  Also, added default 'return false' handling if no return value provided (prevents HREF from being triggered -- return TRUE to allow HREF to be processed).  Thanks to Xavier Verges for suggestion and preliminary code.
|please see [[InlineJavascriptPluginInfo]] for additional revision details|
2005.11.08 [1.0.0] initial release
<<<
!!!!!Code
***/
//{{{
version.extensions.inlineJavascript= {major: 1, minor: 9, revision: 2, date: new Date(2008,3,3)};

config.formatters.push( {
	name: "inlineJavascript",
	match: "\\<script",
	lookahead: "\\<script(?: src=\\\"((?:.|\\n)*?)\\\")?(?: label=\\\"((?:.|\\n)*?)\\\")?(?: title=\\\"((?:.|\\n)*?)\\\")?(?: key=\\\"((?:.|\\n)*?)\\\")?( show)?\\>((?:.|\\n)*?)\\</script\\>",

	handler: function(w) {
		var lookaheadRegExp = new RegExp(this.lookahead,"mg");
		lookaheadRegExp.lastIndex = w.matchStart;
		var lookaheadMatch = lookaheadRegExp.exec(w.source)
		if(lookaheadMatch && lookaheadMatch.index == w.matchStart) {
			var src=lookaheadMatch[1];
			var label=lookaheadMatch[2];
			var tip=lookaheadMatch[3];
			var key=lookaheadMatch[4];
			var show=lookaheadMatch[5];
			var code=lookaheadMatch[6];
			if (src) { // load a script library
				// make script tag, set src, add to body to execute, then remove for cleanup
				var script = document.createElement("script"); script.src = src;
				document.body.appendChild(script); document.body.removeChild(script);
			}
			if (code) { // there is script code
				if (show) // show inline script code in tiddler output
					wikify("{{{\n"+lookaheadMatch[0]+"\n}}}\n",w.output);
				if (label) { // create a link to an 'onclick' script
					// add a link, define click handler, save code in link (pass 'place'), set link attributes
					var link=createTiddlyElement(w.output,"a",null,"tiddlyLinkExisting",wikifyPlainText(label));
					var fixup=code.replace(/document.write\s*\(/gi,'place.bufferedHTML+=(');
					link.code="function _out(place){"+fixup+"\n};_out(this);"
					link.tiddler=w.tiddler;
					link.onclick=function(){
						this.bufferedHTML="";
						try{ var r=eval(this.code);
							if(this.bufferedHTML.length || (typeof(r)==="string")&&r.length)
								var s=this.parentNode.insertBefore(document.createElement("span"),this.nextSibling);
							if(this.bufferedHTML.length)
								s.innerHTML=this.bufferedHTML;
							if((typeof(r)==="string")&&r.length) {
								wikify(r,s,null,this.tiddler);
								return false;
							} else return r!==undefined?r:false;
						} catch(e){alert(e.description||e.toString());return false;}
					};
					link.setAttribute("title",tip||"");
					var URIcode='javascript:void(eval(decodeURIComponent(%22(function(){try{';
					URIcode+=encodeURIComponent(encodeURIComponent(code.replace(/\n/g,' ')));
					URIcode+='}catch(e){alert(e.description||e.toString())}})()%22)))';
					link.setAttribute("href",URIcode);
					link.style.cursor="pointer";
					if (key) link.accessKey=key.substr(0,1); // single character only
				}
				else { // run inline script code
					var fixup=code.replace(/document.write\s*\(/gi,'place.innerHTML+=(');
					var code="function _out(place){"+fixup+"\n};_out(w.output);"
					try { var out=eval(code); } catch(e) { out=e.description?e.description:e.toString(); }
					if (out && out.length) wikify(out,w.output,w.highlightRegExp,w.tiddler);
				}
			}
			w.nextMatch = lookaheadMatch.index + lookaheadMatch[0].length;
		}
	}
} )
//}}}

// // Backward-compatibility for TW2.1.x and earlier
//{{{
if (typeof(wikifyPlainText)=="undefined") window.wikifyPlainText=function(text,limit,tiddler) {
	if(limit > 0) text = text.substr(0,limit);
	var wikifier = new Wikifier(text,formatter,null,tiddler);
	return wikifier.wikifyPlain();
}
//}}}
!Basic instructions
#Download the file to your hard drive by [[right-clicking and saving the link / target as...|webviewtw.html]] to the filename and location of your choice. Close this page and open your new file.
#Replace the title in the upper left by editing MainMenu.
#Add topics to MainMenu. Click on those topics to create the tiddlers for those topics. To your uninitiated web viewers they will appear to be separate webpages, but you and I know better!
#Edit DefaultTiddlers to include the names of the tiddlers that you want to appear when the ~TiddlyWiki is opened.
#If you want different colorpalettes than the ones provided, check [[here|http://www.giffmex.org/webviewtwexample.html#MoreColorPalettes!]] for more. Just import them from that file to this file.
#If you want to temporarily suspend the single-page-only feature, I recommend the toggle singlepage mode bookmarklet from ~TiddlyTools [[(link here)|http://www.tiddlytools.com/#InstantBookmarklets.]]
#Upload to your site using the UploadPlugin. [[Instructions here|http://www.giffmex.org/twfortherestofus.html#%5B%5BSimple%20instructions%20for%20BidiX's%20UploadPlugin%5D%5D]]
[[<Back to Lecture|Babel02]]
!!!
<html><img src="01/Borges-Google.jpg" style="height:400px"></html>
^^Google Images^^

Borges was a writer and philosopher with a large interest in classical theology and mathematics. But his day job was as a librarian and in this 1941 essay one can see a very well developed day-dream of his as he roamed the book stacks of the Argentine National Library in Buenos Ares. 

[[Borges' essay: Library of Babel|01/Borges-LibraryBabel.pdf]]
!Lecture 01
<html>
<div style="color: rgb(100, 100, 150); font-family: Monaco;">
<big><big>
<b>PERL</b><br>
</big>
<i>"Practical Extraction Report Language"</i>
</html>
# Basic Setup: [[Starting PERL|L01.01]]
# What is a PERL script: [[bare skeleton|L01.02]]
# [[Simple Sorting Code|L01.1]] 
# [[Sort Code Screen output|L01.2]]
# [[Swap Code Bloc|L01.3]]
# [[Revised Sort Code Logic|L01.4]]
!
<html>
<div style="color: rgb(100, 100, 150); font-family: Monaco;"><big><b>
Index of Weekly Lecture Topics 
</html>

!Bioinformatic Discussions
# [[Ground Zero: TicTacToe Coding|TicTacToe-01]]
# [[Code Mechanics: Algorithms|Mechanics-01]]
** [[TicTacToe Winner|TicTacToe Winner 01]]
** [[TicTacToe Autoplay|TicTacToe CPU Players]]
** [[TicTacToe Iterate|TicTacToe BootStrap]]
** [[TicTacToe Calculate|TicTacToe SuperBowl]]
# Sorting Lists
** [[Simple Sort, Part 1|Sorting-01]]
** [[Simple Sort, Part 2|Sorting-06]] >> File IO
** [[Simple Sort, Part 3|Sorting-11]] >> R stats; Dictionaries
# [[Recombinatorial Diversity|Babel-01]]
# [[Information Content/Complexity|Complexity00]]
# [[Recombinometrics & Entropy|Entropy-01]] 
# [[FASTA bioinformatic analysis|FastaAnalyze-01]] >> Sequence processing and analysis
# [[FASTA REGEX search & analysis|REGEX-01]] >> finding motifs
# [[Information Content/Complexity|Complexity00]]
# [[HTML read/parse|HTMLread-01]] >> ''$/'' = input break character
# [[Working with FASTA Files|FastaRead-01]] >> Sequence reading and analysis
# [[Sequence Alignments|BLAST-01]]
/%
!Project Discussions
# Grzymski: [[Nitrogen Cost Minimization|Nitrogen Cost Minimization 01]]
| Genome | GOS Representation | Dominant Location |
| Synechococcus ~WH8109 | 3.8x | more abundant in coastal samples |
| Prochlorococcus ~AS9601 | 3.5x | more abundant in open ocean samples |

!!!Reference Info from ~MAST697
# [[Simple Sort, Part 1|Sorting-01]]
# [[Simple Sort, Part 2|Sorting-06]] >> File IO
# [[Simple Sort, Part 3|Sorting-11]] >> R stats; Dictionaries

# [[FASTA bioinformatic analysis|FastaAnalyze-01]] >> Sequence processing and analysis
# [[FASTA REGEX search & analysis|REGEX-01]] >> finding motifs
# [[Recombinometrics & Entropy|Entropy-01]] 
%/
!!
/***
|''Name:''|LegacyStrikeThroughPlugin|
|''Description:''|Support for legacy (pre 2.1) strike through formatting|
|''Version:''|1.0.2|
|''Date:''|Jul 21, 2006|
|''Source:''|http://www.tiddlywiki.com/#LegacyStrikeThroughPlugin|
|''Author:''|MartinBudden (mjbudden (at) gmail (dot) com)|
|''License:''|[[BSD open source license]]|
|''CoreVersion:''|2.1.0|
***/

//{{{
// Ensure that the LegacyStrikeThrough Plugin is only installed once.
if(!version.extensions.LegacyStrikeThroughPlugin) {
version.extensions.LegacyStrikeThroughPlugin = {installed:true};

config.formatters.push(
{
	name: "legacyStrikeByChar",
	match: "==",
	termRegExp: /(==)/mg,
	element: "strike",
	handler: config.formatterHelpers.createElementAndWikify
});

} //# end of "install only once"
//}}}
[[<Back to Lecture|Babel02]]
!Recombinatorial Diversity

Borges was a writer and philosopher with a large interest in classical theology and mathematics. But his day job was as a librarian and in this 1941 essay one can see a very well developed day-dream of his as he roamed the book stacks of the Argentine National Library in Buenos Ares. 
[[Borges' essay: Library of Babel|01/Borges-LibraryBabel.pdf]]



!!!Borges
http://en.wikipedia.org/wiki/Jorge_Luis_Borges
''Jorge Francisco Isidoro Luis Borges'' (24 August 1899 – 14 June 1986) was an Argentine writer born on 24 August 1899 in Buenos Aires, Argentina. He was brought up bilingual in Spanish and English. In 1914 his family moved to Switzerland where he attended school, then traveled around Spain. On return to Argentina in 1921, Borges began his career as a writer with the publication of poems and essays in Surrealism literary journals. He worked as a librarian, suffering political persecution at the hands of the Peron administration. He then became a public lecturer.

Due to a hereditary condition, Borges became blind in his late fifties. In 1955 he was appointed director of the National Public Library (Biblioteca Nacional) and professor of Literature at the University of Buenos Aires. In 1961 he came to international attention when he received the first International Publishers' Prize Prix Formentor. His work was translated and published widely in the United States and in Europe. He died in Geneva, Switzerland, in 1986.

!!!Theology and Geometry
http://en.wikipedia.org/wiki/Combinatorics
''Combinatorics'' is a branch of pure mathematics concerning the study of discrete (and usually finite) objects. It is related to many other areas of mathematics, such as algebra, probability theory, ergodic theory and geometry, as well as to applied subjects in computer science and statistical physics. Aspects of combinatorics include "counting" the objects satisfying certain criteria (enumerative combinatorics), deciding when the criteria can be met, and constructing and analyzing objects meeting the criteria (as in combinatorial designs and matroid theory), finding "largest", "smallest", or "optimal" objects (extremal combinatorics and combinatorial optimization), and finding algebraic structures these objects may have (algebraic combinatorics).

Combinatorics is as much about problem solving as theory building, though it has developed powerful theoretical methods, especially since the later twentieth century. One of the oldest and most accessible parts of combinatorics is graph theory, which also has numerous natural connections to other areas. Combinatorics is used frequently in computer science to obtain estimates on the number of elements of certain sets. 
!!!
!!!
[[BACK to Working Code|BoneYard]]
!!!
!Load Codon Table for Translation:
There are many codon translation tables that [[GenBank|http://www.ncbi.nlm.nih.gov/Taxonomy/Utils/wprintgc.cgi?mode=c#SG1]] currently has on file. This subroutine uses the standard Eukaryote/Bacteria set. 

{{{
    # Declare this global HASH array:
          my %CodonTable;

    # Call the subroutine with:
	&LoadCodonTable();

#------------------------------------------------------------
sub LoadCodonTable
{	my @bases = ('T', 'C', 'A', 'G');
	my @aa = split(//,"FFLLSSSSYY**CC*WLLLLPPPPHHQQRRRRIIIMTTTTNNKKSSRRVVVVAAAADDEEGGGG");
	foreach my $a (@bases)
	{	foreach my $b (@bases)
		{	foreach my $c (@bases)
			{	$CodonTable{$a.$b.$c}=shift(@aa); }
		}
	}

}
# http://www.ncbi.nlm.nih.gov/Taxonomy/Utils/wprintgc.cgi?mode=c#SG1
# > 1 Standard
# Amino  FFLLSSSSYY**CC*WLLLLPPPPHHQQRRRRIIIMTTTTNNKKSSRRVVVVAAAADDEEGGGG
# Base1  TTTTTTTTTTTTTTTTCCCCCCCCCCCCCCCCAAAAAAAAAAAAAAAAGGGGGGGGGGGGGGGG
# Base2  TTTTCCCCAAAAGGGGTTTTCCCCAAAAGGGGTTTTCCCCAAAAGGGGTTTTCCCCAAAAGGGG
# Base3  TCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAGTCAG
#------------------------------------------------------------
}}}
{{menubox2{MAST 697/497}}}{{menubox3{BIOINFO}}}
<<search>>
!OUTLINE:
[[FrontPage]]
[[1. What's New?|What's New?]]
[[2. Syllabus|Syllabus]]
[[3. Lectures|Lecture Index]]
[[4. Resources|Resource Index]]
[[5. Working Code|BoneYard]]
[[6. Assignments|CodeWork]]
!!
{{tuduSlider{<<slider chkToolbox Toolbox 'Toolbox »'>>}}}
!AGM Tools:
[[Setup|Welcome to the Webview TiddlyWiki]]
[[SubTopics|ConfigSubTopics]]
[[Insert Figure|InFig]]
[[Emphasis Text|TextMonaco]]
!!























<!--{{{-->
<link rel='alternate' type='application/rss+xml' title='RSS' href='index.xml'/>
<!--}}}-->

<style type="text/css">#contentWrapper {display:none;}</style><div id="SplashScreen" style="border: 3px solid #ccc; display: block; text-align: center; width: 320px; margin: 100px auto; padding: 50px; color:#000; font-size: 28px; font-family:Tahoma; background-color:#eee;"><b>LOADING</b>: <blink> ...</blink><br><br></div>
[[<Back to Code Index|BoneYard]]
!Mean, Median, Skew
This functions work by passing an array of values by reference:
Example:
@@{{{my $mean = MEAN(\@ARRAY);}}}@@
where @ARRAY is a list of the values for the calculation.
{{{
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
sub SKEWcalc                        # Requires the MEAN & MEDIAN subroutines . . 
{	my $array = $_[0];
	my $mean = &MEAN(\@{$array});
	my $median = &MEDIAN(\@{$array});
	# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
	my $skew = &RoundOff(200*($median - $mean)/($mean + $median), 3);
	# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
	return $skew;
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
sub MEAN                          # called by SKEW . . . . . . . . . . . . . . .
{	my $array = $_[0];
	my $N = scalar(@{$array});
	my $sum = 0;
	foreach my $data (@{$array})
	{	$sum += $data; }
	return &RoundOff($sum/$N, 4);
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
sub MEDIAN                        # called by SKEW . . . . . . . . . . . . . . .
{	my $array = $_[0];
	my $N = scalar(@{$array});
	my @SORT = sort{$a<=>$b}(@{$array});
	my $mid = int($N/2);
	return &RoundOff($SORT[$mid], 4);
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
}}}
[[< Back to Lectures|Lecture Index]]|[[Next>|Mechanics-02]]
!Code Mechanics:
We will return to the ''~TicTacToe'' code example from the previous lecture [[(code here)|TicTacToe-07]] to discuss the two operational levels in any script: 
## The __functional__ level of what the code does
## The __structural__ level of how the code works.
Example: {{{print("".(($line=join("",<>))=~s/.*\n/$h{$&}++?"":$&/ge,$line));}}}

!!!Function
# Algorithms - what are they? [[(GO)|Mechanics-02]]
# Adding a 'WINNER' routine [[(GO)|TicTacToe Winner 01]]

!!!Structure
# Code formatting [[(GO)|Formatting-01]]
# What makes good code FOR YOU:
## Consistency
## Clarity

!!!Running Code
# File permissions
# Current working folder


!
[[< Back|Mechanics-01]]|[[Next>|Mechanics-03]]
!Code Mechanics - Algorithms:
A series of logical decisions that are sequentially executed to reach a desired result. Often represented as flow charts with decision branch points. An algorithm is essentially a strategy for processing information. 
<html><img src="01/algorithm_flowchart_1.png" style="height:500px"></html>

!Game Algorithms:
What would a flow chart for playing ~TicTacToe look like? What information is processed and what decision points must be passed?
<html><img src="01/tictactoe.png" style="height:100px"></html>


!
[[< Back|Mechanics-02]]|[[Return To Lecture Index>|Lecture Index]]|[[TicTacToe Winner|TicTacToe Winner 01]]
!Code Mechanics: ~TicTacToe Board

The task of drawing a ~TicTacToe grid for two-person game play is a very simple algorithm. Now we are going to add another logic step to that algorithm in the form of a decision point to assess whether a winning stage has been reached:

<html><table><tr>
<td><img src="01/FlowChart1.pptx.png" style="height:400px"></td>
<td><img src="01/FlowChart2.pptx.png" style="height:400px"></td>
</tr></table></html>

By imposing a WINNER DECLARATION function, we are essentially establishing an algorithm to control the 'flow' of the game. The first coding assignment [[see Assignments|CodeWork]] utilizes this flow control expansion to:
* Allow the script to declare a winner with a full row, col, diag
* Allow for 2 virtual players to play by making random moves
* Iterate, tracking winners, and calculate:
** probability of winning when moving first
** probability of winning when moving second
** probability of winning when first move is in an outside corner
** probability of winning when second move is in center

!
<!--{{{-->
<div class='toolbar' macro='toolbar closeTiddler closeOthers +editTiddler > fields syncing permalink references jump'></div>
<div class='MicroGen' macro='tiddler MicroGenSubtopicMenu'></div><div class='title' macro='view title'></div>
<div class='viewer' macro='view text wikified'></div><div class='tagClear'></div>
<!--}}}-->
[[<BACK|ShakespearesMonkeys]] | [[NEXT>|GA-01]]
!Alphabet Soup

Using a 52 letter character set (upper and lower case), with 100 bootstrap iterations at each length, there is a significant positive correlation between the number of characters in the sequence and the Min, Mean and Max generation cycles or turns that were required for one random string to converge on another.  
!!!
<html><img src="08/00-DataPlot-ALL-ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz.png" style="height:400px"></html>
!!!
[[<Back to Discussion Index|Lecture Index]]|[[Next>|Nitrogen Cost Minimization 02]]
!Nitrogen Minimization

Reference: [[Grzymski-ISME|03-Grz/Grzymski-Ncost-minimization-ismej201172a.pdf]]

<html><img src="03-Grz/titlepage.png" style="height:500px"></html>
[[<Back|Nitrogen Cost Minimization 01]]|[[Next>|Nitrogen Cost Minimization 03]]
!Introduction

> Biosynthetic cost minimization in microorganisms is a reduction in amino-acid biosynthetic costs to maximize central metabolic costs.

> Thus, microorganisms generally first use amino acids with lower molecular weights and lower assimilation costs, especially in less critical protein domains (Barrai et al., 1995; Dufton, 1997).

> Here we show that in oligotrophic, open-ocean regions of low N or Fe, there is a preferential reduction in N side chains compared with carbon (C) in amino-acid sequences, with a concomitant increase in the average mass of proteins.

> These findings, . . . , suggest the importance of N limitation as a selective force on molecular evolution of codon usage and protein atomic composition in microorganisms that are well adapted to oligotrophic ocean conditions.

> In areas not impacted by significant N discharge, net N fixation is less than denitrification, causing the dissolved pool of inorganic nutrients in the ocean to be slightly enriched in P compared to N (Falkowski, 1997). 

> When ammonium is available, for example, the diazotroph Trichodesmium limits N fixation, saving B16 mol of ATP per mol of N2 fixed (Mulhol- land et al., 1999). Under N limitation, Prochlorococ- cus CCMP1986 ( 1⁄4 MED4) quickly downregulates N-rich translation proteins, which differs from the strategy employed by the MIT9313 strain (Gilbert and Fagan, 2010). Regardless of the individual nutrient acquisition and assimilatory strategy, the longer-term evolutionary strategy and selective pressure that time in low-nutrient environments exerts is for organisms that face even transient nutrient stress to minimize usage of those compounds in proteins. 

> We hypothesized the extent of N cost minimization to be pervasive in genomes of open-ocean microorgan- isms—proteins vital for survival in these oligotrophic conditions would be especially limited in N side- chain usage.
[[<Back|Nitrogen Cost Minimization 02]]|[[Next>|Nitrogen Cost Minimization 04]]
!Materials & Methods

* Marine Microbial Genomes
** Moore Foundation Marine Microbial Sequencing Project
** NCBI (National Center for Biotechnology Information = ne GenBank)
** PathoSystems Resource Integration Center (PATRIC)

* Environmental Data GOS

* Protein Atomic Composition
** ~Baudoin-Cornu "//S,N Bias in Genes//" : link [[BC-Science|03-Grz/Science-2001-Baudouin-Cornu-297-300.pdf]]
** ~Baudoin-Cornu "//Big Bias Theory//" : link [[BC-JBC|03-Grz/J.Biol.Chem.-2004-Baudouin-Cornu-5421-8.pdf]]

* Protein Atomic Composition: PATRIC vs. Moore

* Circos plots

* Distance from land calculation

* Overlapping Genomes

* Estimation of N requirements

!
[[<Back|Nitrogen Cost Minimization 03]]|[[Next>|Nitrogen Cost Minimization 05]]
!Nitrogen Costs

Usage of atomic Nitrogen in amino acid side chain groups:

<html><img src="03-Grz/AminoAcidStructures.jpg" style="height:900px"></html>


!
[[<Back|Nitrogen Cost Minimization 04]]|[[Next>|Nitrogen Cost Minimization 06]]
!Estimation of Nitrogen Requirements

!!!Equation 1: G~~i~~= GC content, S~~i~~= cell size, L~~i~~= genome size 
<html><img src="03-Grz/eq1.png" style="height:200px"></html>

!!!Other Equations: 
<html><img src="03-Grz/eqs.png" style="height:800px"></html>

!
[[<Back|Nitrogen Cost Minimization 05]]|[[Next>|Nitrogen Cost Minimization 07]]
!Estimation of Nitrogen Requirements

!Figure 2
<html><img src="03-Grz/fig1.png" style="height:800px"></html>

[[link to quantile summary|FastaAnalyze-03]]

!
[[<Back|Nitrogen Cost Minimization 06]]|[[Next>|Nitrogen Cost Minimization 08]]
!Estimation of Nitrogen Requirements

!Figure 3
<html><img src="03-Grz/fig2.png" style="height:400px"></html>

!
[[<Back|Nitrogen Cost Minimization 07]]|[[Next>|Nitrogen Cost Minimization 09]]
!Estimation of Nitrogen Requirements

!Figure 4
<html><img src="03-Grz/fig3.png" style="height:600px"></html>
Circular genome plots of //Prochlorococcus marinus// ecotypes. (a) Coding (gray) and non-coding regions (red 1⁄4 leading strand, blue 1⁄4 lagging strand) for the P. marinus ecotype MIT 9313. Additional data are available in Supplementary Tables S4 and S5c. Averaged nitrogen ARSC for each ORF is plotted as a colored bar graph, with green indicating high nitrogen ARSC and red indicating lower as in Materials and methods. 
!
[[<Back|Nitrogen Cost Minimization 08]]|[[Next>|Nitrogen Cost Minimization 10]]
!Conclusions
!!!First Point:
<html><img src="03-Grz/conclusion01.png" style="height:500px"></html>



!
[[<Back|Nitrogen Cost Minimization 09]]|[[Next>|Nitrogen Cost Minimization 11]]
!Conclusions
!!!Second Point:
<html><img src="03-Grz/conclusion02.png" style="height:500px"></html>



!
[[<Back|Nitrogen Cost Minimization 10]]|[[Next>|Nitrogen Cost Minimization 12]]
!Conclusions
!!!Third Point:
<html><img src="03-Grz/conclusion03.png" style="height:500px"></html>



!
[[<Back|Nitrogen Cost Minimization 11]]|[[Return to Index>|Nitrogen Cost Minimization 01]]
!Conclusions
!!!Fourth Point:
<html><img src="03-Grz/conclusion04.png" style="height:300px"></html>

 . . . and following discussion is a great summary of nutrient availability in open ocean ecosystems over the last 250 mya.


!
//{{{
config.options.chkSearchTitles=true;
config.options.chkSearchText=true;
config.options.chkSearchTags=true;
config.options.chkSearchFields=true;
config.options.chkSearchTitlesFirst=false;
config.options.chkSearchList=true;
config.options.chkSearchByDate=false;
config.options.chkSearchIncremental=true;
config.options.chkSearchShadows=false; 
//}}}
!PDF Resources

# Grzymski "//Nitrogen Cost Minimization//" : link [[Grzymski-ISME|03-Grz/Grzymski-Ncost-minimization-ismej201172a.pdf]]
# Raghaven "//GC Content Selection//" : link [[Raghaven-PNAS|biddle/PNAS-2012-Raghavan-14504-7.pdf]]
# ~Baudoin-Cornu "//S,N Bias in Genes//" : link [[BC-Science|03-Grz/Science-2001-Baudouin-Cornu-297-300.pdf]]
# ~Baudoin-Cornu "//Big Bias Theory//" : link [[BC-JBC|03-Grz/J.Biol.Chem.-2004-Baudouin-Cornu-5421-8.pdf]]
[[< Back to Resources|Resource Index]]
!What is PERL:
In computer programming, Perl is a high-level, general-purpose, interpreted, dynamic programming language. Perl was originally developed by Larry Wall, a linguist working as a systems administrator for NASA, in 1987, as a general purpose Unix scripting language to make @@ report processing easier.@@ The language provides powerful text processing facilities without the arbitrary data length limits of many contemporary Unix tools, making it the ideal language for manipulating text files. (from http://en.wikipedia.org/wiki/PERL)

Does your computer have PERL installed? All unix-type operating systems (Linux and OS X) have a PERL version installed by default. In contrast,  MS Windows verisons (2000, XP, Vista) do not.  You can check by opening a terminal window and at the command prompt (here just designated "prompt>") enter "perl -v" and hit <enter>:
{{{
prompt> perl -v
}}}
If PERL is installed, then you will get a brief summary of the current version index that is on your machine. If you need to install PERL, two common sources are listed below:

''PERL Sources:''
1. PERL Org - http://www.perl.org
<html><img src="00/perlorg.png" style="height:150px"></html>

2. For Windows (2000, XP, Vista): Active State - http://www.activestate.com/Products/activeperl/
<html><img src="00/activeperl.png" style="height:150px"></html>
''You will need the Windows x86 MSI file. Here is a local link to the current version available from Active state: [[EASY DOWNLOAD|00/ActivePerl-5.10.0.1003-MSWin32-x86-285500.msi]]
Full instructions for the install are described here: 

!

<!--{{{-->
<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>
<!--}}}-->
/***
|''Name:''|PasswordOptionPlugin|
|''Description:''|Extends TiddlyWiki options with non encrypted password option.|
|''Version:''|1.0.2|
|''Date:''|Apr 19, 2007|
|''Source:''|http://tiddlywiki.bidix.info/#PasswordOptionPlugin|
|''Author:''|BidiX (BidiX (at) bidix (dot) info)|
|''License:''|[[BSD open source license|http://tiddlywiki.bidix.info/#%5B%5BBSD%20open%20source%20license%5D%5D ]]|
|''~CoreVersion:''|2.2.0 (Beta 5)|
***/
//{{{
version.extensions.PasswordOptionPlugin = {
	major: 1, minor: 0, revision: 2, 
	date: new Date("Apr 19, 2007"),
	source: 'http://tiddlywiki.bidix.info/#PasswordOptionPlugin',
	author: 'BidiX (BidiX (at) bidix (dot) info',
	license: '[[BSD open source license|http://tiddlywiki.bidix.info/#%5B%5BBSD%20open%20source%20license%5D%5D]]',
	coreVersion: '2.2.0 (Beta 5)'
};

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

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

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

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

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

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

merge(config.optionsDesc,{
		pasPassword: "Test password"
	});
*/
//}}}
/***
|''Name:''|PlasticCalendarPlugin|
|''Description:''|This plugin creates a custom Gregorian calendar|
|''Version:''|1.3.1|
|''Date:''|Mar 13, 2007|
|''Source:''|http://www.math.ist.utl.pt/~psoares/addons.html|
|''Documentation:''|[[PlasticCalendarPlugin Documentation|PlasticCalendarPluginDoc]]|
|''Author:''|Paulo Soares|
|''License:''|[[Creative Commons Attribution-Share Alike 3.0 License|http://creativecommons.org/licenses/by-sa/3.0/]]|
|''~CoreVersion:''|2.1.0|
***/
{{{
// --------------------------------------------------------------------
// Calendar
// --------------------------------------------------------------------

config.macros.calendar = {holidays: []};
config.macros.calendar.options = {
 // day week starts from (normally 0-Su or 1-Mo)
 calendarWeekStart: 0,
 calendarToday: "Today",
 calendarHoliday: "Holiday: ",
 calendarLongDateFormat: "0DD/0MM/YYYY",
 calendarShortDateFormat: "0DD/0MM",
 calendarTag: ["journal"]
};

/***************************************************************************
** Internal functions
***************************************************************************/
var cldTag;

config.macros.calendar.calendarIsHoliday = function(date) {
 var cm = config.macros.calendar;
 var longHoliday = date.formatString(cm.options.calendarLongDateFormat);
 var shortHoliday = date.formatString(cm.options.calendarShortDateFormat);
 for(var i = 0; i < cm.holidays.length; i++) {
 if(cm.holidays[i][0] == longHoliday || cm.holidays[i][0] == shortHoliday) {
 return cm.holidays[i];
 }
 }
 return null;
}

config.macros.calendar.onClickOtherDay = function(e) {
 var day = this.getAttribute('tiddlylink');
 story.displayTiddler(null,day,DEFAULT_EDIT_TEMPLATE);
 for(var i=0; i<cldTag.length;i++){
 story.setTiddlerTag(day, cldTag[i], 0);
 }
 story.focusTiddler(day,"text");
}

config.macros.calendar.getPopupText = function(title) {
 var popup_entries = store.getTiddlerText(title).split("\n");
 var popup = popup_entries[0];
 if(popup_entries.length>1) popup += " ...";
 return popup;
}

config.macros.calendar.findCalendar = function(child) {
 var parent;
 while (child && child.parentNode) {
 parent = child.parentNode;
 if (parent.id == "calendarWrapper") {
 return parent;
 }
 child = parent;
 }
 return null;
}

config.macros.calendar.selectDate = function(e) {
 if (!e) var e = window.event;
 var cm = config.macros.calendar;
 var calendar = cm.findCalendar(this);
 if (calendar) {
 var d = this.getAttribute("date");
 if (d != null) cm.makeCalendar(calendar, new Date(new Number(d)));
 }
 e.cancelBubble = true;
 if (e.stopPropagation) e.stopPropagation();
 return false;
}

config.macros.calendar.makeCalendar = function(calendar, dt_current) {
 var cm = config.macros.calendar;
 var currentDay = new Date(new Number(calendar.getAttribute("currentDay")));
 var setControls = calendar.getAttribute("setControls");
 calendar.setAttribute("date", dt_current.valueOf());

 while (calendar.hasChildNodes())
 calendar.removeChild(calendar.firstChild);

if(setControls==1){
 // get same date in the previous year
 var dt_prev_year = new Date(dt_current);
 dt_prev_year.setFullYear(dt_prev_year.getFullYear() - 1);
 if (dt_prev_year.getDate() != dt_current.getDate())
 dt_prev_year.setDate(0);

 // get same date in the next year
 var dt_next_year = new Date(dt_current);
 dt_next_year.setFullYear(dt_next_year.getFullYear() + 1);
 if (dt_next_year.getDate() != dt_current.getDate())
 dt_next_year.setDate(0);

 // get same date in the previous month
 var dt_prev_month = new Date(dt_current);
 dt_prev_month.setMonth(dt_prev_month.getMonth() - 1);
 if (dt_prev_month.getDate() != dt_current.getDate())
 dt_prev_month.setDate(0);

 // get same date in the next month
 var dt_next_month = new Date(dt_current);
 dt_next_month.setMonth(dt_next_month.getMonth() + 1);
 if (dt_next_month.getDate() != dt_current.getDate())
 dt_next_month.setDate(0);
}

 // get first day to display in the grid for current month
 var dt_firstday = new Date(dt_current);
 dt_firstday.setDate(1);
 dt_firstday.setDate(1 - (7 + dt_firstday.getDay() - cm.options.calendarWeekStart) % 7);

 var area, header;
 var line, cell, i;

 // 1 - calendar header table
 // 2 - print weekdays titles
 // 3 - calendar days table 
calendar.cellPadding = 0;
calendar.cellSpacing = 0;
area = createTiddlyElement(calendar, "tbody");

 // 1 - calendar header table
 header = createTiddlyElement(area,"tr", "calendarHeader");
 header.cellPadding = 0;
 header.cellSpacing = 0;

if(setControls==1){ 
var headerValues = [
 [ "<<", "selectYear", dt_prev_year.valueOf() ],
 [ "<", "selectMonth", dt_prev_month.valueOf() ],
 [ config.messages.dates.months[dt_current.getMonth()] + ' ' + dt_current.getFullYear(),
 "selectToday", currentDay.valueOf() ],
 [ ">", "selectMonth", dt_next_month.valueOf() ],
 [ ">>", "selectYear", dt_next_year.valueOf() ]
 ];

 for (i = 0; i < headerValues.length; ++i) {
 var link = createTiddlyElement(header,"td", null, null, headerValues[i][0]);
 if(i==2) link.colSpan=3;
 link.onclick = cm.selectDate;
 link.setAttribute("date", headerValues[i][2]);
 }
} else {
 var link = createTiddlyElement(header,"td", null, null, 
config.messages.dates.months[dt_current.getMonth()] + ' ' + dt_current.getFullYear());
link.colSpan=7;
}

 // 2 - print weekdays titles
 line = createTiddlyElement(area, "tr", "weekNames");
 for (var n = 0; n < 7; ++n) {
 createTiddlyElement(line, "td", null, null, config.messages.dates.shortDays[(cm.options.calendarWeekStart + n)%7]);
 }

 // 3 - calendar days table
 var dt_current_day = new Date(dt_firstday);
 var day_class;
 var title;
 var holiday;
 var popup;
 var clickHandler;

 while (dt_current_day.getMonth() == dt_current.getMonth() ||
 dt_current_day.getMonth() == dt_firstday.getMonth()) {

 // print row header
 line = createTiddlyElement(area, "tr", "calendarLine", null, null);
 for (var n_current_wday = 0; n_current_wday < 7; ++n_current_wday) {
 title = dt_current_day.formatString(cm.options.calendarLongDateFormat);
 clickHandler = cm.onClickOtherDay;
 popup = null;
 holiday = cm.calendarIsHoliday(dt_current_day);

 if (holiday != null) {
 // holidays
 day_class = (holiday.length==3)? holiday[2]: "holiDay";
 popup = cm.options.calendarHoliday + holiday[1];
 } else if (dt_current_day.getDay() == 0 || dt_current_day.getDay() == 6) {
 // weekend days
 day_class = "weekDay";
 } else {
 // print working days of current month
 day_class = "workingDay";
 }

if(dt_current_day.getMonth() == dt_current.getMonth()){
 if (currentDay.valueOf() == dt_current_day.valueOf()) {
 // print current date
 if (store.tiddlerExists(title)){
 // day has a tiddler associated with it
 day_class += " currentscheduledDay";
 clickHandler = onClickTiddlerLink;
 popup = cm.options.calendarToday + ": "+ cm.getPopupText(title);
 } else {
 day_class += " currentDay";
 popup = cm.options.calendarToday;
}
}


 if (store.tiddlerExists(title) && store.getTiddler(title).isTagged(cldTag[0]))  {
 // day has a tiddler associated with it
 day_class += " scheduledDay";
 clickHandler = onClickTiddlerLink;
 popup = cm.getPopupText(title);
 }
}

 // extra formatting for days of previous or next month
 if (dt_current_day.getMonth() != dt_current.getMonth()) {
 day_class += " otherMonthDay";
 }

 var text = dt_current_day.getDate();
 var cell = createTiddlyElement(line, "td", null, day_class, text);
 cell.onclick=clickHandler;
 cell.setAttribute("date", dt_current_day.valueOf());
 cell.setAttribute("tiddlyLink", title);
 if(popup) cell.setAttribute("title", popup);
 dt_current_day.setDate(dt_current_day.getDate()+1);
 }
 }
}

config.macros.calendar.handler = function(place,macroName,params,wikifier,paramString,tiddler) {
 var start_date = new Array();
 var date = new Date();
 var cldParams = paramString.parseParams('calendarParams', null, true);
 var cldYear = (cldParams[0].year)?parseFloat(cldParams[0].year[0]): date.getFullYear();
 var cldMonth = (cldParams[0].month)?parseFloat(cldParams[0].month[0]): date.getMonth();
 var n_months = (cldParams[0].numberMonths)?parseFloat(cldParams[0].numberMonths[0]): 1;
 var n_cols = (cldParams[0].numberColumns)?parseFloat(cldParams[0].numberColumns[0]): 3;
 cldTag = (cldParams[0].tag)?cldParams[0].tag[0].split("#"): config.macros.calendar.options.calendarTag;
 for(var i = 0; i < n_months; i++){
 start_date[i] = new Date(cldYear, cldMonth+i, 1);
 }
 var n_rows = Math.max(1,Math.ceil(n_months/n_cols));
 n_cols = Math.min(n_cols,n_months);
 var setControls=(n_months>1)? 0: 1;
 var currentDay = new Date();
 currentDay = new Date(currentDay.getFullYear(), currentDay.getMonth(), currentDay.getDate());
 var holder = createTiddlyElement(place, "table", null,"calendarHolder");
 var holderTable = createTiddlyElement(holder, "tbody");
 for(var i = 0; i < n_rows; i++){
 var holderLine = createTiddlyElement(holderTable, "tr");
 for(var j = 0; j < n_cols; j++){
 var holderCell = createTiddlyElement(holderLine, "td");
 if(n_cols*i+j+1<=n_months){
 var calendar = createTiddlyElement(holderCell, "table", "calendarWrapper");
 calendar.setAttribute("name", "calendarWrapper");
 calendar.setAttribute("setControls", setControls);
 calendar.setAttribute("currentDay", currentDay.valueOf());
 config.macros.calendar.makeCalendar(calendar, start_date[n_cols*i+j]);
 }
 }
 }
}

function refreshCalendars(hint) {
 var calendars = document.getElementsByName("calendarWrapper");
 var i, c;
 for (i = 0; i < calendars.length; ++i) {
 c = calendars.item(i);
 if (c.id == "calendarWrapper") {
 config.macros.calendar.makeCalendar(c, new Date(new Number(c.getAttribute("date"))));
 }
 }
}

store.addNotification(null, refreshCalendars);

setStylesheet("/***\n!Calendar Styles\n***/\n/*{{{*/\n .viewer .calendarHolder {\n margin-left: auto;\n margin-right: auto;\n border: none;\n}\n\n .viewer .calendarHolder table {\n border: none;\n margin: 0;\n}\n\n .viewer .calendarHolder tr {\n border: none;\n vertical-align: top;\n}\n\n .viewer .calendarHolder td {\n border: none;\n vertical-align: top;\n}\n\n .viewer #calendarWrapper {\n width: 21em;\n border: 2px solid #4682b4;\n cursor: pointer;\n}\n\n #calendarWrapper #calendarLine td {\n height: 2.5em;\n}\n\n #calendarWrapper tr {\n border:none;\n}\n\n #calendarWrapper td {\n text-align: center;\n vertical-align: middle;\n width: 14.28%;\n border:none;\n}\n\n #calendarWrapper #calendarHeader td{\n color: #ffffff;\n background-color: #4682b4;\n height: 2em;\n}\n\n #calendarWrapper #weekNames td {\n color: #ffffff;\n background-color: #87cefa;\n height: 2em;\n}\n\n #calendarWrapper .weekDay {\n background-color: #ccff99;\n}\n\n #calendarWrapper .holiDay {\n background-color: #9acd32;\n}\n\n #calendarWrapper .currentDay {\n border: solid #ff0000 2px;\n font-weight: bold;\n}\n\n #calendarWrapper .currentscheduledDay {\n border: solid #ff0000 2px;\n font-weight: bold;\n}\n\n #calendarWrapper .workingDay {\n background-color: #ffffff;\n}\n\n #calendarWrapper .scheduledDay {\n border: solid orange 2px;\n}\n\n #calendarWrapper .otherMonthDay {\n background-color: #999;\n}\n\n/*}}}*/","CalendarStyles");

config.shadowTiddlers.PlasticCalendarPluginDoc="The documentation is missing. It is available [[here|http://www.math.ist.utl.pt/~psoares/addons.html#PlasticCalendarPluginDoc]].";
}}}
version.extensions.Holidays = {
 major: 1, minor: 1, revision: 0,
 date: new Date(2006, 4, 18), 
 type: 'config'
};

config.macros.calendar.holidays = [ ["01/01", "New Year's day"], ["25/12", "Christmas day", "Christian"] ];
[[< Back|Lecture Index]]|[[Next>|REGEX-02]]
!REGEX Hunting

REGEX: ''regular expressions'' that are formalized algorithms to evaluate character-by-character usage patterns in text strings. 

# regex is not unique to PERL
# often are not interested in exact pattern matches
# often interested in pattern matches with a variable target
# often need separate logic gates within the match pattern
# almost like a mini-programming language

[[REGEX Refernce Page in RESOURCES|regex expression syntax]]


!



  
[[< Back|REGEX-01]]|[[Next>|REGEX-03]]
!REGEX Hunting

!!Compare 'CG' vs 'GC' motif usage

We have analyzed the GC content of genes within the genome for: ''Acidianus_hospitalis_W1_uid66875''
<html><img src="07/PLOT-Fig4-GCvsCpG.jpg" style="height:500px"></html>

The 'CG' motif frequency does not appear to be randomly correlated with the %GC content of any gene. 

''QUESTION: //Is there any significance to the appearance of 'CG' motifs within genes to suggest that there is a functional role for the motif that would result in a pattern of selection via functional fitness?//''

@@''HOW DO WE TEST THIS KIND OF QUESTION?''@@

!

[[< Back|REGEX-02]]|[[Next>|REGEX-04]]
!FASTA Motif Hunting

First step to test is to development a NULL model to test against. Essentially, if the appearance of CG was completely random, then NULL model is the random outcome set. So how do we test if CG is random or not?

Well, if we think CG may be important, then maybe a good control could be looking at the pattern of 'GC' motifs. This motif has the same NTs as 'CG' but in the reverse order, so if let's look for differences in the usage pattern of 'CG' vs 'GC'.

[[FASTA script to count CG and GC|FASTA CG and GC]]

<html><table><tr>
<td><img src="07/PLOT-Fig4-GCvsCpG.jpg" style="height:400px"></td>
<td><img src="07/PLOT-Fig5-GCvsGpC.jpg" style="height:400px"></td>
</tr></table></html>


!
[[< Back|REGEX-03]]|[[Next>|REGEX-05]]
!FASTA Motif Hunting

!!Plot: GC vs CG by gene
<html><img src="07/PLOT-Fig6-GpCvsCpG.jpg" style="height:400px"></html>

!!Ratio: CG/CG by gene
* Compare the usage of 'CG' vs 'GC' on a gene by gene basis . . . .  
* Use a simple ratio of dividing the 'CG' counts by the 'GC' counts. If both are used equally, the ratio = 1.
<html><img src="07/PLOT-Fig8-GCvsRatio.jpg" style="height:400px"></html>

* A distribution plot of the ratio clearly shows that 'CG' counts are most frequently less than 'GC' counts in any given gene:
<html><img src="07/PLOT-Fig7-Ratio.jpg" style="height:400px"></html>


!
[[< Back|REGEX-04]]|[[Next>|REGEX-06]]
!Rounding Subroutine
There's no need to keep non-significant digits in numerical calculations. Here's a simple strategy that implements a rounding function to a specific number of decimal places.
{{{
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
sub Round
{	
	my $num = shift(@_);             #   25.9259259259259 = target number
	my $dig = shift(@_);             #   3 = number of decimal places
	#my $round = ($num * 10**$dig);  #   25925.9259259259
	#$round = $round + 0.5;          #   25926.4259.....
	#$round = int($round);           #   25926
	#$round = $round/10**$dig;       #   25.926
	#return $round;
	return ((int(($num * 10**$dig) + 0.50))/10**$dig);
}

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
}}}

It would be called from a script like this:
@@{{{ my $x = &Round( $y/17.25, 4); }}}@@
where the quotient of $y/17 would be rounded to float with 4 decimal places.


!

[[< Back|REGEX-05]]|[[Next>|REGEX-07]]
!Randomizing Sequences

{{{
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
sub FYshuffle
{
	#Fisher-Yates Randomization . . . . .
	my @s = split(//,$_[0]);
	#my @s = (0,1,2,3);
	foreach my $k (1..10)
	{	#print "\n\n********************\n$k. Loop starting seq: ", join(", ", @s), "\n";
		for (my $i = $#s; $i>0 ; $i--)
		{	my $j = int(rand($i-1));
			@s[$i,$j] = @s[$j,$i];
			#print "---------------------------\n i= $i; j= $j; s= ", join("  |  ", @s),"\n";
		}
	}
	return join('',@s);
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
}}}



!
[[< Back|REGEX-06]]|[[Next>|REGEX-08]]
!Randomizing Sequences
{{{
# 0 Generate Random Control gene sequences . . . . . .
foreach my $id (keys %Genes)
{	$RGenes{$id}{'head'} = $id;
	$RGenes{$id}{'seq'}  = &FYshuffle($Genes{$id}{'seq'});
	$RGenes{$id}{'len'} = length($RGenes{$id}{'seq'});
	
	print "GENE: $Genes{$id}{'seq'}\n\n";
	print "RAND: $RGenes{$id}{'seq'}\n\n";
	
	my @g = split(//,$Genes{$id}{'seq'});
	my @r = split(//,$RGenes{$id}{'seq'});
	
	my $equal = 0;
	for my $i (0..$#g)
	{	if ($g[$i] eq $r[$i])
		{	$equal += 1;  }
	}
	print "\n\nThere were $equal matching NTs.\n";
	print "Seqs are ", &Round(100*$equal/($#g+1), 1), "% identical\n\n";
	
	die;
}
}}}



!
!Course Resources:
# [[PERL]]
# [[Code Editors|Editors]]
# [[R Statistical Shell|Rstats]]
# [[Working with R in Windows OS]]
# [[Biohen Cluster Computing|Biohen]]
# [[Ref Book: Genomic PERL|Genomic Perl]] 
# [[PERL regex control|regex expression syntax]] 
# [[SSH Passwordless Login|SSHsetup]]
# [[Project Library|PDF Library]]

!!!Other
* ~DropBox
* ~EverNote
* Hierarchical clustering sequence alignment: [[ClustalX|http://www.clustal.org/]]
* Dendrogram Tree visualization: [[FigTree|http://tree.bio.ed.ac.uk/software/figtree/]]

!
[[Back to Working Code List|BoneYard]]
!!!
!Rounding significant digits
It's often confusing for us mere humans to cope with 12 digit numbers (and mostly meaningless as well in terms of biological significance). Here's a routine to round numbers that relies on the ''integer'' function, which just drops any decimal digits. 
__''The number of digits retained is set by the power of ten (exponents) used in the calculation.''__
{{{
# Call the subroutine:
       &Round(any numeric variable or expression, number of sig digits);

# Subroutine Code:
# - - - - - - - - - - - - - - - - - - - - - - - - - -
sub ROUND
{	my $num = shift(@_);
	my $decimals = shift(@_);
	my $roundnum = int(($num * 10**$decimals) + 0.5)/(10**$decimals);
	return $roundnum;
}
#---------------------
}}}
[[<BACK to Resource Index|Resource Index]]
!R Stats Package

!!!Statistical Software Package: http://www.r-project.org
<html><img src="00/Rstat.png" style="height:300px"></html>

!!!R Studio Editing Display Package: http://rstudio.org
<html><img src="00/Rstudio.png" style="height:300px"></html>

!!!Hadley Wickham's: "ggplot2: Elegant Graphics for Data Analysis"
<html><img src="00/Rstat-ggplot2.png" style="height:200px"></html>

!!!Guides
/%
* Here's a simple R Tutorial: [[Tutorial-Verzani-SimpleR.pdf|00/Tutorial-Verzani-SimpleR.pdf]]
%/
* Here's a simple R guide: [[QUICK-R Guide|http://www.statmethods.net/index.html]]

!
[[<Back|BoneYard]]
!Skew Calculation for AA and Codon profiles

{{{
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
sub SKEW                           # Requires the SKEWcalc subroutines . . 
{	print "   Skew calculation . . . \n";
	my @AAx = qw | A C D E F G H I K L M N P Q R S T V W Y |;
	my $GenDict = $_[0];
	foreach my $id (keys %{$GenDict})
	{	# 1. Calculate SKaa . . . . . . .
		my @pAA;
		foreach my $aa (@AAx)
		{	push(@pAA, ${$GenDict}{$id}{'AAfreq'}{'p'.$aa}); }
		${$GenDict}{$id}{'SKaa'} = &SKEWcalc(\@pAA);
		# &DUMP(${$GenDict}{$id}{'SKaa'});
		
		# 2. Calculate SKcd . . . . . . .
		my @nCD;
		foreach my $codon (keys %CodonTable)
		{	push(@nCD,${$GenDict}{$id}{'CDfreq'}{'n'.$codon}); }
		${$GenDict}{$id}{'SKcd'} = &SKEWcalc(\@nCD);
		# &DUMP(${$GenDict}{$id}{'SKcd'});
	}
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
}}}
[[BACK to Resources|Resource Index]]
!!!
!SSH setup for automatic login to Biohen:
SSH has a system for allowing computers to recognize each other and bypass the exchange of a password when connecting them. The way it works is that your local computer (A) generates an encrypted KEY that is then put in a file in your home directory on Biohen. Login authorization is then determined by the computers 'recognizing' each other using this key.

First, start an SSH-client (command) terminal window on local computer (here named 'LOCAL'). Then generate the ssh key by following these commands, but do not enter a 'passphrase' when prompted. Just hit return twice.
{{{
LOCAL> ssh-keygen -t rsa
Generating public/private rsa key pair.
Enter file in which to save the key (/home/user/.ssh/id_rsa): 
Created directory '/home/user/.ssh'.
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in /home/user/.ssh/id_rsa.
Your public key has been saved in /home/user/.ssh/id_rsa.pub.
The key fingerprint is:
3e:4f:05:79:3a:9f:96:7c:3b:ad:e9:58:37:bc:37:e4 user@LOCAL
}}}
Now use ssh to create a directory ~/.ssh Biohen. (The directory may already exist, which is fine). Use your account //username//. You will be prompted for your password:
{{{
LOCAL> ssh username@biohen.dbi.udel.edu mkdir -p .ssh
}}}

Now we just add/append the public key from LOCAL to your Biohen account in a file named "authorized_keys". Again use your biohen //username// and you will be prompted for your password:
{{{
LOCAL> cat .ssh/id_rsa.pub | ssh username@biohen.dbi.udel.edu 'cat >> .ssh/authorized_keys'
}}}
From now on you can log into Biohen from your LOCAL computer without entering a password. 

You can streamline the login process even more by establishing an 'alias' command in your shell profile. This is easy to do, but depends upon what shell you are running on your LOCAL computer. For a C shell (csh) add a line like this to the ''.cshrc'' file in your home directory on LOCAL (//note that this is a hidden file//):
{{{
alias biohen ssh -l username biohen.dbi.udel.edu
}}}

For a bash shell add a line like this to the ''.bash_profile'' file in your home directory on LOCAL (//note that this is a hidden file//):
{{{
alias biohenf='ssh -l username biohen.dbi.udel.edu'
}}}

From a terminal window you need to restart the shell with either:
** prompt> source .cshrc
** prompt> source .bashrc
And then you can log into your Biohen account with just the command:
{{{
LOCAL> biohen
}}}
//{{{
window.reportSearchResults=function(text,matches)
{
	var title=config.macros.search.reportTitle
	var q = config.options.chkRegExpSearch ? "/" : "'";
	var body="\n";

	// numbered list of links to matching tiddlers
	body+="\n<<<";
	for(var t=0;t<matches.length;t++) {
		var date=config.options.chkSearchByDate?(matches[t].modified.formatString('YYYY.0MM.0DD 0hh:0mm')+" "):"";
		body+="\n# "+date+"[["+matches[t].title+"]]";
	}
	body+="\n<<<\n";

	// create/update the tiddler
	var tiddler=store.getTiddler(title); if (!tiddler) tiddler=new Tiddler();
	tiddler.set(title,body,config.options.txtUserName,(new Date()),"excludeLists excludeSearch");
	store.addTiddler(tiddler); story.closeTiddler(title);

	// use alternate "search again" label in <<search>> macro
	var oldprompt=config.macros.search.label;
	config.macros.search.label="search again";

	// render/refresh tiddler
	story.displayTiddler(null,title,1);
	store.notify(title,true);

	// restore standard search label
	config.macros.search.label=oldprompt;

}

//}}}
/***
|Name|SearchOptionsPlugin|
|Source|http://www.TiddlyTools.com/#SearchOptionsPlugin|
|Documentation|http://www.TiddlyTools.com/#SearchOptionsPluginInfo|
|Version|2.6.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.search, TiddlyWiki.prototype.search, config.macros.search.onKeyPress|
|Description|extend core search function with additional user-configurable options|
Extend core search function with additional user-configurable options including generating a ''list of matching tiddlers'' instead of immediately displaying all matches.
!!!!!Documentation
>see [[SearchOptionsPluginInfo]]
!!!!!Configuration
<<<
<<option chkSearchTitles>> Search in titles
<<option chkSearchText>> Search in tiddler text
<<option chkSearchTags>> Search in tags
<<option chkSearchFields>> Search in data fields
<<option chkSearchShadows>> Search shadow tiddlers
<<option chkSearchTitlesFirst>> Show title matches first
<<option chkSearchByDate>> Sort matching tiddlers by date
<<option chkSearchList>> Show list of matches in [[SearchResults]]
<<option chkSearchIncremental>> Incremental (key-by-key) searching
<<<
!!!!!Revisions
<<<
2007.02.17 [2.6.1] added redefinition of config.macros.search.onKeyPress() to restore check to bypass key-by-key searching (i.e., when chkSearchIncremental==false), which had been unintentionally removed with v2.6.0
|please see [[SearchOptionsPluginInfo]] for additional revision details|
2005.10.18 [1.0.0] Initial Release
<<<
!!!!!Code
***/
//{{{
version.extensions.searchOptions = {major: 2, minor: 6, revision: 1, date: new Date(2007,2,17)};

if (config.options.chkSearchTitles===undefined) config.options.chkSearchTitles=true;
if (config.options.chkSearchText===undefined) config.options.chkSearchText=true;
if (config.options.chkSearchTags===undefined) config.options.chkSearchTags=true;
if (config.options.chkSearchFields===undefined) config.options.chkSearchFields=true;
if (config.options.chkSearchTitlesFirst===undefined) config.options.chkSearchTitlesFirst=false;
if (config.options.chkSearchList===undefined) config.options.chkSearchList=false;
if (config.options.chkSearchByDate===undefined) config.options.chkSearchByDate=false;
if (config.options.chkSearchIncremental===undefined) config.options.chkSearchIncremental=true;
if (config.options.chkSearchShadows===undefined) config.options.chkSearchShadows=false;

if (config.optionsDesc) {
	config.optionsDesc.chkSearchTitles="Search in tiddler titles";
	config.optionsDesc.chkSearchText="Search in tiddler text";
	config.optionsDesc.chkSearchTags="Search in tiddler tags";
	config.optionsDesc.chkSearchFields="Search in tiddler data fields";
	config.optionsDesc.chkSearchShadows="Search in shadow tiddlers";
	config.optionsDesc.chkSearchTitlesFirst="Search results show title matches first";
	config.optionsDesc.chkSearchList="Search results show list of matching tiddlers";
	config.optionsDesc.chkSearchByDate="Search results sorted by modification date ";
	config.optionsDesc.chkSearchIncremental="Incremental searching";
} else {
	config.shadowTiddlers.AdvancedOptions += "\n<<option chkSearchTitles>> Search in tiddler titles"
		+"\n<<option chkSearchText>> Search in tiddler text"
		+"\n<<option chkSearchTags>> Search in tiddler tags"
		+"\n<<option chkSearchFields>> Search in tiddler data fields"
		+"\n<<option chkSearchShadows>> Search in shadow tiddlers"
		+"\n<<option chkSearchTitlesFirst>> Search results show title matches first"
		+"\n<<option chkSearchList>> Search results show list of matching tiddlers"
		+"\n<<option chkSearchByDate>> Search results sorted by modification date"
		+"\n<<option chkSearchIncremental>> Incremental searching";
}

if (config.macros.search.reportTitle==undefined)
	config.macros.search.reportTitle="SearchResults";

config.macros.search.onKeyPress = function(e)
{
	if(!e) var e = window.event;
	switch(e.keyCode)
		{
		case 13: // Ctrl-Enter
		case 10: // Ctrl-Enter on IE PC
			config.macros.search.doSearch(this);
			break;
		case 27: // Escape
			this.value = "";
			clearMessage();
			break;
		}
	if (config.options.chkSearchIncremental) {
		if(this.value.length > 2)
			{
			if(this.value != this.getAttribute("lastSearchText"))
				{
				if(config.macros.search.timeout)
					clearTimeout(config.macros.search.timeout);
				var txt = this;
				config.macros.search.timeout = setTimeout(function() {config.macros.search.doSearch(txt);},500);
				}
			}
		else
			{
			if(config.macros.search.timeout)
				clearTimeout(config.macros.search.timeout);
			}
	}
}
//}}}

//{{{
Story.prototype.search = function(text,useCaseSensitive,useRegExp)
{
	highlightHack = new RegExp(useRegExp ? text : text.escapeRegExp(),useCaseSensitive ? "mg" : "img");
	var matches = store.search(highlightHack,config.options.chkSearchByDate?"modified":"title","excludeSearch");
	if (config.options.chkSearchByDate) matches=matches.reverse(); // most recent changes first
	var q = useRegExp ? "/" : "'";
	clearMessage();
	if (!matches.length) {
		if (config.options.chkSearchList) discardSearchResults();
		displayMessage(config.macros.search.failureMsg.format([q+text+q]));
	} else {
		if (config.options.chkSearchList) 
			reportSearchResults(text,matches);
		else {
			var titles = []; for(var t=0; t<matches.length; t++) titles.push(matches[t].title);
			this.closeAllTiddlers(); story.displayTiddlers(null,titles);
			displayMessage(config.macros.search.successMsg.format([matches.length, q+text+q]));
		}
	}
	highlightHack = null;
}

TiddlyWiki.prototype.search = function(searchRegExp,sortField,excludeTag)
{
	var candidates = this.reverseLookup("tags",excludeTag,false,sortField);

	// scan for matching titles first...
	var results = [];
	if (config.options.chkSearchTitles) {
		for(var t=0; t<candidates.length; t++)
			if(candidates[t].title.search(searchRegExp)!=-1)
				results.push(candidates[t]);
		if (config.options.chkSearchShadows)
			for (var t in config.shadowTiddlers)
				if ((t.search(searchRegExp)!=-1) && !store.tiddlerExists(t))
					results.push((new Tiddler()).assign(t,config.shadowTiddlers[t]));
	}
	// then scan for matching text, tags, or field data
	for(var t=0; t<candidates.length; t++) {
		if (config.options.chkSearchText && candidates[t].text.search(searchRegExp)!=-1)
			results.pushUnique(candidates[t]);
		if (config.options.chkSearchTags && candidates[t].tags.join(" ").search(searchRegExp)!=-1)
			results.pushUnique(candidates[t]);
		if (config.options.chkSearchFields && store.forEachField!=undefined) // requires TW2.1 or above
			store.forEachField(candidates[t],
				function(tid,field,val) { if (val.search(searchRegExp)!=-1) results.pushUnique(candidates[t]); },
				true); // extended fields only
	}
	// then check for matching text in shadows
	if (config.options.chkSearchShadows)
		for (var t in config.shadowTiddlers)
			if ((config.shadowTiddlers[t].search(searchRegExp)!=-1) && !store.tiddlerExists(t))
				results.pushUnique((new Tiddler()).assign(t,config.shadowTiddlers[t]));

	// if not 'titles first', or sorting by modification date,  re-sort results to so titles, text, tag and field matches are mixed together
	if(!sortField) sortField = "title";
	var bySortField=function (a,b) {if(a[sortField] == b[sortField]) return(0); else return (a[sortField] < b[sortField]) ? -1 : +1; }
	if (!config.options.chkSearchTitlesFirst || config.options.chkSearchByDate) results.sort(bySortField);

	return results;
}

// REPORT GENERATOR
if (!window.reportSearchResults) window.reportSearchResults=function(text,matches)
{
	var title=config.macros.search.reportTitle
	var q = config.options.chkRegExpSearch ? "/" : "'";
	var body="\n";

	// summary: nn tiddlers found matching '...', options used
	body+="''"+config.macros.search.successMsg.format([matches.length,q+"{{{"+text+"}}}"+q])+"''\n";
	body+="^^//searched in:// ";
	body+=(config.options.chkSearchTitles?"''titles'' ":"");
	body+=(config.options.chkSearchText?"''text'' ":"");
	body+=(config.options.chkSearchTags?"''tags'' ":"");
	body+=(config.options.chkSearchFields?"''fields'' ":"");
	body+=(config.options.chkSearchShadows?"''shadows'' ":"");
	if (config.options.chkCaseSensitiveSearch||config.options.chkRegExpSearch) {
		body+=" //with options:// ";
		body+=(config.options.chkCaseSensitiveSearch?"''case sensitive'' ":"");
		body+=(config.options.chkRegExpSearch?"''text patterns'' ":"");
	}
	body+="^^";

	// numbered list of links to matching tiddlers
	body+="\n<<<";
	for(var t=0;t<matches.length;t++) {
		var date=config.options.chkSearchByDate?(matches[t].modified.formatString('YYYY.0MM.0DD 0hh:0mm')+" "):"";
		body+="\n# "+date+"[["+matches[t].title+"]]";
	}
	body+="\n<<<\n";

	// open all matches button
	body+="<html><input type=\"button\" href=\"javascript:;\" ";
	body+="onclick=\"story.displayTiddlers(null,["
	for(var t=0;t<matches.length;t++)
		body+="'"+matches[t].title.replace(/\'/mg,"\\'")+"'"+((t<matches.length-1)?", ":"");
	body+="],1);\" ";
	body+="accesskey=\"O\" ";
	body+="value=\"open all matching tiddlers\"></html> ";

	// discard search results button
	body+="<html><input type=\"button\" href=\"javascript:;\" ";
	body+="onclick=\"story.closeTiddler('"+title+"'); store.deleteTiddler('"+title+"'); store.notify('"+title+"',true);\" ";
	body+="value=\"discard "+title+"\"></html>";

	// search again
	body+="\n\n----\n";
	body+="<<search \""+text+"\">>\n";
	body+="<<option chkSearchTitles>>titles ";
	body+="<<option chkSearchText>>text ";
	body+="<<option chkSearchTags>>tags";
	body+="<<option chkSearchFields>>fields";
	body+="<<option chkSearchShadows>>shadows";
	body+="<<option chkCaseSensitiveSearch>>case-sensitive ";
	body+="<<option chkRegExpSearch>>text patterns";
	body+="<<option chkSearchByDate>>sort by date";

	// create/update the tiddler
	var tiddler=store.getTiddler(title); if (!tiddler) tiddler=new Tiddler();
	tiddler.set(title,body,config.options.txtUserName,(new Date()),"excludeLists excludeSearch temporary");
	store.addTiddler(tiddler); story.closeTiddler(title);

	// use alternate "search again" label in <<search>> macro
	var oldprompt=config.macros.search.label;
	config.macros.search.label="search again";

	// render/refresh tiddler
	story.displayTiddler(null,title,1);
	store.notify(title,true);

	// restore standard search label
	config.macros.search.label=oldprompt;

}

if (!window.discardSearchResults) window.discardSearchResults=function()
{
	// remove the tiddler
	story.closeTiddler(config.macros.search.reportTitle);
	store.deleteTiddler(config.macros.search.reportTitle);
}
//}}}
<<<
# [[BLAST-04]]
# [[BoneYard]]
# [[Complexity05]]
# [[FASTApipe]]
# [[HomeWork-06]]
# [[Library of Babel]]
# [[TransFasta]]
<<<
/***
Quick and dirtly palette switcher for 2.1.x
<<selectPalette>>
WARNING this will overwrite your ColorPalette tiddler.
***/

//{{{

merge(config.macros,{

	setPalette: {

		handler: function(place,macroName,params,wikifier,paramString,tiddler) {
			var paletteName = params[0] ? params[0] : tiddler.title;
			createTiddlyButton(place,"apply","Apply this palette",function(e) {
				config.macros.selectPalette.updatePalette(tiddler.title);
				return false;
			});
		}
	},

	selectPalette: {

		handler: function(place,macroName,params,wikifier,paramString,tiddler) {
			createTiddlyDropDown(place,this.onPaletteChange,this.getPalettes());
		},

		getPalettes: function() {
			var result = [
				{caption:"-select palette-", name:""},
				{caption:"(Default)", name:"(default)"}
			];
			var tagged = store.getTaggedTiddlers("palette","title");
			for(var t=0; t<tagged.length; t++)
				result.push({caption:tagged[t].title, name:tagged[t].title});
			return result;
		},

		onPaletteChange: function(e) {
			config.macros.selectPalette.updatePalette(this.value);
			return true;
		},

		updatePalette: function(title) {
			if (title != "") {
				store.deleteTiddler("ColorPalette");
				if (title != "(default)")
					store.saveTiddler("ColorPalette","ColorPalette",store.getTiddlerText(title),
								config.options.txtUserName,undefined,"");
				this.refreshPalette();
				if(config.options.chkAutoSave)
					saveChanges(true);
			}
		},

		refreshPalette: function() {
			config.macros.refreshDisplay.onClick();
		}
	}
});

//}}}
[[<BACK|Entropy-01]] | [[NEXT>|MoreMonkeys]]
!Shakespeare's Monkeys

The Infinite Monkey Thereom:
[img[08/250px-Monkey-typing.jpg]] 
^^http://en.wikipedia.org/wiki/Infinite_monkey_theorem^^

__Determined Evolution Model:__ these models are described as directed selection in which the end-goal is already established and the model is essentially studying the process or mechanics by which that end-goal is achieved.

Simple PERL script to look at how long it would take to randomly fit a given text pattern following the rule that once a character in the evolving string was matched to the target string, it is fixed and stops changing. 

| @@Working Code: MonkeysTyping@@ |

{{{
----------------------------------------------------------
Would it really take a thousand years for a thousand monkeys 
typing on a thousand typewriters to compose Hamlet's soliloquy?
----------------------------------------------------------
}}}
Enter a starting target string that the monkeys have to type. 
{{{
Here's what you entered:
      F o u r   s c o r e   a n d   s e v e n   y e a r s   
a g o   o u r f o r e f a t h e r s   c r e a t e d   a   
n e w   n a t i o n
}}}
Final count for how many generations it took to match the initial input string:
{{{
It took 256 bananas to find 67 correct letters.
}}}
!
<<search>><<closeAll>><<permaview>><<newTiddler>><<newTiddler title:"tagnameSubtopicMenu" tag:"SubtopicMenu" label:"new subtopic menu" text:"{{tableindex{
|[[subtopic1]]|[[subtopic2]]|[[subtopic3]]|
}}}">><<newTiddler title:"tagnameViewTemplate" tag:"excludeLists" label:"new viewtemplate" text:"<!--{{{-->
<div class='toolbar' macro='toolbar closeTiddler closeOthers +editTiddler > fields syncing permalink references jump'></div>
<div class='xxxx' macro='tiddler xxxxSubtopicMenu'></div><div class='title' macro='view title'></div>
<div class='viewer' macro='view text wikified'></div><div class='tagClear'></div>
<!--}}}-->
">><<saveChanges>>[[Formatting cheatsheet]]<<selectPalette>><<slider chkSliderOptionsPanel OptionsPanel "options »" "Change TiddlyWiki advanced options">>

<<tabs txtMainTab "Timeline" "Timeline" TabTimeline "All" "All tiddlers" TabAll "Tags" "All tags" TabTags "More" "More lists" TabMore>>
/***
|Name|SinglePageModePlugin|
|Source|http://www.TiddlyTools.com/#SinglePageModePlugin|
|Documentation|http://www.TiddlyTools.com/#SinglePageModePluginInfo|
|Version|2.8.2|
|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.displayTiddler(), Story.prototype.displayTiddlers()|
|Description|Show tiddlers one at a time with automatic permalink, or always open tiddlers at top/bottom of page.|
This plugin allows you to configure TiddlyWiki to navigate more like a traditional multipage web site with only one tiddler displayed at a time.
!!!!!Documentation
>see [[SinglePageModePluginInfo]]
!!!!!Configuration
<<<
<<option chkSinglePageMode>> Display one tiddler at a time
><<option chkSinglePageKeepFoldedTiddlers>> Don't auto-close folded tiddlers
><<option chkSinglePagePermalink>> Automatically permalink current tiddler
<<option chkTopOfPageMode>> Always open tiddlers at the top of the page
<<option chkBottomOfPageMode>> Always open tiddlers at the bottom of the page
<<option chkSinglePageAutoScroll>> Automatically scroll tiddler into view (if needed)

Notes:
* The "display one tiddler at a time" option can also be //temporarily// set/reset by including a 'paramifier' in the document URL: {{{#SPM:true}}} or {{{#SPM:false}}}.
* If more than one display mode is selected, 'one at a time' display takes precedence over both 'top' and 'bottom' settings, and if 'one at a time' setting is not used, 'top of page' takes precedence over 'bottom of page'.
* When using Apple's Safari browser, automatically setting the permalink causes an error and is disabled.
<<<
!!!!!Revisions
<<<
2008.03.14 [2.8.2] in displayTiddler(), if editing specified tiddler, just move it to top/bottom of story *without* re-rendering (prevents discard of partial edits).
| Please see [[SinglePageModePluginInfo]] for previous revision details |
2005.08.15 [1.0.0] Initial Release.  Support for BACK/FORWARD buttons adapted from code developed by Clint Checketts.
<<<
!!!!!Code
***/
//{{{
version.extensions.SinglePageMode= {major: 2, minor: 8, revision: 2, date: new Date(2008,3,14)};
//}}}
//{{{
config.paramifiers.SPM = { onstart: function(v) {
	config.options.chkSinglePageMode=eval(v);
	if (config.options.chkSinglePageMode && config.options.chkSinglePagePermalink && !config.browser.isSafari) {
		config.lastURL = window.location.hash;
		if (!config.SPMTimer) config.SPMTimer=window.setInterval(function() {checkLastURL();},1000);
	}
} };
//}}}
//{{{
if (config.options.chkSinglePageMode==undefined) config.options.chkSinglePageMode=false;
if (config.options.chkSinglePageKeepFoldedTiddlers==undefined) config.options.chkSinglePageKeepFoldedTiddlers=true;
if (config.options.chkSinglePagePermalink==undefined) config.options.chkSinglePagePermalink=true;
if (config.options.chkTopOfPageMode==undefined) config.options.chkTopOfPageMode=false;
if (config.options.chkBottomOfPageMode==undefined) config.options.chkBottomOfPageMode=false;
if (config.options.chkSinglePageAutoScroll==undefined) config.options.chkSinglePageAutoScroll=true;

if (config.optionsDesc) {
	config.optionsDesc.chkSinglePageMode="Display one tiddler at a time";
	config.optionsDesc.chkSinglePageKeepFoldedTiddlers="Don't auto-close folded tiddlers";
	config.optionsDesc.chkSinglePagePermalink="Automatically permalink current tiddler";
	config.optionsDesc.chkSinglePageAutoScroll="Automatically scroll tiddler into view (if needed)";
	config.optionsDesc.chkTopOfPageMode="Always open tiddlers at the top of the page";
	config.optionsDesc.chkBottomOfPageMode="Always open tiddlers at the bottom of the page";
} else {
	config.shadowTiddlers.AdvancedOptions += "\
		\n<<option chkSinglePageMode>> Display one tiddler at a time \
		\n<<option chkSinglePageKeepFoldedTiddlers>> Don't auto-close folded tiddlers \
		\n<<option chkSinglePagePermalink>> Automatically permalink current tiddler \
		\n<<option chkSinglePageAutoScroll>> Automatically scroll tiddler into view (if needed) \
		\n<<option chkTopOfPageMode>> Always open tiddlers at the top of the page \
		\n<<option chkBottomOfPageMode>> Always open tiddlers at the bottom of the page";
}
//}}}
//{{{
config.SPMTimer = 0;
config.lastURL = window.location.hash;
function checkLastURL()
{
	if (!config.options.chkSinglePageMode)
		{ window.clearInterval(config.SPMTimer); config.SPMTimer=0; return; }
	if (config.lastURL == window.location.hash) return; // no change in hash
	var tids=convertUTF8ToUnicode(decodeURIComponent(window.location.hash.substr(1))).readBracketedList();
	if (tids.length==1) // permalink (single tiddler in URL)
		story.displayTiddler(null,tids[0]);
	else { // restore permaview or default view
		config.lastURL = window.location.hash;
		if (!tids.length) tids=store.getTiddlerText("DefaultTiddlers").readBracketedList();
		story.closeAllTiddlers();
		story.displayTiddlers(null,tids);
	}
}

if (Story.prototype.SPM_coreDisplayTiddler==undefined)
	Story.prototype.SPM_coreDisplayTiddler=Story.prototype.displayTiddler;
Story.prototype.displayTiddler = function(srcElement,title,template,animate,slowly)
{
	var opt=config.options;
	if (opt.chkSinglePageMode) {
		// close all tiddlers except current tiddler, tiddlers being edited, and tiddlers that are folded (optional)
		story.forEachTiddler(function(tid,elem) {
			if (	tid==title
				|| elem.getAttribute("dirty")=="true"
				|| (opt.chkSinglePageKeepFoldedTiddlers && elem.getAttribute("folded")=="true"))
				return;
			story.closeTiddler(tid);
		});
	}
	else if (opt.chkTopOfPageMode)
		arguments[0]=null;
	else if (opt.chkBottomOfPageMode)
		arguments[0]="bottom";
	if (opt.chkSinglePageMode && opt.chkSinglePagePermalink && !config.browser.isSafari) {
		window.location.hash = encodeURIComponent(convertUnicodeToUTF8(String.encodeTiddlyLink(title)));
		config.lastURL = window.location.hash;
		document.title = wikifyPlain("SiteTitle") + " - " + title;
		if (!config.SPMTimer) config.SPMTimer=window.setInterval(function() {checkLastURL();},1000);
	}
	var tiddlerElem=document.getElementById(story.idPrefix+title); // ==null unless tiddler is already display
	if (tiddlerElem && tiddlerElem.getAttribute("dirty")=="true") { // editing... move tiddler without re-rendering
		var isTopTiddler=(tiddlerElem.previousSibling==null);
		if (!isTopTiddler && (opt.chkSinglePageMode || opt.chkTopOfPageMode))
			tiddlerElem.parentNode.insertBefore(tiddlerElem,tiddlerElem.parentNode.firstChild);
		else if (opt.chkBottomOfPageMode)
			tiddlerElem.parentNode.insertBefore(tiddlerElem,null);
		else this.SPM_coreDisplayTiddler.apply(this,arguments); // let CORE render tiddler
	} else
		this.SPM_coreDisplayTiddler.apply(this,arguments); // let CORE render tiddler
	var tiddlerElem=document.getElementById(story.idPrefix+title);
	if (tiddlerElem&&opt.chkSinglePageAutoScroll) {
		var yPos=ensureVisible(tiddlerElem); // scroll to top of tiddler
		var isTopTiddler=(tiddlerElem.previousSibling==null);
		if (opt.chkSinglePageMode||opt.chkTopOfPageMode||isTopTiddler)
			yPos=0; // scroll to top of page instead of top of tiddler
		if (opt.chkAnimate) // defer scroll until 200ms after animation completes
			setTimeout("window.scrollTo(0,"+yPos+")",config.animDuration+200); 
		else
			window.scrollTo(0,yPos); // scroll immediately
	}
}

if (Story.prototype.SPM_coreDisplayTiddlers==undefined)
	Story.prototype.SPM_coreDisplayTiddlers=Story.prototype.displayTiddlers;

Story.prototype.displayTiddlers = function() {
	// suspend single-page mode (and/or top/bottom display options) when showing multiple tiddlers
	var opt=config.options;
	var saveSPM=opt.chkSinglePageMode; opt.chkSinglePageMode=false;
	var saveTPM=opt.chkTopOfPageMode; opt.chkTopOfPageMode=false;
	var saveBPM=opt.chkBottomOfPageMode; opt.chkBottomOfPageMode=false;
	this.SPM_coreDisplayTiddlers.apply(this,arguments);
	opt.chkBottomOfPageMode=saveBPM;
	opt.chkTopOfPageMode=saveTPM;
	opt.chkSinglePageMode=saveSPM;
}
//}}}

MAST 697/497
[[< Back to Lectures|Lecture Index]]|[[Next>|Sorting-02]]
!Sorting Elements in a List or Array:

Sorting elements is a very common computational task, and consequently, there is a large field of algorithms specializing in this task: 

http://www.sorting-algorithms.com/
{{engindent{{{engindent{
# Strategies
## Insertion
## Selection
## Bubble
## Shell
## Merge
## Heap
# Data Populations
## Random
## Nearly Sorted
## Reversed
## Few Unique
}}}}}}

!

[[< Back|Sorting-01]]|[[Next>|Sorting-03]]
!Insertion Sort:

[[from Lionel's Blog|http://lionel.textmalaysia.com/insertion-sort.html#.UE1Yp44wn4o]]

Insertion sort is a simple sorting algorithm: a comparison sort in which the sorted array (or list) is built one entry at a time. It is much less efficient on large lists than more advanced algorithms such as quicksort, heapsort, or merge sort. However, insertion sort provides several advantages:
** Simple implementation
** Efficient for (quite) small data sets
** Adaptive (i.e., efficient) for data sets that are already substantially sorted: the time complexity is O(n + d), where d is the number of inversions
** More efficient in practice than most other simple quadratic (i.e., O(n2)) algorithms such as selection sort or bubble sort; the best case (nearly sorted input) is O(n)
** Stable; i.e., does not change the relative order of elements with equal keys
** In-place; i.e., only requires a constant amount O(1) of additional memory space

When humans manually sort something (for example, a deck of playing cards), most use a method that is similar to insertion sort.

!
[[< Back|Sorting-02]]|[[Next>|Sorting-04]]
!Insertion Sort:

''Dynamics of Algorithmic Processing in Computer Systems''
Dominik Strzałka* and Franciszek Grabowski† 
Department of Distributed Systems 
Rzeszów University of Technology W. Pola 2, 35-959 Rzeszów, Poland 
 * //strzalka@prz.edu.pl// 
 † //fgrab@prz.edu.pl//
http://www.complex-systems.com/pdf/19-1-4.pdf

{{engindent{{{engindent{Knuth states that sorting is still one of the most important problems in computer processing, taking about 60 to 70% of total processing time. From a theoretical viewpoint, the sorting problem is algorith- mically closed: solutions exist that have a worst-case complexity equal to the lower limit for the sorting problem (i.e., OH log L). But due to the importance of this problem and the new view proposed in this paper, we are still interested in it.

We consider the insertion sort algorithm, which is one of the sim- plest sorting procedures based on the behavior of a bridge player sort- ing their cards before the hand is played (see Figure 1).
The algorithm has two loops. The external loop guarantees that all sorting elements (keys) will be sorted, and an internal loop finds the right place for each sorted key.}}}}}}

<html><img src="01/InsertionSortChart.png" style="height:500px"></html>

!

[[< Back|Sorting-03]]|[[Next>|Sorting-05]]
!Card Sorting:

<html><img src="01/SortCards.png" style="height:300px"></html>

!

[[< Back|Sorting-04]]| [[Return to Lecture Index|Lecture Index]] |[[Next>|Sorting-06]]
!Card Sorting:

Start writing code with [[Bone Code Template|BoneCode]]
{{{
#!/usr/bin/perl
use strict;

# - - - - - H E A D E R - - - - - - - - - - - - - - - - -


# - - - - - U S E R    V A R I A B L E S - - - - - - - -


# - - - - - G L O B A L  V A R I A B L E S  - - - - - -


# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# - - - - - M A I N - - - - - - - - - - - - - - - - - - - -
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -


# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# - - - - - S U B R O U T I N E S - - - - - - - - - - -
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -


# - - - - - EOF - - - - - - - - - - - - - - - - - - - - - -

}}}


!
[[< Back|Sorting-05]]|[[Next>|Sorting-07]]
!Number Sorting: Part 2
The skeleton of the program starts to take shape by filling in the essential elements that will be needed in each section, and making sure all the code runs without errors. 
<html><img src="01/Sort-Part1-PrintOut.png" style="height:700px"></html>


!
[[< Back|Sorting-06]]|[[Next>|Sorting-08]]
!Number Sorting: The SWAP
The essence of the strategy is to identify elements in the array (//i// vs. //i+1//) that are not in numerical order, and then switch their places so that //i// < //i+1//. 
{{{
# 1. Execute Sort . . . . . . .
print "\n\nExecuting Sort . . . . \nstart >> ";
&dump;
foreach my $i (0..$#nums-1)
{	if ($nums[$i] > $nums[$i+1])
	{	# Need to swap places in array: out of ascending order
		my $larger  = $nums[$i];
		$nums[$i]   = $nums[$i+1];
		$nums[$i+1] = $larger;
	}
	print "i = $i >> ";
	&dump();
}	
}}}

The swap step requires an intermediate temporary memory location which is named {{{$large}}} above. However, these three lines of code can be shortened in PERL to a simple dual assignment statement equivalent to (x,y) = (y,x):
{{{
			if ($nums[$k] < $nums[$k-1])
			{ 	($nums[$k], $nums[$k-1]) = ($nums[$k-1], $nums[$k]); }
}}}


!!Output From SWAP Loop
After executing the foreach loop with the SWAP code, here are the results from each iteration.
{{{
Executing Sort . . . . 
start >> 24 217 457 3 -34 18 546
i = 0 >> 24 217 457 3 -34 18 546
i = 1 >> 24 217 457 3 -34 18 546
i = 2 >> 24 217 3 457 -34 18 546
i = 3 >> 24 217 3 -34 457 18 546
i = 4 >> 24 217 3 -34 18 457 546
i = 5 >> 24 217 3 -34 18 457 546
}}}
!
[[< Back|Sorting-07]]|[[Next>|Sorting-09]]
!Number Sorting: ARRAY defined in script
Here's the {{{01b-Sort.pl}}} script from the ~DropBox folder that correctly swaps all array positions to full numerical order within one pass.
{{{
#!/usr/bin/perl
use strict;
# - - - - - H E A D E R - - - - - - - - - - - - - - - - -
# Goal: Sort a series of numbers.
# AGM:2012
# - - - - - U S E R    V A R I A B L E S - - - - - - - -
my @nums = (24, 217, 457, 3, -34, 18, 546);

# - - - - - G L O B A L  V A R I A B L E S  - - - - - -

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# - - - - - M A I N - - - - - - - - - - - - - - - - - - - -
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
print "\n\nI drove 100 miles today and never even left L.A. . . . \n";
print "Sorting Numbers: \n";
foreach my $i (0..$#nums)
{	print "   $i. $nums[$i]\n"; }

# 1. Execute Sort . . . . . . .
print "\n\nBeginning Sort . . . . \n";
my $count = 0;

foreach my $i (0..$#nums-1)
{	# Check for numerical order . . . . . . . 
	if ($nums[$i] > $nums[$i+1])
	{ 	($nums[$i], $nums[$i+1]) = ($nums[$i+1], $nums[$i]);
		# Keep swapping positions to the left before proceeding to next $i
		for (my $k = $i; $k > 0; $k -= 1)
		{	if ($nums[$k] < $nums[$k-1])
			{ 	($nums[$k], $nums[$k-1]) = ($nums[$k-1], $nums[$k]); }
		}
	}
	print "count = $count  >>>  ";
	&dump;
	$count += 1;
} # end foreach $i . . .
	

# 2. Output Sort . . . . . .  

print "\n\n* * * *    D O N E   * * * *\n\n";
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# - - - - - S U B R O U T I N E S - - - - - - - - - - -
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
sub dump
{	print join(' ', @nums), "\n"; }
# - - - - - EOF - - - - - - - - - - - - - - - - - - - - - -
}}}
[[< Back|Sorting-08]]|[[Next>|Sorting-10]]

!LARGE NUMBER SETS
The SORT worked out in the previous page is not very useful in that it is unlikely that you would ever need to use a code loop to sort 7 numbers. Think of the {{{01b-Sort.pl}}} code as a trouble-shooting development script using a small defined number series. Now, let's apply that script to a more realistic scenario where you've got 1000's of data observations that you'd like to analyze by first having them numerically sorted. 

!!Loading Data From File:

The OPEN file I/O handle, is a specialized function in PERL that allows reading and writing of information to files in the "current working folder."

The ''open'' statement initializes an input/output buffer stream. Think of it like a pipe for information flow. You give the pipe a name so the computer knows which piece of plumbing to look at for the data, and you specify the direction of information flow. 

READING: //note the direction of the @@<@@ operator//
{{{
open(HandleName,"<filename");
my @FILE = <HandleName>;
}}}

WRITING: //note the direction of the @@>@@ operator//
{{{
open(HandleName,">filename");   # creates new file, deleting contents of any existing file
print HandleName "This text is now being saved to file . . . .\n";

OR

open(HandleName,">>filename");  # appends text to end of existing file
print HandleName "This text is now being added to file . . . .\n";
}}}



! 
[[< Back|Sorting-09]]|[[Return to Lecture Index>|Lecture Index]]|[[Next>|Sorting-11]]
!BIG DATA SORT
The script {{{01c-Sort.pl}}} has been setup for loading data into the {{{@nums}}} array from a text file, sorting the target numbers, and then writing a new file of sorted numbers appropriate for plotting.

!!File Input Sorting Routine
{{{
#!/usr/bin/perl
use strict;
# - - - - - H E A D E R - - - - - - - - - - - - - - - - -
# Goals: 	1. Load data from file
#		2. Sort the data numbers.
#		3. Output new data file of sorted numbers for plotting.
# AGM:2012

# - - - - - U S E R    V A R I A B L E S - - - - - - - -
my $infile  = "00D-D10-CS1-Pval.txt";
my $outfile = "MySortedData.txt";

# - - - - - G L O B A L  V A R I A B L E S  - - - - - -
my @nums;

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# - - - - - M A I N - - - - - - - - - - - - - - - - - - - -
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
print "\n\nI drove 100 miles today and never even left L.A. . . . \n";

# 1 . LOAD NUMBERS FROM FILE . . . . . .
open(IN, "<$infile") or die "\n\nNADA $infile you FOOL!!!\n\n";
my @DATA = <IN>;
close(IN);
shift(@DATA);
foreach my $line (@DATA)
{	my @data = split('\t', $line);
	push(@nums, $data[3]);          # Read the D2 column, index 3 in @data
}
print "\nThere are ", $#nums+1, " data obs input from file: $infile\n\n";


# 2. Execute Sort . . . . . . .
print "\n\nBeginning Sort . . . . \n";
my $count = 0;
foreach my $i (0..$#nums-1)
{	if ($nums[$i] > $nums[$i+1])
	{ 	($nums[$i], $nums[$i+1]) = ($nums[$i+1], $nums[$i]);
		# Keep swapping positions to the left . . .
		for (my $k = $i; $k > 0; $k -= 1)
		{	if ($nums[$k] < $nums[$k-1])
			{ 	($nums[$k], $nums[$k-1]) = ($nums[$k-1], $nums[$k]); }
		}
	}
	# print "count = $count  >>>  ";
	# &dump;
	$count += 1;
} # end foreach $i . . .
	

# 3. Output Sorted data . . . . . .
print "\nWriting sorted data to file: $outfile\n";
open(OUT, ">$outfile");
foreach my $i (0..$#nums)
{	print OUT "$i\t$nums[$i]\n"; }
close(OUT);


print "\n\n* * * *    D O N E   * * * *\n\n";
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# - - - - - S U B R O U T I N E S - - - - - - - - - - -
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
sub dump
{	print join(' ', @nums), "\n"; }
# - - - - - EOF - - - - - - - - - - - - - - - - - - - - - -		
}}}
[[< Back|Sorting-10]]|[[Next>|Sorting-12]]
!R stats:
You can find the information for obtaining the R statistics package on this page: [[Rstats]].

''R'' is a scripting language that utilizes an interactive environment for running analyses and handling data. For the plotting tasks in this course, you will need to install the @@{{{ggplot2}}}@@ package. Once you have R running on your computer, issue this command: {{{install.packages('ggplot2')}}}

A simple plotting script for the exercise to see if D2 is correctly sorted in the output file '~MySortedData.txt':
{{{
library('ggplot2')

rm(list=ls())
D <- read.table("MySortedData.txt",sep='\t',header=FALSE)
names(D) <- c("N","D2")
summary(D)

p <- ggplot(data=D, aes(x=D2,y=N)) +
		geom_point(colour='blue4',size=1.5) +
		xlab("Distance Score") +
		ylab("Sorted Index Number") +
		opts(title="AGM: 01c-Sort.pl plot")
p

}}}



!
[[< Back|Sorting-11]]|[[Next>|Sorting-13]]
!PERL SORT()
We generated code to perform a numerical sort, with the primary sorting function contained within this code loop:
{{{
# 2. Execute Sort . . . . . . .
foreach my $i (0..$#nums-1)
{	if ($nums[$i] > $nums[$i+1])
	{ 	($nums[$i], $nums[$i+1]) = ($nums[$i+1], $nums[$i]);
		# Keep swapping positions to the left . . .
		for (my $k = $i; $k > 0; $k -= 1)
		{	if ($nums[$k] < $nums[$k-1])
			{ 	($nums[$k], $nums[$k-1]) = ($nums[$k-1], $nums[$k]); }
		}
	}
} # end foreach $i . . .
}}}

''But PERL has its own built in SORT() function that is highly optimized for cpu efficiency.'' The only trick to using it is to make sure that the correct type of sort is set in the specification string. So the sorting loop we coded above can be condensed into the following:
{{{
# 2. Execute Sort . . . . . . .
#---- NUMERICAL SORT ----------------------------
          @nums = sort {$b <=> $a}(@nums);
#------------------------------------------------
}}}

!SORT() MODES:
!!Numerical Sort
{{{@sorted = sort { $a <=> $b } @not_sorted}}}

!!~ASCII-betical Sort 
{{{@sorted = sort { $a cmp $b } @not_sorted}}}

!!Alphabetical Sort
{{{@sorted = sort { lc($a) cmp lc($b) } @not_sorted}}}

!!Get a list of hash keys sorted by value.
{{{@sorted = sort { $hash{$a} cmp $hash{$b} } keys %hash;}}}
{{{
my @keys = sort {$GeneD2{$a} <=> $GeneD2{$b} } (keys %GeneD2);
}}}


!
[[< Back|Sorting-12]]|[[Next>|Sorting-14]]
!Dictionaries
Arrays are a list of values that are stored/accessed by their numerical index position within the array: {{{my @Array = ('apple', 'banana', 'grape');}}}, then the command {{{print $Array[1];}}} would return the value 'apple' on screen.

Often in data sets we have distinct associations between different kinds of observations and so we want to store that information in hierarchical lists, which in PERL are called HASHES but can be generally referred to as DICTIONARIES. For example, consider fruit color organized as follows: {{{ my %FC = ('apple':'red', 'banana':'yellow', 'grape':'purple')}}}. We now have a dictionary defined where instead of accessing elements by index number, they are accessed by a 'key' which here is fruit: {{{print $FC{'apple'};}}} would return the value 'red' to the screen;

In our sorting example, we are going to load the data from the text file and store it in a dictionary using the unique ID number found in the first column. We can then add additional data from the file by adding additional dictionaries:

!01e-Sort.pl
{{{
#!/usr/bin/perl
use strict;
# - - - - - H E A D E R - - - - - - - - - - - - - - - - -
# Goals: 	1. Load data from file
#			2. Sort the data numbers.
#			3. Output new data file of sorted numbers for plotting.
# AGM:2012

# - - - - - U S E R    V A R I A B L E S - - - - - - - -
my $infile = "00D-D10-CS1-Pval-test.txt";
my $outfile = "MySortedData.txt";

# - - - - - G L O B A L  V A R I A B L E S  - - - - - -
my %GeneD2;
my %GeneSD;

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# - - - - - M A I N - - - - - - - - - - - - - - - - - - - -
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
print "\n\nI drove 100 miles today and never even left L.A. . . . \n";

# 1 . LOAD NUMBERS FROM FILE . . . . . .
open(IN, "<$infile") or die "\n\nNADA $infile you FOOL!!!\n\n";
my @DATA = <IN>;
close(IN);
shift(@DATA);
foreach my $line (@DATA)
{	my @data = split('\t', $line);
	# ArrayID, Code, RS, D2, SD, RD, Pval, code
	$GeneD2{$data[0]} = $data[3];
	$GeneSD{$data[0]} = $data[4];
}

# 2. Execute Sort . . . . . . .
print "\n\nBeginning Sort . . . . \n";

#---- Numerical Sort of Dictionary Values ---------------------
my @sortedkeys = (sort {$GeneD2{$a} <=> $GeneD2{$b} } (keys %GeneD2));
#---- Numerical Sort of Dictionary Values ---------------------	

# 3. Output Sorted data . . . . . .
print "\nWriting sorted data to file: $outfile\n";
open(OUT, ">$outfile");
foreach my $i (0..$#sortedkeys)
{	print OUT "$i\t$GeneD2{$sortedkeys[$i]}\t$GeneSD{$sortedkeys[$i]}\n"; }
close(OUT);


print "\n\n* * * *    D O N E   * * * *\n\n";
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# - - - - - EOF - - - - - - - - - - - - - - - - - - - - - -		
			
			
}}}
! 
[[< Back|Sorting-13]]|[[Next>|Sorting-15]]
!Multidimensional Dictionaries
Dictionaries (and arrays) can be multidimensional. On the preceeding page, two dictionaries based on a key of Gene ID were used to each store a separate piece of information about each gene. We can essentially merge those two dictionaries into one structure based on Gene ID, by defining another set of keys as the variable names of the info that we want to store: ''D2'' and ''SD''. Now with one dictionary can can store multiple variables under one Gene ID:
{{{
$Gene{'10025467'}{'D2'} = 235;
$Gene{'10025467'}{'SD'} = 4.345;
}}}


!!01f-Sort.pl
{{{
#!/usr/bin/perl
use strict;
# - - - - - H E A D E R - - - - - - - - - - - - - - - - -
# Goals: 	1. Load data from file
#			2. Sort the data numbers.
#			3. Output new data file of sorted numbers for plotting.
# AGM:2012

# - - - - - U S E R    V A R I A B L E S - - - - - - - -
my $infile = "00D-D10-CS1-Pval-test.txt";
my $outfile = "MySortedData.txt";
my @keys2 = qw | D2 SD |;

# - - - - - G L O B A L  V A R I A B L E S  - - - - - -
my %Gene;
open(OUT, ">$outfile");
print OUT "N";
foreach my $k (@keys2){ print OUT "\t$k";}
print OUT "\n";
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# - - - - - M A I N - - - - - - - - - - - - - - - - - - - -
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
print "\n\nI drove 100 miles today and never even left L.A. . . . \n";

# 1 . LOAD NUMBERS FROM FILE . . . . . .
open(IN, "<$infile") or die "\n\nNADA $infile you FOOL!!!\n\n";
my @DATA = <IN>;
close(IN);
shift(@DATA);
foreach my $line (@DATA)
{	my @data = split('\t', $line);
	# ArrayID, Code, RS, D2, SD, RD, Pval, code
	foreach my $i (0..$#keys2)
	{	$Gene{$data[0]}{$keys2[$i]} = $data[3+$i]; }
}

# 2. Execute Sort . . . . . . .
print "\n\nBeginning Sort . . . . \n";

#---- Numerical Sort of Dictionary Values ---------------------
my @sortedkeys = sort {$Gene{$a}{'D2'} <=> $Gene{$b}{'D2'} } (keys %Gene);
#---- Numerical Sort of Dictionary Values ---------------------	

# 3. Output Sorted data . . . . . .
print "\nWriting sorted data to file: $outfile\n";
foreach my $i (0..$#sortedkeys)
{	print OUT "$i\t$Gene{$sortedkeys[$i]}{'D2'}\t$Gene{$sortedkeys[$i]}{'SD'}\n"; }
close(OUT);


print "\n\n* * * *    D O N E   * * * *\n\n";
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# - - - - - EOF - - - - - - - - - - - - - - - - - - - - - -		
			
			
}}}

!
[[< Back|Sorting-14]]|[[Return to Lecture Index|Lecture Index]]
!Sorting Assignment: ~HW04
The sample data file ''00D-D10-CS1-Pval.txt'' has the following variables defined in the header line:
| ID Num | Gene Code | ~RefSeq | D2 | sumdist | meandiff | delta | pval |

# ~HW04a: Sort SUMDIST
## plot file: ''~XYZ-04a-SUMDIST.png''
### x = sumdist; y = sorted index number
# ~HW04b: Sort MEANDIST
## plot file: ''~XYZ-04b1-MEANDIFF.png''
### x = meandist; y = sorted index number
## calculate a new variable: D2 * sumdist
## plot file:  ''~XYZ-04b2-MEANDIFF.png'' 
### x = meandiff; y = new var

@@NOTE: In the plot files, substitute your last name for 'XYZ'@@ 

!
/***
|''Name:''|SparklinePlugin|
|''Description:''|Sparklines macro|
***/
//{{{
if(!version.extensions.SparklinePlugin) {
version.extensions.SparklinePlugin = {installed:true};

//--
//-- Sparklines
//--

config.macros.sparkline = {};
config.macros.sparkline.handler = function(place,macroName,params)
{
	var data = [];
	var min = 0;
	var max = 0;
	var v;
	for(var t=0; t<params.length; t++) {
		v = parseInt(params[t]);
		if(v < min)
			min = v;
		if(v > max)
			max = v;
		data.push(v);
	}
	if(data.length < 1)
		return;
	var box = createTiddlyElement(place,"span",null,"sparkline",String.fromCharCode(160));
	box.title = data.join(",");
	var w = box.offsetWidth;
	var h = box.offsetHeight;
	box.style.paddingRight = (data.length * 2 - w) + "px";
	box.style.position = "relative";
	for(var d=0; d<data.length; d++) {
		var tick = document.createElement("img");
		tick.border = 0;
		tick.className = "sparktick";
		tick.style.position = "absolute";
		tick.src = "data:image/gif,GIF89a%01%00%01%00%91%FF%00%FF%FF%FF%00%00%00%C0%C0%C0%00%00%00!%F9%04%01%00%00%02%00%2C%00%00%00%00%01%00%01%00%40%02%02T%01%00%3B";
		tick.style.left = d*2 + "px";
		tick.style.width = "2px";
		v = Math.floor(((data[d] - min)/(max-min)) * h);
		tick.style.top = (h-v) + "px";
		tick.style.height = v + "px";
		box.appendChild(tick);
	}
};


}
//}}}
/***

''Inspired by [[TiddlyPom|http://www.warwick.ac.uk/~tuspam/tiddlypom.html]]''

|Name|SplashScreenPlugin|
|Created by|SaqImtiaz|
|Location|http://tw.lewcid.org/#SplashScreenPlugin|
|Version|0.21 |
|Requires|~TW2.08+|
!Description:
Provides a simple splash screen that is visible while the TW is loading.

!Installation
Copy the source text of this tiddler to your TW in a new tiddler, tag it with systemConfig and save and reload. The SplashScreen will now be installed and will be visible the next time you reload your TW.

!Customizing
Once the SplashScreen has been installed and you have reloaded your TW, the splash screen html will be present in the MarkupPreHead tiddler. You can edit it and customize to your needs.

!History
* 20-07-06 : version 0.21, modified to hide contentWrapper while SplashScreen is displayed.
* 26-06-06 : version 0.2, first release

!Code
***/
//{{{
var old_lewcid_splash_restart=restart;

restart = function()
{   if (document.getElementById("SplashScreen"))
        document.getElementById("SplashScreen").style.display = "none";
      if (document.getElementById("contentWrapper"))
        document.getElementById("contentWrapper").style.display = "block";
    
    old_lewcid_splash_restart();
   
    if (splashScreenInstall)
       {if(config.options.chkAutoSave)
			{saveChanges();}
        displayMessage("TW SplashScreen has been installed, please save and refresh your TW.");
        }
}


var oldText = store.getTiddlerText("MarkupPreHead");
if (oldText.indexOf("SplashScreen")==-1)
   {var siteTitle = store.getTiddlerText("SiteTitle");
   var splasher='\n\n<style type="text/css">#contentWrapper {display:none;}</style><div id="SplashScreen" style="border: 3px solid #ccc; display: block; text-align: center; width: 320px; margin: 100px auto; padding: 50px; color:#000; font-size: 28px; font-family:Tahoma; background-color:#eee;"><b>'+siteTitle +'</b> is loading<blink> ...</blink><br><br><span style="font-size: 14px; color:red;">Requires Javascript.</span></div>';
   if (! store.tiddlerExists("MarkupPreHead"))
       {var myTiddler = store.createTiddler("MarkupPreHead");}
   else
      {var myTiddler = store.getTiddler("MarkupPreHead");}
      myTiddler.set(myTiddler.title,oldText+splasher,config.options.txtUserName,null,null);
      store.setDirty(true);
      var splashScreenInstall = true;
}
//}}}
/*{{{*/
/*FONT ADJUSTMENTS*/
body {font-family: Trebuchet MS; font-size: 12pt;}
#mainMenu .tiddlyLinkExisting, #mainMenu .tiddlyLinkNonExisting {font-family: Trebuchet MS; font-size: 11pt;}
#mainMenu {font-family: Trebuchet MS; font-size: 11pt;}
#mainMenu h1 {font-size: 10pt;}
#mainMenu th {background-color:[[ColorPalette::SecondaryPale]]; color:[[ColorPalette::SecondaryDark]];}
#mainMenu table {border:none;}
#mainMenu tr {background-color:white;}
#mainMenu {background-color:[[ColorPalette::PrimaryLight]];}
.viewer {line-height: 1.7em;}
/*WIDEN MAINMENU*/
#mainMenu {width: 14.5em;}
#mainMenu {text-align: left;}
#displayArea {margin: 0em 17em 0em 17em;}
.teeny {font-size: 9pt; text-align: center;}
/*TABLE HEADER*/
.viewer th {color: #000; background-color: #eeeeee;} 
/*TIDDLER TOPMARGIN AND BUTTON BORDER*/
a.button{border: 0;} 
.viewer { margin-top: 1em; }
/*UNORDERED and ORDERED LISTS TWEAK*/
.viewer li {padding-top: 0.0em; padding-bottom: 0.0em;} 
/*LINELESS BLOCKQUOTES*/
.viewer blockquote {border-left: 0px; margin-top:0em; margin-bottom:0em; }
/*HEADLINE COLOR, etc*/
h1,h2,h3,h4,h5 { color: #000; background: none; font-family: Trebuchet MS;}
/*TuDuSlider*/
.tuduSlider .button{font-family: Trebuchet MS; font-weight: bold; font-size: 10pt; color: black;}
/* GIFFMEX TWEAKS TO STYLESHEETPRINT (so that nothing but tiddler title and text are printed) */
@media print {#mainMenu {display: none ! important;}}
@media print {#topMenu {display: none ! important;}}
@media print {#sidebar {display: none ! important;}}
@media print {#messageArea {display: none ! important;}} 
@media print {#toolbar {display: none ! important;}}
@media print {.header {display: none ! important;}}
@media print {.tiddler .subtitle {display: none ! important;}}
@media print {.tiddler .toolbar {display; none ! important; }}
@media print {.tiddler .tagging {display; none ! important; }}
@media print {.tiddler .tagged {display; none ! important; }}
@media print {#displayArea {margin: 1em 1em 0em 1em;}}
@media print {.pageBreak {page-break-before: always;}}
/*CSS FOR BIBLE FORMATTING*/
.engindent {margin-left: 2em; display:block;}
.gkindent {font-family: Gentium; font-size: 16pt; margin-left: 2em; display:block;}
.greek {font-family: Gentium; font-size: 16pt;}
.hebrewNoAlign{font-family: Gentium; font-size: 20pt;}
.hebrewRightAlign{text-align:right; font-family: Gentium; font-size: 20pt; display:block;}
.hebAlignAndIndent{text-align:right; font-family: Gentium; font-size: 20pt; margin-right: 2em; display:block;}
.red {color: #ff3300; font-weight: bold;}
.blue {color: #0000cc; font-weight: bold;}
.green {color: #22bb00; font-weight: bold;}
.gold {color: #bbaa55; font-weight: bold;}
.purple {color: #9922ff; font-weight: bold;}
.gray {color: #777777; font-weight: bold;}
.magenta{color: #cc0066; font-weight: bold;}
.teal {color: #008888; font-weight: bold;}
.burgundy {color: #990000; font-weight: bold;}
.orange {color: #ff8866; font-weight: bold;}
/*INVISIBLE TABLE*/
.viewer .invisiblecomm table {border-color: white;}
.viewer .invisiblecomm table td { font-size: 1em; font-family: Verdana; border-color: white; padding: 10px 20px 10px 0px; text-align: left; vertical-align: top; padding-bottom: 20px;} 
.viewer .invisiblecomm table th {color:[[ColorPalette::PrimaryMid]]; background-color: white; border-color: white; font-family: Verdana; font-size: 1.2em; font-weight: bold; padding: 10px 20px 10px 0px; text-align: left; vertical-align: top;} 
.viewer .invisiblecomm table tr.leftColumn { background-color: #bbbbbb; }
/*OTHER TABLES*/
.menubox { display:block; padding:1em; -moz-border-radius:1em; border:1px solid; background:[[ColorPalette::TertiaryDark]]; color:#000; }
.menubox2 { display:block; padding: .25em; border:none; margin: 0; background:[[ColorPalette::TertiaryDark]]; [[ColorPalette::SecondaryDark]]; text-align: center; font-size: 1.6em;}
.menubox3 { display:block; padding:.25em; border:none; margin: 0; background:[[ColorPalette::TertiaryDark]]; [[ColorPalette::SecondaryDark]]; text-align: center; font-size: 2.5em;}
.viewer th {background-color:[[ColorPalette::SecondaryPale]]; [[ColorPalette::SecondaryDark]]}
.tableindex table, .tableindex td, .tableindex tr { font-size: 1em; border: solid white; background-color:[[ColorPalette::SecondaryPale]]; [[ColorPalette::SecondaryDark]]}
/*}}}*/
/*{{{*/
* 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.0em; line-height:1.0em; overflow:auto;}
.viewer code {font-size:1.0em; line-height:1.0em;}

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

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

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

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

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

.whenBackstage {display:none;}
.backstageVisible .whenBackstage {display:block;}
/*}}}*/
Subtopic menus are menus at the top of the topic tiddlers, like the one above, which has three subtopics: "Welcome", "Instructions", and "Subtopic menu instructions". You can have a separate subtopic menu for as many topics as you add to your mainmenu. There are three steps to creating a new subtopic menu. You may do these steps in any order you wish:
#''Create tiddlers for each of the subtopics within a topic.'' Tag them all with one appropriate tag pertaining to the topic. This will link them all so that they appear in the subtopic menu.
#''Create a subtopic menu tiddler.'' This will be the tiddler where the menu that appears above the other tiddlers is stored. In the Sidebar, click on 'new subtopic menu'. Replace 'tagname' in the title with the name of the tag you added to the tiddlers above. Then add the title of your subtopic tiddlers in the table provided, within the double brackets {{{[[ ]]}}}. Three table cells have been provided. Delete or add table cells as needed.
#''Create a custom ~ViewTemplate for your topic.'' This will tell ~TiddlyWiki to show your subtopic menu at the top of all the tiddlers that you have tagged with that topic's tag. In the Sidebar, click on 'new viewtemplate'. Replace 'tagname' with the tag you added to the tiddlers above. Do this for the title of the tiddler, as well as in the two instances of 'tagname' in the viewtemplate's code (it will look like the line shown below before you change it).
<!--{{{-->
<div class='tagnameMacro='tiddler tagnameSubtopicmenu'></div>
<!--}}}-->
That's it. A menu of links to the tiddlers you have tagged and added to your subtopic menu tiddler should appear above the tiddler title of each of those tiddlers.
!Course Summary: FALL 2015

Course grades are determined as follows:
{{engindent{{{engindent{
# 20% Class Participation
# 40% Homework Assignments
# 20% Project 01: Genome Analysis
# 20% Project 02: ~PubMed Literature Analysis
}}}}}}
|! DATE |! Subject |! Reference |! Code Work |! Home Work |
|SEP 02 WED|Introduction | Chap 1 PDF| [[Tic Tac Toe Board|TicTacToe-01]] | |
|SEP 07 MON|>|>|>|bgcolor(orange): LABOR DAY: NO CLASS |
|SEP 09 WED | [[Code Mechanics|Mechanics-01]] | Chap 2 PDF  | [[ Human Tic Tac Toe|TicTacToe-07]]  | |
|SEP 14 MON | [[TicTacToe Winner Algorithm|TicTacToe Winner 01]]| Chap 3 PDF  | |bgcolor(yellow): ~HomeWork-01 DUE in class  |
|SEP 16 WED | ~TicTacToe Analysis | R Stats  |  | |
|SEP 21 MON | Basic Code Work |   | foreach |bgcolor(yellow): ~HomeWork-02 DUE in class   |
|SEP 23 WED | Basic Code Work |  | full script  | |
|SEP 28 MON | Sorting Algorithms |  | |bgcolor(yellow): ~HomeWork-03 DUE in class   |
|SEP 30 WED | Sorting Analyses |  |   | |
|OCT 05 MON | Restriction Digests |  | |bgcolor(yellow): ~HomeWork-04 DUE in class    |
|OCT 07 WED | Restriction Profiling |  | | |
|OCT 12 MON | Control/Worker Scripting | RE digests  | |bgcolor(yellow): ~HomeWork-05 DUE in class |
|OCT 14 WED | RE Multiple Genomes |  |    | |
|OCT 19 MON | RE x %GC Analysis |  | |bgcolor(yellow): ~HomeWork-06 DUE in class |
|OCT 21 WED | RE x %GC Analysis |  | | |
|OCT 26 MON | HTML Parsing |  | | |
|OCT 28 WED | ~PubMed Parsing |  | | |
|NOV 02 MON | FASTA File I/O | | |bgcolor(yellow): ~HomeWork-07 DUE in class |
|NOV 04 WED | FASTA Parse/Analysis  | | | |
|NOV 09 MON | Codon Usage |  | | |
|NOV 11 WED | Amino Acid Bias |  |    | |
|NOV 16 MON | Genome Analysis |  | |bgcolor(yellow): ~HomeWork-08 DUE in class |
|NOV 18 WED | Genome Profiling |   |  | |
|NOV 23 MON |>|>|>|bgcolor(orange): THANKSGIVING BREAK: NO CLASS |
|NOV 25 WED |>|>|>|bgcolor(orange): THANKSGIVING BREAK: NO CLASS |
|NOV 30 MON | Shakespeare's Monkeys |  | |bgcolor(yellow): Project-01 DUE via email   |
|DEC 02 WED | Recombinometrics | | | |
|DEC 07 MON | Genetic Algorithms | | | |
|DEC 09 WED | Entropy |  | | |
|DEC 14 MON | FINALS WEEK | | |bgcolor(yellow): Project-02 DUE via email |
/%
[[Sorting Pt 1|Sorting-01]]
[[Sorting Pt 2|Sorting-06]]
|bgcolor(blue): Current . . .|>|>|>|>|
| | Sequence Alignment |  | |bgcolor(yellow): ~HomeWork-09 DUE in class |
%/
!
!
/***
|Name|TaggedTemplateTweak|
|Source|http://www.TiddlyTools.com/#TaggedTemplateTweak|
|Documentation|http://www.TiddlyTools.com/#TaggedTemplateTweakInfo|
|Version|1.1.0|
|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.01.22 [*.*.*] plugin size reduction - documentation moved to [[TaggedTemplateTweakInfo]]
2007.06.23 [1.1.0] re-written to use automatic 'tag prefix' search instead of hard coded check for each tag.  Allows new custom tags to be used without requiring code changes to this plugin.
| please see [[TaggedTemplateTweakInfo]] for previous revision details |
2007.06.11 [1.0.0] initial release
<<<
!!!!!Code
***/
//{{{
version.extensions.taggedTemplate= {major: 1, minor: 1, revision: 0, date: new Date(2007,6,23)};
Story.prototype.taggedTemplate_chooseTemplateForTiddler = Story.prototype.chooseTemplateForTiddler
Story.prototype.chooseTemplateForTiddler = function(title,template)
{
	// get default template from core
	var template=this.taggedTemplate_chooseTemplateForTiddler.apply(this,arguments);

	// if the tiddler to be rendered doesn't exist yet, just return core result
	var tiddler=store.getTiddler(title); if (!tiddler) return template;

	// look for template whose prefix matches a tag on this tiddler
	for (t=0; t<tiddler.tags.length; t++) {
		var tag=tiddler.tags[t];
		if (store.tiddlerExists(tag+template)) { template=tag+template; break; }
		// try capitalized tag (to match WikiWord template titles)
		var cap=tag.substr(0,1).toUpperCase()+tag.substr(1);
		if (store.tiddlerExists(cap+template)) { template=cap+template; break; }
	}

	return template;
}
//}}}
{{{
<html>
<div style="color: rgb(100, 100, 150); font-family: Monaco;">
<big><big><b>
xxxx
</html>
}}}
!Bootstrap replicate runs of the ~TicTacToe 'Engine'

{{{
#!/usr/bin/perl
use strict;

#------- HEADER --------------------------------
# TicTacToe: code mechanics review for MAST698/498 Environmental Bioinformatics.
# v1 = TicTacToe - the game board and stdin play
# v2 = + Game Winner subroutine
# v3 = + Computer players via random moves; score winning marker
# v4 = + Iteration to calc mean results
#
# AGM2013


#-------  GLOBAL VARIABLES -------------------------------
my @cells = qw | 1 2 3 4 5 6 7 8 9 |;       # define cell state
my @markers = qw | X O |;
my $GameOver = 'FALSE';
my $Winner = 'D';                            
my %WinLossDraw = {};
my $BootStrap = 100;

#--------  MAIN ------------

&BOARD;
print "\n\nRunning SuperBowl XLVIII championship series: . . . \n";

foreach my $game (1..$BootStrap)
{ # GAME LOOP . . . . . . . . . . . . . .
	# Initialize starting vars . . . . . . 
	$GameOver = 'FALSE';
	$Winner = 'D';
	@cells = qw | 1 2 3 4 5 6 7 8 9 |;
	# Start Game . . . . . .
	foreach my $move (1..9)
	{	my $turn = shift(@markers);
		push(@markers, $turn);
		my $z = -1;                        # declare var $z with a default value
		my $turndone = 0;                  # exit flag for while loop (like a boolean true/false)
		while($turndone == 0)              # set condition for while loop execution
		{	$z = int(rand(10));            # rand(N) returns a float; $z needs just the integer 
			if ($cells[$z-1] =~ m/\d/)     # if pos z-1 is a digit (not 'X' or 'O') then the square is 'open'
			{	$turndone = 1; }           # set exit condition when an 'open' square has been selected
		}
		if ($z == -1) { print "\n\nError in rand number selection!!\n\n"; die;}     # unlikely . . . . but . . .
		$cells[$z-1] = $turn;              # make the move . . . .
		&WINNER;
	
		if ($GameOver eq 'TRUE')
		{	last;  }
		
	} # End of Game
	# Score Results . . . . . . . . .
	$WinLossDraw{$Winner} += 1;
	
} # $BootStrap

# Tally Game Results:
my $Xwin = $WinLossDraw{'X'}/$BootStrap;
my $Ywin = $WinLossDraw{'O'}/$BootStrap;
my $Draw = $WinLossDraw{'D'}/$BootStrap;

print "\n\nResults of $BootStrap games:\n";
printf ("   X wins %0.3f of the time\n", $Xwin);
printf ("   O wins %0.3f of the time\n", $Ywin);
printf ("   Draw   %0.3f of the time\n", $Draw);



print "\n* * * *     D  O  N  E    * * * * \n\n";

#--------- SUBROUTINES -----------
sub BOARD
{	system('clear');    
	print "\n\n\nThis is my TicTacToe Game\n\n\n";
	my $position = 0;                          # set initial position 0
	foreach (1..3)                             # control loop for rows
	{   print "   |";                          # start each row with |
		foreach (1..3)                         # control loop for columns
		{   print "_$cells[$position]_|";      # print each individual cell
			$position += 1;                    # increment counter
		}
		print "\n";                            # end each row with RETURN
	}
}
#---------------------------------------
sub WINNER
{	my $s = 3;
	my @gamemarkers;
	my $WIN;
	# row check . . . . . . . 
	foreach my $n (0..$s-1)
	{	my $start = $n*3;
		foreach my $m (0..2)
		{	$gamemarkers[$m] = $cells[$start + $m]; }
		$WIN = CheckIt(@gamemarkers);
		if ($WIN eq 'YES')
		{	$GameOver = 'TRUE';
			last;
		}
	}
	
	if ($GameOver eq 'FALSE')
	{	# column check . . . . . . .
		foreach my $n (0..$s-1)
		{	my $start = $n;
			foreach my $m (0..2)
			{	$gamemarkers[$m] = $cells[$start + $m*3]; }
			$WIN = CheckIt(@gamemarkers);
			if ($WIN eq 'YES')
			{	$GameOver = 'TRUE';
				last;
			}
		}
		if ($GameOver eq 'FALSE')
		{	# diag check . . . . . . .
			foreach my $n (0..1)
			{	my $start = $n*2;
				foreach my $m (0..2)
				{	$gamemarkers[$m] = $cells[$start + $m*4 - $n*$m*2]; }
				$WIN = CheckIt(@gamemarkers);
				if ($WIN eq 'YES')
				{	$GameOver = 'TRUE';
					last;
				}
			}
		}
	}
}
#---------------------------------------
sub CheckIt
{	my @gm = @_;
	my $sumcheck = 0;
	foreach my $n (0..1)
	{	if ($gm[$n] eq $gm[$n+1])
		{	$sumcheck += 1; }
	}
	if ($sumcheck == 2)
	{	$Winner = $gm[0];           # Keep track of the Winning Marker
		return "YES";
	}
	else
	{	return "NO"; }
	
}
#--- EOF -------------------------------

}}}
!
!~TicTacToe 3rd version
CPU players now make random moves. Game play is automatic.
{{{
#!/usr/bin/perl
use strict;

#------- HEADER --------------------------------
# TicTacToe: code mechanics review for MAST698/498 Environmental Bioinformatics.
# v1 = TicTacToe - the game board and stdin play
# v2 = + Game Winner subroutine
# v3 = + Computer players via random moves; score winning marker
#
# AGM2013


#-------  GLOBAL VARIABLES -------------------------------
my @cells = qw | 1 2 3 4 5 6 7 8 9 |;       # define cell state
my @markers = qw | X O |;
my $GameOver = 'FALSE';
my $Winner = 'D';                             # new var to track the winning marker; default D = draw; see sub CheckIt()
my %WinLossDraw = {'X'=>0, 'O'=>0, 'D'=>0 };  # ugly long-hand method - don't ever do this
                                              # used only to clarify this hash array for you now

#--------  MAIN ------------
&BOARD;

foreach my $move (1..9)
{	my $turn = shift(@markers);
	push(@markers, $turn);
	my $z = -1;                        # declare var $z with a default value
	my $turndone = 0;                  # exit flag for while loop (like a boolean true/false)
	while($turndone == 0)              # set condition for while loop execution
	{	$z = int(rand(10));            # rand(N) returns a float; $z needs just the integer 
		if ($cells[$z-1] =~ m/\d/)     # if pos z-1 is a digit (not 'X' or 'O') then the square is 'open'
		{	$turndone = 1; }           # set exit condition when an 'open' square has been selected
	}
	if ($z == -1) { print "\n\nError in rand number selection!!\n\n"; die;}     # unlikely . . . . but . . .
	$cells[$z-1] = $turn;              # make the move . . . .
	#&BOARD;                           # don't need to draw the board each turn
	&WINNER;

	if ($GameOver eq 'TRUE')
	{	print "\n\nWINNER!\n Game Over\n\n";
		last;
	}
}

print "\n";
&BOARD;             # Draw the board to see the full game

# Score Results . . . . . . . . .
$WinLossDraw{$Winner} += 1;
if ($GameOver eq 'TRUE')
{	print "The winner was: $Winner\n\n"; }
else
{	print "The game was a draw: $Winner\n\n"; }



#--------- SUBROUTINES -----------
sub BOARD
{	system('clear');    
	print "\n\n\nThis is my TicTacToe Game\n\n\n";
	my $position = 0;                          # set initial position 0
	foreach (1..3)                             # control loop for rows
	{   print "   |";                          # start each row with |
		foreach (1..3)                         # control loop for columns
		{   print "_$cells[$position]_|";      # print each individual cell
			$position += 1;                    # increment counter
		}
		print "\n";                            # end each row with RETURN
	}
}
#---------------------------------------
sub WINNER
{	my $s = 3;
	my @gamemarkers;
	my $WIN;
	# row check . . . . . . . 
	foreach my $n (0..$s-1)
	{	my $start = $n*3;
		foreach my $m (0..2)
		{	$gamemarkers[$m] = $cells[$start + $m]; }
		$WIN = CheckIt(@gamemarkers);
		if ($WIN eq 'YES')
		{	$GameOver = 'TRUE';
			print "\n>>",@gamemarkers,"<<\n";
			last;
		}
	}
	
	if ($GameOver eq 'FALSE')
	{	# column check . . . . . . .
		foreach my $n (0..$s-1)
		{	my $start = $n;
			foreach my $m (0..2)
			{	$gamemarkers[$m] = $cells[$start + $m*3]; }
			$WIN = CheckIt(@gamemarkers);
			if ($WIN eq 'YES')
			{	$GameOver = 'TRUE';
				last;
			}
		}
		if ($GameOver eq 'FALSE')
		{	# diag check . . . . . . .
			foreach my $n (0..1)
			{	my $start = $n*2;
				foreach my $m (0..2)
				{	$gamemarkers[$m] = $cells[$start + $m*4 - $n*$m*2]; }
				$WIN = CheckIt(@gamemarkers);
				if ($WIN eq 'YES')
				{	$GameOver = 'TRUE';
					last;
				}
			}
		}
	}
}
#---------------------------------------
sub CheckIt
{	my @gm = @_;
	my $sumcheck = 0;
	foreach my $n (0..1)
	{	if ($gm[$n] eq $gm[$n+1])
		{	$sumcheck += 1; }
	}
	if ($sumcheck == 2)
	{	$Winner = $gm[0];           # Keep track of the Winning Marker
		return "YES";
	}
	else
	{	return "NO"; }
	
}
#--- EOF -------------------------------

}}}
!R Stats
This script takes an input file generated by the ~TicTacToe Replicate Model script ([[TicTacToe SuperBowl]]) and generates an analysis and plot of the DRAW, X winner and O winner frequencies.
{{{
#-------------------------------------------
# TicTacToe Winner Distribution Profiles
# Input file Format:
#    Tab-Delimited txt file with two columns with headers	
#       COL-1: "Winner" = a symbol representing the game outcome
#		COL-2: "Score"  = fractional representation of that outcome in the sample
# Example File Text:
#	Winner	Score
#	O	0.740
#	X	0.140
#	D	0.120
#	O	0.650
#	X	. . . .
#
# agm14
#-------------------------------------------

# install.packages('ggplot2')
library(ggplot2)


# 1. Input Data . . . . . . 
rm(list=ls())
d = read.table("TicTacToe-datatable-0910.txt", sep="\t",header=TRUE)
summary(d)


# 2. Generate Freq Distribution Plots . . . . . .  
p <-ggplot(d, aes(x=Score, group=Winner)) +
	geom_histogram(aes(fill=Winner),colour="grey30",size=0.5,binwidth=0.0175) +
	facet_wrap(~Winner,ncol=1) +
	labs(title="TicTacToe SuperBowls")
p

ggsave(p,file="Rplot-TicTacToe-dataplot-0910.pdf",dpi=300)



# 3. Run Stat Tests . . . . . . . . . . . . . . . . . . 
means <- tapply(d$Score, d$Winner, mean)
anova <- aov(Score ~ Winner , data=d)
tukey <- TukeyHSD(anova, ordered=TRUE, conf.level=0.95)


# screen dump results . . . . . . . . . ..
means
summary(anova)
tukey
# plot(TukeyHSD(anova, "Winner"))

#----------------------------------------------------
# EOF
#----------------------------------------------------


}}}
!
!Bootstrap Superbowl ~TicTacToe

{{{
#!/usr/bin/perl
use strict;
$| = 1;  

# - - - - - H E A D E R - - - - - - - - - - - - - - - - -
# Goal: Play Tic Tac Toe
#	  1. Takes TicTacToe moves from human players.
#     2. Variable board grid - user input
#	  3. Winner subroutine to end game 
#     4. Store move sequence data
#     5. Convert turn moves to random computer play
#     6. Bootstrap iteration for mean stats
#     7. Replicate for model stats
#
# MAST497/697|AGM-2014

# - - - - - U S E R    V A R I A B L E S - - - - - - - -
my $size      = 3;            # board grid size
my $BootStrap = 100;          # iterations
my $Replicate = 500;          # replicate runs
my $outfile   = "TicTacToe-datatable-0910.txt";

# - - - - - G L O B A L  V A R I A B L E S  - - - - - -
my $SIZE = $size**2-1;        # max index number of board grid 
my $GameOver = 'FALSE';       # Game status for exit condition
my @marker = ("X", "O");      # Turn markers for game play
my @cell = (0..$SIZE);        # Stores grid cell contents; empty = index integer
my @Sequence;                 # Stores move sequence for each game
my $Winner = 'D';             # Game result = "D" Draw; "X" winner; "O" winner
my %WIN;
my @Keys = qw | X O D |;

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# - - - - - M A I N - - - - - - - - - - - - - - - - - - - - -
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

# SETUP - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
open(OUT,">$outfile");        # open an output to file named 'OUT'  
print OUT "Winner\tScore\n";  # print column headers to outfile

# Screen Intro . . . . . . . . . . .
print "\n\nRunning TicTacToe Analysis:\n";
print "         grid size  = $size x $size\n";
print "         BootStrap  = $BootStrap\n";
print "         Replicates = $Replicate\n";
print "\n\n";

# Hypothesis . . . . .


# WORK - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

foreach my $r (1..$Replicate)
{	# Progress counter . . . . . . . .
	if (($r % 15) == 0 ){	print " $r "; }
	
	# Bootstrap loop for winner frequencies . . . ..  . . . .  .
	foreach my $b (1..$BootStrap)
	{	# 1. Setup the VARS for game play . . . . . . .
		$GameOver = 'FALSE';       # Game status for exit condition
		@marker = ("X", "O");      # Turn markers for game play
		@cell = (0..$SIZE);        # Stores grid cell contents; empty = index integer
		$Winner = 'D';             # Game result = "D" Draw; "X" winner; "O" winner
	
		# 2. Play the game . . . . . . .
		foreach my $move (0..$SIZE)
		{	if ($GameOver eq 'FALSE')
			{	&PlayGame;     # < Get move input and manage board display
				&WINNER;       # < Check for WIN condition (sets $GameOver status)
			}
			else
			{	last; }
		}	
		
		# 3. Save Data . . . . . 
		$WIN{$Winner} += 1;
		
	} # end BootStrap . . . . . . . . . 
	
	# 4. Write data to file . . . . . . . . 
	foreach my $key (@Keys)
	{	my $mean = $WIN{$key}/$BootStrap;
		printf OUT ("%s\t%0.3f\n", ($key,$mean));
		$WIN{$key} = 0;
	}
	
} # end Replicate . . . . 

# CLEAN UP - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# EXIT Routine . . . . . . .

print "\n\nExiting TicTacToe script.\nRunning R Analysis . . . \n";
print "\n-------------------------------------------------------\n";

#-------------------------------------------------------
# Run R Analysis Script . . . . .
system('R --vanilla <06-ResultsPlotDistribution.R');
#-------------------------------------------------------



print "\n\n* * * * D O N E  * * * * * \n\n";

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# - - - - - S U B R O U T I N E S - - - - - - - - - - - - - -
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
sub WINNER
{	my $markers = "";
	my @cellstrings;
 
	# Set the match strings . . . . . 
	my $winX = 'X' x $size;
	my $winO = 'O' x $size;
			
	# row check . . . . . . . 
	foreach my $n (0..$SIZE)
	{	my $first = $n*$size;
		$markers = "";
		foreach my $m (0..$SIZE)
		{	$markers = $markers . $cell[$first + $m];}
		push(@cellstrings, $markers);
	}

	# column check . . . . . . .
	foreach my $n (0..$SIZE)
	{	my $first = $n;
		$markers = "";
		foreach my $m (0..$SIZE)
		{	$markers = $markers . $cell[$first + $m*$size];}
		push(@cellstrings, $markers);
	}

	# diag check . . . . . . .
	foreach my $n (0..1)
	{	my $first = $n*($SIZE);
		$markers = "";
		foreach my $m (0..$SIZE)
		{	$markers = $markers . $cell[$first + $m*($size+1) - $n*$m*2];}
		push(@cellstrings, $markers);
	}
	
	# WINNER CHECK . . . . . . . .
	foreach my $string (@cellstrings)
	{	if ($string eq $winX)
		{	$GameOver = "TRUE";
			$Winner = "X";
			last;
		}
		if ($string eq $winO)
		{	$GameOver = "TRUE";
			$Winner = "O";
			last;
		}
	}
}

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
sub PlayGame
{	my $xo = shift(@marker);
	push(@marker, $xo);
	my $validmove = "FALSE";
	while($validmove eq "FALSE")
	{# Random Computer Generated Moves . . . . .
		my $turn = int(rand($SIZE+1));                     # rand(N) returns a float; $z needs just the integer
		if ($cell[$turn] =~ m/\d/)                         # << a regex conditional test
		{	$cell[$turn] = $xo;
			$validmove = "TRUE";
			push(@Sequence, $turn);
		}
	}
}

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# - - - - - EOF - - - - - - - - - - - - - - - - - - - - - -
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -





}}}
!
[[<Back|Mechanics-03]]|[[Next>|TicTacToe Winner 02]]
!~TicTacToe Code Work Assignment

The task of drawing a ~TicTacToe grid for two-person game play is a very simple algorithm. Now we are going to add another logic step to that algorithm in the form of a decision point to assess whether a winning stage has been reached:

<html><table><tr>
<td><img src="01/FlowChart1.pptx.png" style="height:400px"></td>
<td><img src="01/FlowChart2.pptx.png" style="height:400px"></td>
</tr></table></html>

By imposing a WINNER DECLARATION function, we are essentially establishing an algorithm to control the 'flow' of the game. The first coding assignment [[see Assignments|CodeWork]] utilizes this flow control expansion to:
* Allow the script to declare a winner with a full row, col, diag
* Allow for 2 virtual players to play by making random moves
* Iterate, tracking winners, and calculate:
** probability of winning when moving first
** probability of winning when moving second
** probability of winning when first move is in an outside corner
** probability of winning when second move is in center
[[< Back|TicTacToe Winner 01]]|[[Next>|TicTacToe Winner 03]]
!~TicTacToe Winner:

If the board is grided with the following cell numbers:
{{{
                     |-----|-----|-----|
                     |  1  |  2  |  3  |
                     |-----|-----|-----|
                     |  4  |  5  |  6  |
                     |-----|-----|-----|
                     |  7  |  8  |  9  |
                     |-----|-----|-----|
}}}
the computer keeps track of the cell contents as a linear array or vector:
{{{
     cell address:  0  1  2  3  4  5  6  7  8 
     cell contents: X  O  -  X  O  -  X  -  O
}}}
then, the winning combinations will be any row or column or diagonal containing the same 'marker' as defined by cell numbers:
| ROWS: | 1, 2, 3 | 4, 5, 6 | 7, 8, 9 |
| COLUMNS: | 1, 4, 7 | 2, 5, 8 | 3, 6, 9 |
| DIAGONALS: | 1, 5, 9 | 3, 5, 7 | |
Now we need to think about how to express these series of numbers as a numerical pattern that the CPU can evaluate. This pattern processing can then be implemented by an ALGORITHM . . . . 



!
[[< Back|TicTacToe Winner 02]]|[[Next>|TicTacToe Winner 04]]
!~TicTacToe Winner:

Now we need to think about how to express these series of numbers as a numerical pattern that the CPU can evaluate. This pattern processing can then be implemented by an ALGORITHM:
|bgcolor(yellow): ROWS: |bgcolor(yellow): |bgcolor(yellow): |
| | row number | n{0..2} |
| | start of each row | m = n*3 + 1 |
| | cell addresses | m, m+1, m+2 |
|bgcolor(yellow): COLUMNS: |bgcolor(yellow): |bgcolor(yellow): |
| | col number | p{0..2} |
| | start of each col | q = p + 1 |
| | cell addresses | q, q+3, q+6 |
|bgcolor(yellow): DIAGONALS: |bgcolor(yellow): |bgcolor(yellow): |
| | diag number | r = {0..1} |
| | start of each diag | s = r*2 + 1 |
| | cell addresses diag #1 | s, s+4, s+8 |
| | cell addresses diag #2 | s, s+2, s+4 |

Here's the mechanics of the algorithm to identify the cell contents that need to be compared for each possible winning combination. The strategy here is to load the contents of the target cells into another array called '@gamemarkers' and then use a subroutine to check if all the '$gamemarkers' are the same.
{{{
# row check . . . . . . . 
	foreach my $n (0..2)
	{	my $start = $n*3;
		foreach my $m (0..2)
		{	$gamemarkers[$m] = $cells[$start + $m]; }
		$WIN = CheckIt(@gamemarkers);
	}

# column check . . . . . . .
	foreach my $n (0..2)
	{	my $start = $n;
		foreach my $m (0..2)
		{	$gamemarkers[$m] = $cells[$start + $m*3]; }
		$WIN = CheckIt(@gamemarkers);
	}

# diag check . . . . . . .
	foreach my $n (0..1)
	{	my $start = $n*2;
		foreach my $m (0..2)
		{	$gamemarkers[$m] = $cells[$start + $m*4 - $n*$m*2]; }
		$WIN = CheckIt(@gamemarkers);
	}
}}}

!
[[< Back|TicTacToe Winner 03]]|[[Return to Index>|Lecture Index]]
!~TicTacToe Winner:

Version includes the WINNER recognition algorithm:
{{{
#!/usr/bin/perl
use strict;

# - - - - - H E A D E R - - - - - - - - - - - - - - - - -
# Goal: Play Tic Tac Toe
#        1. Takes TicTacToe moves from human players.
#        2. Variable board grid - user input
#	  3. Winner subroutine to end game 
#        4. Store move sequence data
#
# MAST497/697|AGM-2014

# - - - - - U S E R    V A R I A B L E S - - - - - - - -
my $name = "Adam";
my $size = 3;

# - - - - - G L O B A L  V A R I A B L E S  - - - - - -
my $GameOver = 'FALSE';
my @marker = ("X", "O");
my @cell;
foreach my $i (0..$size**2-1)
{	push(@cell, $i); }
my @Sequence;


# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# - - - - - M A I N - - - - - - - - - - - - - - - - - - - -
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

# 1. Start Game = Display Board and Input Command . . . . 
&BOARD;

# 2. Play the game . . . . . . .
foreach my $move (0..$size**2-1)
{	if ($GameOver eq 'FALSE')
	{	&PlayGame; }
	else
	{	# If $GameOver is TRUE . . . . . 
		print "\n\nWINNER!\nGame Over\n\n";
		last;
	}
}

# Mssg on TIE . . . . . . .  .
if ($GameOver eq 'FALSE')
{	print "\n\nTIE GAME . . . .\n\n";}

# 3. Exit . . . . . . .
print "Here's the game move sequence . . . \n";
print join(", ",@Sequence);

print "\n\n* * * * D O N E  * * * * * \n\n";

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# - - - - - S U B R O U T I N E S - - - - - - - - - - -
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
sub WINNER
{	my $markers = "";
	my @cellstrings;
 
	# Set the match strings . . . . . 
	my $winX = '';
	foreach (0..$size-1){ $winX .= "X";}
	my $winO = '';
	foreach (0..$size-1){ $winO .= "O";}
			
	# row check . . . . . . . 
	foreach my $n (0..$size-1)
	{	my $first = $n*$size;
		$markers = "";
		#print ">> rows $n: ";
		foreach my $m (0..$size-1)
		{	$markers = $markers . $cell[$first + $m];
			#print $first + $m, "  ";
		}
		#print "\n\n";
		push(@cellstrings, $markers);
	}

	# column check . . . . . . .
	foreach my $n (0..$size-1)
	{	my $first = $n;
		$markers = "";
		#print ">> cols $n: ";
		foreach my $m (0..$size-1)
		{	$markers = $markers . $cell[$first + $m*$size];
			#print $first + $m*$size, "  ";
		}
		#print "\n\n";
		push(@cellstrings, $markers);
	}

	# diag check . . . . . . .
	foreach my $n (0..1)
	{	my $first = $n*($size-1);
		$markers = "";
		#print ">> diags $n: ";
		foreach my $m (0..$size-1)
		{	$markers = $markers . $cell[$first + $m*($size+1) - $n*$m*2];
			#print $first + $m*($size+1) - $n*$m*2, "  ";
		}
		#print "\n\n";
		push(@cellstrings, $markers);
	}
	
	# WINNER CHECK . . . . . . . .
	print "\n\nCell Strings . . . . \n";
	foreach my $string (@cellstrings)
	{	print "     $string\n";
		if ($string eq $winX || $string eq $winO )
		{	$GameOver = "TRUE"; }
	}
	
}

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
sub PlayGame
{	my $xo = shift(@marker);
	push(@marker, $xo);
	print "Please Enter position for $xo marker: ";
	# Input and Validation . . . . . .
	my $validmove = "FALSE";
	while($validmove eq "FALSE")
	{	my $turn = <STDIN>;
		chomp($turn);
		# if ($cell[$turn] ne 'X' && $cell[$turn] ne 'O')  # << strict conditional test
		if ($cell[$turn] =~ m/\d/)                         # << a regex conditional test
		{	# IF TRUE: location input is a valid move . . . . . . . . . . .
			$cell[$turn] = $xo;
			$validmove = "TRUE";
			push(@Sequence, $turn);
		}
		else
		{	# IF FALSE: location input is already occupied by a previous move . . . . .  
			print "cheater . . . try again . . . \n";
			print "Please Enter VALID position for $xo marker: ";
		}
	}
	&BOARD;
	&WINNER;
}

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
sub BOARD
{	system("clear");           #   PC= "cls"
	print "\n\nThis is $name\'s TicTacToe Game:\n\n";
	my $pos = 0;
	print "\n\n--------------------------------------\n\n";
	# Print TOP line across game grid . . . . . . . 
	print "     ";
	foreach (0..$size-1)	{	print "_______";}
	print "_\n";
	# Print Game Grid . . . . . . . 
	foreach my $row (0..$size-1)
	{	print "     ";
		foreach my $col (0..$size-1)
		{	# Format cell layout . . . . . . .
			my $cellblock = "|__$cell[$pos]__";        # default
			if ($pos < 10)
			{	$cellblock = "|___$cell[$pos]__";}     # add extra char to line
			elsif ($pos >= 10 && $cell[$pos] =~ /[XO]/)
			{	$cellblock = "|___$cell[$pos]__";}     # add extra char to line
			print $cellblock;
			$pos = $pos + 1;
		}
		print "|\n";
	}
	print "\n\n--------------------------------------\n\n";
}

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# - - - - - EOF - - - - - - - - - - - - - - - - - - - - - -
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

}}}

!
[[< Back to Lectures|Lecture Index]]|[[Next>|TicTacToe-02]]
!Welcome to Working Code:
This is a quick introductory lecture to develop a two-player game engine for: ''Tic Tac Toe''. The code will not calculate moves, but simply compile all the necessary mechanics for two people to play the  game by taking sequential turns.

Here's what the game looks like:
<html><img src="01/tictactoe.png" style="height:100px"></html>

//How can a computer do this?//

!!!Objectives:
# Look at perl code for simple tasks
# Recognize the gap between how humans and computers process logic problems

!
[[< Back|TicTacToe-01]]|[[Next>|TicTacToe-03]]
!Draw a board
We need a 3x3 grid, using "|" and "_" characters:
{{{
   |___|___|___|
   |___|___|___|
   |___|___|___|
}}}

Use a simple ''print'' statement to display information on screen: 
{{{
print "   |___|___|___|\n";
print "   |___|___|___|\n";
print "   |___|___|___|\n";
}}}

But instead of repeating the ''print'' command 3 times, we can use an iteration loop:
{{{
foreach my $i (1..3)
{    print "   |___|___|___|\n"; }
}}}

!


[[< Back|TicTacToe-02]]|[[Next>|TicTacToe-04]]
!A Board Algorithm

We need a way to reference each cell in the grid separately to keep track of whether it is an ''X'' or an ''O''. We'll start by assigning a number to each cell so that if a cell contains a numeric character, it means that the cell is "empty" or open for a move:  
{{{
   |_1_|_2_|_3_|
   |_4_|_5_|_6_|
   |_7_|_8_|_9_|
}}}

The way the computer thinks of this is not as a board grid, but just as an ''array'' or list of elements that describe the state of each cell.
{{{
my @cells = qw | 1 2 3 4 5 6 7 8 9 |;      # define cell states
my $position = 0;                          # set initial position 0
foreach (1..3)                             # control loop for rows
{    print "   |";                         # start each row
     foreach (1..3)                        # control loop for columns
     {    print "_$cells[$position]_|";    # print each individual cell
          $position += 1;                  # increment counter
     }
	 print "\n";                       # end each row with RETURN
}
}}}


!
[[< Back|TicTacToe-03]]|[[Next>|TicTacToe-05]]
!A Game Algorithm
Now we just need the logic structure for how the game will be played on the board. It's a simple game . . . . 
{{{
1. Draw board
2. Get first move for position of ''X''
3. Redraw board
4. Get first move for position of ''O''
5. Redraw board
6. Get second move for position of ''X''
. . . . 
}}}

Here's a pseudo-code logic outline:
{{{
Repeat 5 times . . . 
{     Draw Board
      Get X
      Draw Board
      Get O
}
}}}

And if we make the turn decision automatic (''X'' then ''O'' then ''X'' etc.) this can be simplified:
{{{
Draw Board
Then Repeat 9 times . . . 
{     
      Get MOVE
      Draw Board
}
}}}

!
[[< Back|TicTacToe-04]]|[[Next>|TicTacToe-06]]
!A Subroutine Code

Because we will be drawing the board after every turn, we will make the BOARD code repeatable by defining it as a subroutine.
{{{
#-------------------------------------
sub BOARD
{   my $position = 0;   
    foreach (1..3)  
    {    print "   |";
        foreach (1..3)  
        {   print "_$cells[$position]_|";
            $position += 1; 
        }
        print "\n"; 
    }
}
#-------------------------------------
}}}

!
[[< Back|TicTacToe-05]]|[[Final Code>|TicTacToe-07]]
!The Setup  Code
Here's the way we need to start the script by defining the primary GLOBAL variables that will be used:
{{{
#!/usr/bin/perl
use strict;
my @cells   = qw | 1 2 3 4 5 6 7 8 9 |; 
my @markers = qw | X O |;
}}}

!The MAIN Code
Now the running code that will execute the game:
{{{
&BOARD;
foreach my $move (1..9)
{	my $turn = shift(@markers);
	push(@markers, $turn);
	print "\nWhere does the $turn marker go: "; 
	my $z = <STDIN>;
	chomp $z;
	$cells[$z-1] = $turn;
	&BOARD;
}
}}}

!How does the computer process the game?
Most of the coding involved above is focused on the 'human' display overhead in terms of drawing the grid board with current marker locations. The actual game information about markers that the computer 'sees' is relatively trivial.
{{{
print "\n* * * * *\n", @cells, "\n* * * * *\n";
}}}

As far as the computer is concerned, it just needs the simple array of cell elements in a list to process game play:
{{{
* * * * *
O2X4O6X8X
* * * * *
}}}


!
[[< Previous Lecture Slide|TicTacToe-06]]
[[< Back to Lecture Index|Lecture Index]]
[[ Next Code Iteration >|TicTacToe-08]]
!The ~TicTacToe  Code
Put the sections together with a bit of extra print code just to make the playing experience a little more pleasant . . . . 
{{{
#!/usr/bin/perl
use strict;

# - - - - - H E A D E R - - - - - - - - - - - - - - - - -
# Goal: Takes TicTacToe moves from human players.
# AGM-2014

# - - - - - U S E R    V A R I A B L E S - - - - - - - -


# - - - - - G L O B A L  V A R I A B L E S  - - - - - -
my @cell = (0,1,2,3,4,5,6,7,8);
my @marker = ("X", "O");


# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# - - - - - M A I N - - - - - - - - - - - - - - - - - - - -
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -


print "This is my TicTacToe Game:\n\n";

# 1. Print a Board Display

&BOARD;

# 2. Get Input:

# What is the marker for this turn . . . .


foreach my $move (0..8)
{	my $xo = shift(@marker);
	push(@marker, $xo);
	print "Please Enter position for $xo marker: ";
	# Input and Validation . . . . . .
	my $validmove = "FALSE";
	while($validmove eq "FALSE")
	{	my $turn = <STDIN>;
		chomp($turn);
		if ($cell[$turn] =~ m/\d/)        # << a regex conditional test
		{	# IF TRUE: input is a valid move
			$cell[$turn] = $xo;
			$validmove = "TRUE";
		}
		else
		{	# IF FALSE: location input is already occupied . . . . .  
			print "cheater . . . try again . . . \n";
			print "Please Enter VALID position for $xo marker: ";
		}
	}
	
	&BOARD;
}


print "\n\n* * * * D O N E  * * * * * \n\n";

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# - - - - - S U B R O U T I N E S - - - - - - - - - - -
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
sub BOARD
{	system("clear");           #   PC= "cls"
	my $pos = 0;
	print "\n\n------------------------\n\n";
	print "     ______________________\n";
	foreach my $row (0..2)
	{	print "     ";
		foreach my $col (0..2)
		{	print "|__$cell[$pos]__";
			$pos = $pos + 1;
		}
		print "|\n";
	}
	print "\n\n------------------------\n\n";
}

# - - - - - EOF - - - - - - - - - - - - - - - - - - - - - -
}}}

!
[[< Previous Version|TicTacToe-07]]
!Human Input Grid: ~NxN
Script format takes an input variable to set the size of the grid used for play.

{{{
#!/usr/bin/perl
use strict;

# - - - - - H E A D E R - - - - - - - - - - - - - - - - -
# Goal: Takes TicTacToe moves from human players.
# AGM-2014

# - - - - - U S E R    V A R I A B L E S - - - - - - - -
my $name = "Adam";
my $size = 4;

# - - - - - G L O B A L  V A R I A B L E S  - - - - - -
my @marker = ("X", "O");
my @cell;
foreach my $i (0..$size**2-1)
{	push(@cell, $i); }



# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# - - - - - M A I N - - - - - - - - - - - - - - - - - - - -
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

# 1. Start Game = Display Board and Input Command . . . . 
&BOARD;

# 2. Iterate Turn Input . . . . . . .
foreach my $move (0..$size**2-1)
{	my $xo = shift(@marker);
	push(@marker, $xo);
	print "Please Enter position for $xo marker: ";
	# Input and Validation . . . . . .
	my $validmove = "FALSE";
	while($validmove eq "FALSE")
	{	my $turn = <STDIN>;
		chomp($turn);
		# if ($cell[$turn] ne 'X' && $cell[$turn] ne 'O')  # << strict conditional test
		if ($cell[$turn] =~ m/\d/)                         # << a regex conditional test
		{	# IF TRUE: location input is a valid move . . . . . . . . . . .
			$cell[$turn] = $xo;
			$validmove = "TRUE";
		}
		else
		{	# IF FALSE: location input is already occupied by a previous move . . . . .  
			print "cheater . . . try again . . . \n";
			print "Please Enter VALID position for $xo marker: ";
		}
	}

	&BOARD;
}

# 3. Exit . . . . . . .

print "\n\n* * * * D O N E  * * * * * \n\n";

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# - - - - - S U B R O U T I N E S - - - - - - - - - - -
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
sub BOARD
{	system("clear");           #   PC= "cls"
	print "\n\nThis is $name\'s TicTacToe Game:\n\n";
	my $pos = 0;
	print "\n\n------------------------\n\n";
	# Print TOP line across game grid . . . . . . . 
	print "     ";
	foreach (0..$size-1)	{	print "_______";}
	print "_\n";
	# Print game grid . . . . . . . 
	foreach my $row (0..$size-1)
	{	print "     ";
		foreach my $col (0..$size-1)
		{	# Format cell layout . . . . . . .
			my $cellblock = "|__$cell[$pos]__";        # default
			if ($pos < 10)
			{	$cellblock = "|___$cell[$pos]__";}     # add extra char to line
			elsif ($pos >= 10 && $cell[$pos] =~ /[XO]/)
			{	$cellblock = "|___$cell[$pos]__";}     # add extra char to line
			print $cellblock;
			$pos = $pos + 1;
		}
		print "|\n";
	}
	print "\n\n------------------------\n\n";
}

# - - - - - EOF - - - - - - - - - - - - - - - - - - - - - -

}}}

!
[[< Back to Script Index|BoneYard]]
!Tic Tac Toe
{{{
#!/usr/bin/perl

@XO = qw | _ _ _ _ _ _ _ _ _ |;
@Z  = qw | 1 2 3 4 5 6 7 8 9 |;
my $move = 1;
my $turn = 'X';
system('clear');
&BOARD;


while ($move < 10)
{	if ($turn eq 'X')
	{	print "\nWhere does the X go: "; 
		$x = <STDIN>;
		chomp $x;
		$XO[$x-1] = "X"; 
		system('clear');
		&BOARD();
		$turn = 'O';
	}
	else
	{	print "\nWhere does the O go: "; 
		$x = <STDIN>;
		chomp $x;
		$XO[$x-1] = "O"; 
		system('clear');	
		&BOARD();
		$turn = 'X';
	}
	$move += 1;
}

print "\n\n\nGAME OVER\n\n";

#-------------------------------------
sub BOARD
{   
	print "\n\n\nLet's Play Tic Tac Toe: \n   move = $move\n   turn = $turn\n\n\n";
	my $k = 0;
	foreach my $i (1..3)
	{
		print "     |";
		foreach my $j (1..3)
		{
			if ($XO[$k] =~ m/[XO]/)
			{	print "____$XO[$k]_____|"; }
			else
			{	print "___($Z[$k])____|"; }
			$k += 1;
		}
		print "\n\n";
	}
}	
#---------------------------------------
}}}
!
[[<BACK to Code|BoneYard]]
!Benchmark Module

PERL has a time module for benchmarking the execution time required by a program. You need to load the module at the beginning of a script with:
{{{
use Benchmark;
}}}

In your program, you initialize a 'stopwatch' with the command: 
@@{{{ my $StartTime = new Benchmark; }}}@@

This makes a time record of the point where you want to start timing from. Then when you get to the point where you want to end the timing and calculated the elapsed CPU cycles:
{{{
&TIME($StartTime);
}}}
The TIME subroutine below takes the start vs stop difference and prints out a formatted time string:
{{{
# - - - - - - - - - - - - - - - - - - - - - - - - -
sub TIME
{	my $t1 = new Benchmark;
    my $td = timediff($t1, $_[0]);
    print "\nCode Time:\n",timestr($td),"\n";
}
# - - - - - - - - - - - - - - - - - - - - - - - - - -
}}}
!
[[BACK to Working Code|BoneYard]]
!Time Stamp:
Simple time mark as a print line to stdout device. Generates a string formatted like this:
{{engindent{{{engindent{{{{ 04-May-2011 22:07:35 }}}}}}}}}
{{{
# declare posix module at top of script
use POSIX strftime;

#--------------------------------------------------
sub TimeStamp
{	print strftime("%d-%b-%Y %H:%M:%S\n",localtime(time()));	}
#--------------------------------------------------
}}}
/%
|Name|ToggleRightSidebar|
|Source|http://www.TiddlyTools.com/#ToggleRightSidebar|
|Version|1.0.0|
|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|script|
|Requires|InlineJavascriptPlugin|
|Overrides||
|Description|show/hide right sidebar (SideBarOptions)|

Usage: <<tiddler ToggleRightSidebar>>

Config settings:
	config.options.txtToggleRightSideBarLabelShow (◄)
	config.options.txtToggleRightSideBarLabelHide (►)
	config.options.txtToggleRightSideBarTipShow ("show right sidebar")
	config.options.txtToggleRightSideBarTipHide ("hide right sidebar")

%/<script label="show/hide right sidebar">
	var sb=document.getElementById('sidebar'); if (!sb) return;
	var show=sb.style.display=='none';
	if (!show) { sb.style.display='none'; var margin='1em'; }
	else { sb.style.display='block'; var margin=config.options.txtDisplayAreaRightMargin||''; }
	if (typeof(place)!='undefined') {
		place.innerHTML=show?
			config.options.txtToggleRightSideBarLabelHide:config.options.txtToggleRightSideBarLabelShow;
		place.title=show?
			config.options.txtToggleRightSideBarTipHide:config.options.txtToggleRightSideBarTipShow;
	}
	document.getElementById('displayArea').style.marginRight=margin;
	config.options.chkShowRightSidebar=show;
	saveOptionCookie('chkShowRightSidebar');
	var sm=document.getElementById('storyMenu'); if (sm) config.refreshers.content(sm);
	return false;
</script><script>
	if (config.options.chkShowRightSidebar==undefined)
		config.options.chkShowRightSidebar=true;
	if (!config.options.txtDisplayAreaRightMargin||!config.options.txtDisplayAreaRightMargin.length)
		config.options.txtDisplayAreaRightMargin="18em";
	if (config.options.txtToggleRightSideBarLabelShow==undefined)
		config.options.txtToggleRightSideBarLabelShow=config.browser.isSafari?"&#x25c0;":"&#x25c4;";
	if (config.options.txtToggleRightSideBarLabelHide==undefined)
		config.options.txtToggleRightSideBarLabelHide="&#x25ba;";
	if (config.options.txtToggleRightSideBarTipShow==undefined)
		config.options.txtToggleRightSideBarTipShow="show right sidebar";
	if (config.options.txtToggleRightSideBarTipHide==undefined)
		config.options.txtToggleRightSideBarTipHide="hide right sidebar";

	var show=config.options.chkShowRightSidebar;
	document.getElementById('sidebar').style.display=show?"block":"none";
	document.getElementById('displayArea').style.marginRight=show?
		config.options.txtDisplayAreaRightMargin:"1em";
	place.lastChild.innerHTML=show?
		config.options.txtToggleRightSideBarLabelHide:config.options.txtToggleRightSideBarLabelShow;
	place.lastChild.title=show?
		config.options.txtToggleRightSideBarTipHide:config.options.txtToggleRightSideBarTipShow;
	place.lastChild.style.fontWeight="normal";
</script>
|!History:|!<<back>>|>|!<<history>>|>|!<<forward>>|
|!Font size:|>|>|>|>|! <<fontSize>>|
|!Sidebar:|>|>|>|>|!<<tiddler ToggleRightSidebar>>|
!!!
[[BACK to Working Code|BoneYard]]
!!!
!Translate NT seqs to Protein Amino Acid seqs:
Requires that the dictionary %Genes is globally defined and that the subroutine &~LoadCodonTable has been called.
{{{
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
sub TranslateFasta
{	print "   Amino Acid translation . . . \n";
	&LoadCodonTable();
	my $GenDict = $_[0];
	foreach my $id (keys %{$GenDict})
	{	my $prot = '';
		my $gene = ${$GenDict}{$id}{'ntseq'};
		while ($gene =~ s/^(...)//)
		{	$prot .= $CodonTable{$1}; }
		$prot =~ s/\*$//;   # drop terminal stop codon
		${$GenDict}{$id}{'aaseq'} = $prot;
	}
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 

}}}


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

//
// Environment
//

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

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

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

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

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

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

//
// uploadOptions Macro
//

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

//
// upload functions
//

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

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

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

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

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

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

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

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

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

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

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

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

//
// Utilities
// 

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

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

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

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

//
// Initializations
//

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

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

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

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


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


//}}}

<!--{{{-->
<div class='toolbar' macro='toolbar closeTiddler closeOthers +editTiddler > fields syncing permalink references jump'></div>
<div class='title' macro='view title'></div>
<div class='viewer' macro='view text wikified'></div>
<div class='tagClear'></div>
<!--}}}-->
This is just a modest adaptation of ~TiddlyWiki for use as a webpage. I created it for my own use, but thought others might like an empty template of it. To see a working example of the Webview ~TiddlyWiki, [[see here|http://www.giffmex.org/webviewtwexample.html]]. ''Features of WebviewTW:''
*I have reduced as much clutter as possible, so as not to confuse first time visitors to your site: the header is gone, the sidebar hidden, and Tiddler elements such as author, date created, tagged and tagging have been removed. The mainmenu has a toolbox, which itself can be gutted if desired, when you are ready to upload.
*Only one tiddler opens at a time.
*There is a way to create a series of tiddlers linked in a colorful subtopic menu above the tiddler titles (the three squares above are an example of a subtopic menu and include the instructions necessary to create one). These are good just as subtopic menus, but are also meant for slideshows and linear tutorials and lessons. The idea is similar to the [[PresentationPlugin|http://lewcid.googlepages.com/presentation_empty_full.html#Documentation]], but this setup operates in a different way.
*Saving options have been set to ~SaveBackup:unchecked, and Animations:disabled, and the sidebar is hidden by default. (See [[z_configOptions]] to change these)
*In edit mode there are a number of easyEdit menus. See [[Formatting cheatsheet]] for details. There are also several color palettes to choose from (found in the Sidebar).
*The UploadPlugin and SplashScreenPlugin are installed. For directions for the UploadPlugin, see [[this external link|http://www.giffmex.org/twfortherestofus.html#%5B%5BSimple%20instructions%20for%20BidiX's%20UploadPlugin%5D%5D]]. My apologies to Alan Hecht, the creator of the ~WebViewPlugin - there is no relation between this adaptation and that plugin, which is not used here.
!Synopsis of site postings
!!

!!
[[<Back to Index|Resource Index]]
!R on Windows

Lessons Learned and Advice from J.Stewart
{{{
Ok- I figured out how to get R to run through the command prompt on
Windows 7 64 bit. Apparently multiple R executables are downloaded
with the package and you have to specify the path to the correct 64
bit version.

To set the path:
-Right click on my computer
-Choose properties
-Choose Advanced System Settings
-Click button for 'Enivronmental Variables'
-Under 'User Variables', Highlight 'PATH' and click 'Edit'
-To 'variable value' add the path to the R executable to the current list
separated by semicolons (mine is: C:\Program Files\R\R-2.15.2\bin\x64)
-OK x3 to exit all windows
-Open a new command prompt (cmd from the run line)

Now the 'Rscript yourfilename.r' command will work at the command
prompt- use it to run an r-scritpted file (make sure you are in the
working directory where the file is located or that you specify the
whole file path - In windows, you can drag a file to the terminal at
the prompt and it will write out the whole path for you)

Also, the 'R' command will open R within the terminal for work
directly in the terminal- to quit R and exit to your regular command
line, type q()

This setup should also be able to call an r-script from within the
perl file- to do this, substitute the UNIX system command:
system('R --vanilla <06-ResultsPlotDistribution.R');
with this instead:
system("Rscript 06-ResultsPlotDistribution.R");
Again, make sure you specify the whole path or are working within the
directory that file is located in.

Another problem I encountered was spaces in folders names, for example
a path was:
C:/Program Files/...
and I would get the error message, "C:/Program is not a command",
because of the space...
To correct that I used DOS shorthand to truncate the folder name to:
C:/Progra~1/...
and that worked fine. The ~1 means that it is the first folder that
starts with Progra, so the Program Files (x86) folder would be
Progra~2

}}}
Background: #fff
Foreground: #000
PrimaryPale: #ccccff
PrimaryLight: #ccccff
PrimaryMid: #333366
PrimaryDark: #014
SecondaryPale: #bbbbff
SecondaryLight: #fe8
SecondaryMid: #db4
SecondaryDark: #333366
TertiaryPale: #eee
TertiaryLight: #ccc
TertiaryMid: #999
TertiaryDark: #9999cc
Error: #f88
Background: #fff
Foreground: #000
PrimaryPale: #ffccff
PrimaryLight: #ffccff
PrimaryMid: #ff0066
PrimaryDark: #014
SecondaryPale: #ffcccc
SecondaryLight: #fe8
SecondaryMid: #db4
SecondaryDark: #ff0066
TertiaryPale: #eee
TertiaryLight: #ccc
TertiaryMid: #999
TertiaryDark: #ff99cc
Error: #f88
/***An adaptation of [[easyFormat]]***/
//{{{
config.commands.Color = new TWkd.Ease('Color','change the color of selected text');

config.commands.Color.addMode({
 name:'Red',
 tooltip:'turns selection red',
 operation:function(){
config.commands.Color.putInPlace("{{red{"+TWkd.context.selection.content+"}}}",TWkd.context.selection);
 }
});
config.commands.Color.addMode({
 name:'Blue',
 tooltip:'turns selection blue',
 operation:function(){
config.commands.Color.putInPlace("{{blue{"+TWkd.context.selection.content+"}}}",TWkd.context.selection);
 }
});
config.commands.Color.addMode({
 name:'Green',
 tooltip:'turns selection green',
 operation:function(){
config.commands.Color.putInPlace("{{green{"+TWkd.context.selection.content+"}}}",TWkd.context.selection);
 }
});
config.commands.Color.addMode({
 name:'Gold',
 tooltip:'turns selection gold',
 operation:function(){
config.commands.Color.putInPlace("{{gold{"+TWkd.context.selection.content+"}}}",TWkd.context.selection);
 }
});
config.commands.Color.addMode({
 name:'Gray',
 tooltip:'turns selection gray',
 operation:function(){
config.commands.Color.putInPlace("{{gray{"+TWkd.context.selection.content+"}}}",TWkd.context.selection);
 }
});
config.commands.Color.addMode({
 name:'Magenta',
 tooltip:'turns selection magenta',
 operation:function(){
config.commands.Color.putInPlace("{{magenta{"+TWkd.context.selection.content+"}}}",TWkd.context.selection);
 }
});
config.commands.Color.addMode({
 name:'Purple',
 tooltip:'turns selection purple',
 operation:function(){
config.commands.Color.putInPlace("{{purple{"+TWkd.context.selection.content+"}}}",TWkd.context.selection);
 }
});
config.commands.Color.addMode({
 name:'Teal',
 tooltip:'turns selection teal',
 operation:function(){
config.commands.Color.putInPlace("{{teal{"+TWkd.context.selection.content+"}}}",TWkd.context.selection);
 }
});
config.commands.Color.addMode({
 name:'Burgundy',
 tooltip:'turns selection burgundy',
 operation:function(){
config.commands.Color.putInPlace("{{burgundy{"+TWkd.context.selection.content+"}}}",TWkd.context.selection);
 }
});
//}}}
/***
|!''Name:''|!easyFormat|
|''Description:''|the format command format selection according to your choice|
|''Version:''|0.1.0|
|''Date:''|13/01/2007|
|''Source:''|[[TWkd|http://yann.perrin.googlepages.com/twkd.html#easyFormat]]|
|''Author:''|[[Yann Perrin|YannPerrin]]|
|''License:''|[[BSD open source license]]|
|''~CoreVersion:''|2.x|
|''Browser:''|Firefox 1.0.4+; Firefox 1.5; InternetExplorer 6.0|
|''Requires:''|@@color:red;''E.A.S.E''@@|
***/
//{{{
config.commands.Format = new TWkd.Ease('Format','format selection accordingly to chosen mode');

config.commands.Format.addMode({
 name:'Bold',
 tooltip:'turns selection into bold text',
 operation:function(){
config.commands.Format.putInPlace("''"+TWkd.context.selection.content+"''",TWkd.context.selection);
 }
});
config.commands.Format.addMode({
 name:'Italic',
 tooltip:'turns selection into italic text',
 operation:function(){
config.commands.Format.putInPlace("//"+TWkd.context.selection.content+"//",TWkd.context.selection);
 }
});
config.commands.Format.addMode({
 name:'Underline',
 tooltip:'underlines selected text',
 operation:function(){
config.commands.Format.putInPlace("__"+TWkd.context.selection.content+"__",TWkd.context.selection);
 }
});
config.commands.Format.addMode({
 name:'Highlight',
 tooltip:'highlight selection',
 operation:function(){
config.commands.Format.putInPlace("@@"+TWkd.context.selection.content+"@@",TWkd.context.selection);
 }
});
config.commands.Format.addMode({
 name:'Hyperlink',
 tooltip:'turns selection into a link using double brackets',
 operation:function(){
config.commands.Format.putInPlace("[["+TWkd.context.selection.content+"]]",TWkd.context.selection);
 }
});
//}}}
/***An adaptation of [[easyFormat]]***/
//{{{
config.commands.Greek = new TWkd.Ease('Greek','formatting for Greek text');

config.commands.Greek.addMode({
 name:'Greek',
 tooltip:'formats Greek text correctly',
 operation:function(){
config.commands.Greek.putInPlace("{{greek{"+TWkd.context.selection.content+"}}}",TWkd.context.selection);
 }
});
config.commands.Greek.addMode({
 name:'GkIndent1x',
 tooltip:'formats Gk and indents text 1x',
 operation:function(){
config.commands.Greek.putInPlace("{{gkindent{"+TWkd.context.selection.content+"}}}",TWkd.context.selection);
 }
});
config.commands.Greek.addMode({
 name:'GkIndent2x',
 tooltip:'formats Gk and indents text 2x',
 operation:function(){
config.commands.Greek.putInPlace("{{gkindent{{{gkindent{"+TWkd.context.selection.content+"}}}}}}",TWkd.context.selection);
 }
});
config.commands.Greek.addMode({
 name:'GkIndent3x',
 tooltip:'formats Gk and indents text 3x',
 operation:function(){
config.commands.Greek.putInPlace("{{gkindent{{{gkindent{{{gkindent{"+TWkd.context.selection.content+"}}}}}}}}}",TWkd.context.selection);
 }
});
config.commands.Greek.addMode({
 name:'GkIndent4x',
 tooltip:'formats Gk and indents text 4x',
 operation:function(){
config.commands.Greek.putInPlace("{{gkindent{{{gkindent{{{gkindent{{{gkindent{"+TWkd.context.selection.content+"}}}}}}}}}}}}",TWkd.context.selection);
 }
});
config.commands.Greek.addMode({
 name:'GkIndent5x',
 tooltip:'formats Gk and indents text 5x',
 operation:function(){
config.commands.Greek.putInPlace("{{gkindent{{{gkindent{{{gkindent{{{gkindent{{{gkindent{"+TWkd.context.selection.content+"}}}}}}}}}}}}}}}",TWkd.context.selection);
 }
});
//}}}
/***An adaptation of [[easyFormat]]***/
//{{{
config.commands.Hebrew = new TWkd.Ease('Hebrew','formatting for Hebrew text');

config.commands.Hebrew.addMode({
 name:'HebrewNoAlign',
 tooltip:'formats Hebrew text correctly',
 operation:function(){
config.commands.Hebrew.putInPlace("{{hebrewNoAlign{"+TWkd.context.selection.content+"}}}",TWkd.context.selection);
 }
});
config.commands.Hebrew.addMode({
 name:'HebrewRightAlign',
 tooltip:'formats Hebrew text correctly and aligns text to the right',
 operation:function(){
config.commands.Hebrew.putInPlace("{{hebrewRightAlign{"+TWkd.context.selection.content+"}}}",TWkd.context.selection);
 }
});
config.commands.Hebrew.addMode({
 name:'HebIndent1x',
 tooltip:'formats Heb and indents text 1x',
 operation:function(){
config.commands.Hebrew.putInPlace("{{hebAlignAndIndent{"+TWkd.context.selection.content+"}}}",TWkd.context.selection);
 }
});
config.commands.Hebrew.addMode({
 name:'HebIndent2x',
 tooltip:'formats Heb and indents text 2x',
 operation:function(){
config.commands.Hebrew.putInPlace("{{hebAlignAndIndent{{{hebAlignAndIndent{"+TWkd.context.selection.content+"}}}}}}",TWkd.context.selection);
 }
});
config.commands.Hebrew.addMode({
 name:'HebIndent3x',
 tooltip:'formats Heb and indents text 3x',
 operation:function(){
config.commands.Hebrew.putInPlace("{{hebAlignAndIndent{{{hebAlignAndIndent{{{hebAlignAndIndent{"+TWkd.context.selection.content+"}}}}}}}}}",TWkd.context.selection);
 }
});
config.commands.Hebrew.addMode({
 name:'HebIndent4x',
 tooltip:'formats Heb and indents text 4x',
 operation:function(){
config.commands.Hebrew.putInPlace("{{hebAlignAndIndent{{{hebAlignAndIndent{{{hebAlignAndIndent{{{hebAlignAndIndent{"+TWkd.context.selection.content+"}}}}}}}}}}}}",TWkd.context.selection);
 }
});
config.commands.Hebrew.addMode({
 name:'HebIndent5x',
 tooltip:'formats Heb and indents text 5x',
 operation:function(){
config.commands.Hebrew.putInPlace("{{hebAlignAndIndent{{{hebAlignAndIndent{{{hebAlignAndIndent{{{hebAlignAndIndent{{{hebAlignAndIndent{"+TWkd.context.selection.content+"}}}}}}}}}}}}}}}",TWkd.context.selection);
 }
});
//}}}
/***
This is an adaptation of:
|!''Name:''|!easyFormat|
|''Description:''|the format command format selection according to your choice|
|''Version:''|0.1.0|
|''Date:''|13/01/2007|
|''Source:''|[[TWkd|http://yann.perrin.googlepages.com/twkd.html#easyFormat]]|
|''Author:''|[[Yann Perrin|YannPerrin]]|
|''License:''|[[BSD open source license]]|
|''~CoreVersion:''|2.x|
|''Browser:''|Firefox 1.0.4+; Firefox 1.5; InternetExplorer 6.0|
|''Requires:''|@@color:red;''E.A.S.E''@@|
***/
//{{{
config.commands.Highlighting = new TWkd.Ease('Highlighting','highlight selected text with a color chosen from the list');
config.commands.Highlighting.addMode({
 name:'Red',
 tooltip:'highlights selection red',
 operation:function(){
config.commands.Highlighting.putInPlace("@@bgcolor(#ff6666):"+TWkd.context.selection.content+"@@",TWkd.context.selection);
 }
});
config.commands.Highlighting.addMode({
 name:'Blue',
 tooltip:'highlights selection blue',
 operation:function(){
config.commands.Highlighting.putInPlace("@@bgcolor(#ccccff):"+TWkd.context.selection.content+"@@",TWkd.context.selection);
 }
});
config.commands.Highlighting.addMode({
 name:'Yellow',
 tooltip:'highlights selection yellow',
 operation:function(){
config.commands.Highlighting.putInPlace("@@"+TWkd.context.selection.content+"@@",TWkd.context.selection);
 }
});
config.commands.Highlighting.addMode({
 name:'Green',
 tooltip:'highlights selection green',
 operation:function(){
config.commands.Highlighting.putInPlace("@@bgcolor(#99ff99):"+TWkd.context.selection.content+"@@",TWkd.context.selection);
 }
});
config.commands.Highlighting.addMode({
 name:'Brown',
 tooltip:'highlights selection brown',
 operation:function(){
config.commands.Highlighting.putInPlace("@@bgcolor(#cc9966):"+TWkd.context.selection.content+"@@",TWkd.context.selection);
 }
});
config.commands.Highlighting.addMode({
 name:'Grey',
 tooltip:'highlight selection',
 operation:function(){
config.commands.Highlighting.putInPlace("@@bgcolor(#cccc99):"+TWkd.context.selection.content+"@@",TWkd.context.selection);
 }
});
config.commands.Highlighting.addMode({
 name:'Orange',
 tooltip:'turns selection into unicode text, for Greek characters',
 operation:function(){
config.commands.Highlighting.putInPlace("@@bgcolor(#ff9933):"+TWkd.context.selection.content+"@@",TWkd.context.selection);
 }
});
//}}}
/***An adaptation of [[easyFormat]]***/
//{{{
config.commands.Indent = new TWkd.Ease('Indent','indents selected text as a blockquote');

config.commands.Indent.addMode({
 name:'Indent1x',
 tooltip:'indents text 1x',
 operation:function(){
config.commands.Indent.putInPlace("{{engindent{"+TWkd.context.selection.content+"}}}",TWkd.context.selection);
 }
});
config.commands.Indent.addMode({
 name:'Indent2x',
 tooltip:'indents text 2x',
 operation:function(){
config.commands.Indent.putInPlace("{{engindent{{{engindent{"+TWkd.context.selection.content+"}}}}}}",TWkd.context.selection);
 }
});
config.commands.Indent.addMode({
 name:'Indent3x',
 tooltip:'indents text 3x',
 operation:function(){
config.commands.Indent.putInPlace("{{engindent{{{engindent{{{engindent{"+TWkd.context.selection.content+"}}}}}}}}}",TWkd.context.selection);
 }
});
config.commands.Indent.addMode({
 name:'Indent4x',
 tooltip:'indents text 4x',
 operation:function(){
config.commands.Indent.putInPlace("{{engindent{{{engindent{{{engindent{{{engindent{"+TWkd.context.selection.content+"}}}}}}}}}}}}",TWkd.context.selection);
 }
});
config.commands.Indent.addMode({
 name:'Indent5x',
 tooltip:'indents text 5x',
 operation:function(){
config.commands.Indent.putInPlace("{{engindent{{{engindent{{{engindent{{{engindent{{{engindent{"+TWkd.context.selection.content+"}}}}}}}}}}}}}}}",TWkd.context.selection);
 }
});
//}}}
/***An adaptation of [[easyFormat]]***/
//{{{
config.commands.Notes = new TWkd.Ease('Notes','add notes and popups');

config.commands.Notes.addMode({
 name:'Syntax',
 tooltip:'adds syntax note',
 operation:function(){
config.commands.Notes.putInPlace("((syntax(add note here)))",TWkd.context.selection);
 }
});
config.commands.Notes.addMode({
 name:'Translation',
 tooltip:'adds syntax note',
 operation:function(){
config.commands.Notes.putInPlace("&#149; ((translation(add note here)))",TWkd.context.selection);
 }
});
config.commands.Notes.addMode({
 name:'Text',
 tooltip:'adds textual note',
 operation:function(){
config.commands.Notes.putInPlace("&#149; ((text(add note here)))",TWkd.context.selection);
 }
});
config.commands.Notes.addMode({
 name:'Gramm.',
 tooltip:'adds grammatical note',
 operation:function(){
config.commands.Notes.putInPlace("&#149; ((gram(add note here)))",TWkd.context.selection);
 }
});
config.commands.Notes.addMode({
 name:'Popup',
 tooltip:'adds popup note to selected text',
 operation:function(){
config.commands.Notes.putInPlace("(("+TWkd.context.selection.content+"(add note here)))",TWkd.context.selection);
 }
});
//}}}
/***An adaptation of [[easyFormat]]***/
//{{{
config.commands.Tableheader = new TWkd.Ease('Tableheader','add the header row for a formatted table');

config.commands.Tableheader.addMode({
 name:'Invisible',
 tooltip:'adds the header row for a 3-column invisible table',
 operation:function(){
config.commands.Tableheader.putInPlace("XXXXX",TWkd.context.selection);
 }
});

config.commands.Tableheader.addMode({
 name:'Sortable',
 tooltip:'adds the header row for a 3-column sortable table',
 operation:function(){
config.commands.Tableheader.putInPlace("|sortable|k||||h",TWkd.context.selection);
 }
});

config.commands.Tableheader.addMode({
 name:'Standard',
 tooltip:'adds the header row for a 3-column standard table',
 operation:function(){
config.commands.Tableheader.putInPlace("|!|!|!|",TWkd.context.selection);
 }
});

//}}}
/***An adaptation of [[easyFormat]]***/
//{{{
config.commands.Tables = new TWkd.Ease('Tables','add preformatted empty tables');

config.commands.Tables.addMode({
 name:'Invisible',
 tooltip:'adds borderless table',
 operation:function(){
config.commands.Tables.putInPlace("{{invisiblecomm{\n|!|!|!|\n||||\n||||\n||||\n}}}",TWkd.context.selection);
 }
});
config.commands.Tables.addMode({
 name:'Sortable',
 tooltip:'adds a sortable table',
 operation:function(){
config.commands.Tables.putInPlace("|sortable|k\n||||h\n||||\n||||\n||||",TWkd.context.selection);
 }
});
config.commands.Tables.addMode({
 name:'Standard',
 tooltip:'adds a standard table',
 operation:function(){
config.commands.Tables.putInPlace("|!|!|!|\n||||\n||||\n||||",TWkd.context.selection);
 }
});
config.commands.Tables.addMode({
 name:'light gray cell',
 tooltip:'inserts a light gray color code into a table cell',
 operation:function(){
config.commands.Tables.putInPlace("bgcolor(#eeeeee):",TWkd.context.selection);
 }
});
config.commands.Tables.addMode({
 name:'dark gray cell',
 tooltip:'inserts a dark gray color code into a table cell',
 operation:function(){
config.commands.Tables.putInPlace("bgcolor(#cccccc):",TWkd.context.selection);
 }
});
//}}}
Background: #fff
Foreground: #000
PrimaryPale: #eeeeee
PrimaryLight: #eeeeee
PrimaryMid: #666666
PrimaryDark: #014
SecondaryPale: #cccccc
SecondaryLight: #fe8
SecondaryMid: #db4
SecondaryDark: #666666
TertiaryPale: #eee
TertiaryLight: #ccc
TertiaryMid: #999
TertiaryDark: #bbbbbb
Error: #f88
Background: #fff
Foreground: #000
PrimaryPale: #ddeeaa
PrimaryLight: #ddeeaa
PrimaryMid: #666633
PrimaryDark: #014
SecondaryPale: #bbdd88
SecondaryLight: #fe8
SecondaryMid: #db4
SecondaryDark: #666633
TertiaryPale: #eee
TertiaryLight: #ccc
TertiaryMid: #999
TertiaryDark: #aacc88
Error: #f88
Background: #fff
Foreground: #000
PrimaryPale: #ddccff
PrimaryLight: #ddccff
PrimaryMid: #5500aa
PrimaryDark: #014
SecondaryPale: #ddbbff
SecondaryLight: #fe8
SecondaryMid: #db4
SecondaryDark: #5500aa
TertiaryPale: #eee
TertiaryLight: #ccc
TertiaryMid: #999
TertiaryDark: #ccaaff
Error: #f88
[[<Back to Lecture|REGEX-01]]
!REGEX NOTES:

!!Works in TWO modes:
** ''MATCH:'' @@{{{$data[5] =~ m/^.{4}AGGTC/;}}}@@
*** If a pattern match is found, returns a TRUE value
*** If a pattern match is not found, returns a FALSE value
** ''SUBSTITUTION:'' @@{{{$data[5] =~ s/^.{4}AGGTC/TTT/;}}}@@
*** If a pattern match is found, returns a TRUE value AND replaces the matched pattern with the substitution string ('TTT') in the original target string ($data[5]).
*** If a pattern match is not found, returns a FALSE value

!!Control Char Codes
Special characters are 'active' in regex expressions to control the execution of the pattern match process:
* ^  = start at beginning of string
* $  = start at end of string 
* .  = wildcard . . . it will match ANYTHING.
* Quantifiers:
** {} = paired braces, {min,max} or {exact}
** *  = any number of matches, from 0 to infinity and beyond . . .
** +  = true if 1 or more to infinity . . ..
* [  ] = brackets to define matching character set
** [AG]  = true if 'A' or 'G'
** [~A-Z] = any capital letter    
** [a-z] = any lower case letter
** \w    = any letter regardless of case
** [0-9] = any digit
** \d    = any digit
** [\d\.]+ = any floating point number (\. matches decimal points)
* ( ) = Parentheses have two applications:
** define allowable matching sets:
*** (AG|CT) = true if 'AG' or 'CT' is present
*** (A|GCT|GC|GCATAT) 
*** ([AC]|T) = matches A or C in one position or T in that same position
*** (AC|T)   = match 'AC' or 'T'
*** ([AC]|TGT) = ('A' or 'C') or ('TGT') 
** parentheses signify memory storage/retrieval
*** {{engindent{{{engindent{
{{{
if ($data[5] =~ m/^.{4}TA(C.+)AGGT+C\s+([\d\.]+)\s+<img src/)
{    $found1 = $1; 
     $found2 = $2; 
     . . . ; 
}  
}}}
}}}}}}

* \s  = matches any white space  (\t tab, \r return, \n linebreak, ' ' space)
* \  = ''de-refrences'' any special character that immediately follows it. Example: If you need to match a '^' character, you need to preceed it with a back slash '\^' so PERL knows not to evaluate '^' in the regex as a position marker, but instead will treat it as a regular character. 
* ? = flags for ''not-greedy'' pattern match. PERL's default regex behavior is to always find the longest possible match of the query pattern against the target string. So {{{/(^.+AT)/}}} against this target "CAGATGCTATAAAAA" would save "CAGATGCAT" into $1. But {{{/(^.+?AT)/}}} would select the shortest possible match against the "AT" so $1 would be "CAGAT". This latter mode is called a non-greedy match because it restricts the scope of the matched pattern string.


!!!Can execute pattern match using a variable:
{{engindent{{{engindent{	my $pattern = "^.{4}AGGT+C";
	if ($data[5] =~ m/$pattern/ ) { . . . ; }    }}}}}}   

!!!Modifiers . . . . . 
{{engindent{{{engindent{g = global
i = case insensitive
@@{{{ if ($data[5] =~ s/a/A/g )   # global substitution in ALL of $data[5] }}}@@}}}}}}



!


 






<?php
/***
! User settings
Edit these lines according to your need
***/
//{{{
$AUTHENTICATE_USER = true;	// true | false
$USERS = array(
	'UserName1'=>'Password1', 
	'UserName2'=>'Password2', 
	'UserName3'=>'Password3'); // set usernames and strong passwords
$DEBUG = false;				// true | false
$CLEAN_BACKUP = true; 		// during backuping a file, remove overmuch backups
$FOLD_JS = true; 			// if javascript files have been expanded during download the fold them
error_reporting(E_ERROR | E_WARNING | E_PARSE);
//}}}
/***
!Code
No change needed under
***/
//{{{

/***
 * store.php - upload a file in this directory
 * version :1.6.1 - 2007/08/01 - BidiX@BidiX.info
 * 
 * see : 
 *	http://tiddlywiki.bidi.info/#UploadPlugin for usage
 *	http://www.php.net/manual/en/features.file-upload.php 
 *		for details on uploading files
 * usage : 
 *	POST  
 *		UploadPlugin[backupDir=<backupdir>;user=<user>;password=<password>;uploadir=<uploaddir>;[debug=1];;]
 *		userfile <file>
 *	GET
 *
 * each external javascript file included by download.php is change by a reference (src=...)
 *
 * Revision history
 * V1.6.1 - 2007/08/01
 * Enhancement: Add javascript folding
 * V1.6.0 - 2007/05/17
 * Enhancement: Add backup management
 * V1.5.2 - 2007/02/13
 * Enhancement: Add optional debug option in client parameters
 * V1.5.1 - 2007/02/01
 * Enhancement: Check value of file_uploads in php.ini. Thanks to Didier Corbière
 * V1.5.0 - 2007/01/15
 * Correct: a bug in moving uploadFile in uploadDir thanks to DaniGutiérrez for reporting
 * Refactoring
 * V 1.4.3 - 2006/10/17 
 * Test if $filename.lock exists for GroupAuthoring compatibility
 * return mtime, destfile and backupfile after the message line
 * V 1.4.2 - 2006/10/12
 *  add error_reporting(E_PARSE);
 * v 1.4.1 - 2006/03/15
 *	add chmo 0664 on the uploadedFile
 * v 1.4 - 2006/02/23
 * 	add uploaddir option :  a path for the uploaded file relative to the current directory
 *	backupdir is a relative path
 *	make recusively directories if necessary for backupDir and uploadDir
 * v 1.3 - 2006/02/17
 *	presence and value of user are checked with $USERS Array (thanks to PauloSoares)
 * v 1.2 - 2006/02/12 
  *	POST  
 *		UploadPlugin[backupDir=<backupdir>;user=<user>;password=<password>;]
 *		userfile <file>
*	if $AUTHENTICATE_USER
 *		presence and value of user and password are checked with 
 *		$USER and $PASSWORD
 * v 1.1 - 2005/12/23 
 *	POST  UploadPlugin[backupDir=<backupdir>]  userfile <file>
 * v 1.0 - 2005/12/12 
 *	POST userfile <file>
 *
 * Copyright (c) BidiX@BidiX.info 2005-2007
 ***/
//}}}

//{{{

if ($_SERVER['REQUEST_METHOD'] == 'GET') {
	/*
	 * GET Request
	 */
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
	<head>
		<meta http-equiv="Content-Type" content="text/html;charset=utf-8" >
		<title>BidiX.info - TiddlyWiki UploadPlugin - Store script</title>
	</head>
	<body>
		<p>
		<p>store.php V 1.6.1
		<p>BidiX@BidiX.info
		<p>&nbsp;</p>
		<p>&nbsp;</p>
		<p>&nbsp;</p>
		<p align="center">This page is designed to upload a <a href="http://www.tiddlywiki.com/">TiddlyWiki<a>.</p>
		<p align="center">for details see : <a href="http://TiddlyWiki.bidix.info/#HowToUpload">TiddlyWiki.bidix.info/#HowToUpload<a>.</p>	
	</body>
</html>
<?php
exit;
}

/*
 * POST Request
 */
	 
// Recursive mkdir
function mkdirs($dir) {
	if( is_null($dir) || $dir === "" ){
		return false;
	}
	if( is_dir($dir) || $dir === "/" ){
		return true;
	}
	if( mkdirs(dirname($dir)) ){
		return mkdir($dir);
	}
	return false;
}

function toExit() {
	global $DEBUG, $filename, $backupFilename, $options;
	if ($DEBUG) {
		echo ("\nHere is some debugging info : \n");
		echo("\$filename : $filename \n");
		echo("\$backupFilename : $backupFilename \n");
		print ("\$_FILES : \n");
		print_r($_FILES);
		print ("\$options : \n");
		print_r($options);
}
exit;
}

function ParseTWFileDate($s) {
	// parse date element
	preg_match ( '/^(\d\d\d\d)(\d\d)(\d\d)\.(\d\d)(\d\d)(\d\d)/', $s , $m );
	// make a date object
	$d = mktime($m[4], $m[5], $m[6], $m[2], $m[3], $m[1]);
	// get the week number
	$w = date("W",$d);

	return array(
		'year' => $m[1], 
		'mon' => $m[2], 
		'mday' => $m[3], 
		'hours' => $m[4], 
		'minutes' => $m[5], 
		'seconds' => $m[6], 
		'week' => $w);
}

function cleanFiles($dirname, $prefix) {
	$now = getdate();
	$now['week'] = date("W");

	$hours = Array();
	$mday = Array();
	$year = Array();
	
	$toDelete = Array();

	// need files recent first
	$files = Array();
	($dir = opendir($dirname)) || die ("can't open dir '$dirname'");
	while (false !== ($file = readdir($dir))) {
		if (preg_match("/^$prefix/", $file))
        array_push($files, $file);
    }
	$files = array_reverse($files);
	
	// decides for each file
	foreach ($files as $file) {
		$fileTime = ParseTWFileDate(substr($file,strpos($file, '.')+1,strrpos($file,'.') - strpos($file, '.') -1));
		if (($now['year'] == $fileTime['year']) &&
			($now['mon'] == $fileTime['mon']) &&
			($now['mday'] == $fileTime['mday']) &&
			($now['hours'] == $fileTime['hours']))
				continue;
		elseif (($now['year'] == $fileTime['year']) &&
			($now['mon'] == $fileTime['mon']) &&
			($now['mday'] == $fileTime['mday'])) {
				if (isset($hours[$fileTime['hours']]))
					array_push($toDelete, $file);
				else 
					$hours[$fileTime['hours']] = true;
			}
		elseif 	(($now['year'] == $fileTime['year']) &&
			($now['mon'] == $fileTime['mon'])) {
				if (isset($mday[$fileTime['mday']]))
					array_push($toDelete, $file);
				else
					$mday[$fileTime['mday']] = true;
			}
		else {
			if (isset($year[$fileTime['year']][$fileTime['mon']]))
				array_push($toDelete, $file);
			else
				$year[$fileTime['year']][$fileTime['mon']] = true;
		}
	}
	return $toDelete;
}

function replaceJSContentIn($content) {
	if (preg_match ("/(.*?)<!--DOWNLOAD-INSERT-FILE:\"(.*?)\"--><script\s+type=\"text\/javascript\">(.*)/ms", $content,$matches)) {
		$front = $matches[1];
		$js = $matches[2];
		$tail = $matches[3];
		if (preg_match ("/<\/script>(.*)/ms", $tail,$matches2)) {		
			$tail = $matches2[1];
		}
		$jsContent = "<script type=\"text/javascript\" src=\"$js\"></script>";
		$tail = replaceJSContentIn($tail);
		return($front.$jsContent.$tail);
	}
	else
		return $content;
}

// Check if file_uploads is active in php config
if (ini_get('file_uploads') != '1') {
   echo "Error : File upload is not active in php.ini\n";
   toExit();
}

// var definitions
$uploadDir = './';
$uploadDirError = false;
$backupError = false;
$optionStr = $_POST['UploadPlugin'];
$optionArr=explode(';',$optionStr);
$options = array();
$backupFilename = '';
$filename = $_FILES['userfile']['name'];
$destfile = $filename;

// get options
foreach($optionArr as $o) {
	list($key, $value) = split('=', $o);
	$options[$key] = $value;
}

// debug activated by client
if ($options['debug'] == 1) {
	$DEBUG = true;
}

// authenticate User
if (($AUTHENTICATE_USER)
	&& ((!$options['user']) || (!$options['password']) || ($USERS[$options['user']] != $options['password']))) {
	echo "Error : UserName or Password do not match \n";
	echo "UserName : [".$options['user']. "] Password : [". $options['password'] . "]\n";
	toExit();
}



// make uploadDir
if ($options['uploaddir']) {
	$uploadDir = $options['uploaddir'];
	// path control for uploadDir   
    if (!(strpos($uploadDir, "../") === false)) {
        echo "Error: directory to upload specifies a parent folder";
        toExit();
	}
	if (! is_dir($uploadDir)) {
		mkdirs($uploadDir);
	}
	if (! is_dir($uploadDir)) {
		echo "UploadDirError : $uploadDirError - File NOT uploaded !\n";
		toExit();
	}
	if ($uploadDir{strlen($uploadDir)-1} != '/') {
		$uploadDir = $uploadDir . '/';
	}
}
$destfile = $uploadDir . $filename;

// backup existing file
if (file_exists($destfile) && ($options['backupDir'])) {
	if (! is_dir($options['backupDir'])) {
		mkdirs($options['backupDir']);
		if (! is_dir($options['backupDir'])) {
			$backupError = "backup mkdir error";
		}
	}
	$backupFilename = $options['backupDir'].'/'.substr($filename, 0, strrpos($filename, '.'))
				.date('.Ymd.His').substr($filename,strrpos($filename,'.'));
	rename($destfile, $backupFilename) or ($backupError = "rename error");
	// remove overmuch backup
	if ($CLEAN_BACKUP) {
		$toDelete = cleanFiles($options['backupDir'], substr($filename, 0, strrpos($filename, '.')));
		foreach ($toDelete as $file) {
			$f = $options['backupDir'].'/'.$file;
			if($DEBUG) {
				echo "delete : ".$options['backupDir'].'/'.$file."\n";
			}
			unlink($options['backupDir'].'/'.$file);
		}
	}
}

// move uploaded file to uploadDir
if (move_uploaded_file($_FILES['userfile']['tmp_name'], $destfile)) {
	if ($FOLD_JS) {
		// rewrite the file to replace JS content
		$fileContent = file_get_contents ($destfile);
		$fileContent = replaceJSContentIn($fileContent);
		if (!$handle = fopen($destfile, 'w')) {
	         echo "Cannot open file ($destfile)";
	         exit;
	    }
	    if (fwrite($handle, $fileContent) === FALSE) {
	        echo "Cannot write to file ($destfile)";
	        exit;
	    }
	    fclose($handle);
	}
    
	chmod($destfile, 0644);
	if($DEBUG) {
		echo "Debug mode \n\n";
	}
	if (!$backupError) {
		echo "0 - File successfully loaded in " .$destfile. "\n";
	} else {
		echo "BackupError : $backupError - File successfully loaded in " .$destfile. "\n";
	}
	echo("destfile:$destfile \n");
	if (($backupFilename) && (!$backupError)) {
		echo "backupfile:$backupFilename\n";
	}
	$mtime = filemtime($destfile);
	echo("mtime:$mtime");
} 
else {
	echo "Error : " . $_FILES['error']." - File NOT uploaded !\n";

}
toExit();
//}}}
?>
<html>
<div style="color: rgb(100, 100, 150); font-family: Monaco;"><big><b>
TITLE OR HEADER OR DESCRIPTOR . . . .. 
</html>
1. [[x |1.0.1]]
2. [[y |1.0.2]]
3. [[z |1.0.3]]
!!
<html>
<div style="color: rgb(100, 100, 150); font-family: Monaco;"><big><b>
TITLE OR HEADER OR DESCRIPTOR . . . .. 
</html>
1. [[x |1.1.1]]
2. [[y |1.1.2]]
3. [[z |1.1.3]]
!!
<html>
<div style="color: rgb(100, 100, 150); font-family: Monaco;"><big><b>
TITLE OR HEADER OR DESCRIPTOR . . . .. 
</html>
1. [[x |1.2.1]]
2. [[y |1.2.2]]
3. [[z |1.2.3]]
!!
<html>
<div style="color: rgb(100, 100, 150); font-family: Monaco;"><big><b>
TITLE OR HEADER OR DESCRIPTOR . . . .. 
</html>
1. [[x |1.3.1]]
2. [[y |1.3.2]]
3. [[z |1.3.3]]
!
{{tableindex{
|[[topic-01-00]]|[[topic-01-01]]|[[topic-01-02]]| [[topic-01-03]]|
}}}
<!--{{{-->
<div class='toolbar' macro='toolbar closeTiddler closeOthers +editTiddler > fields syncing permalink references jump'></div>
<div class='topic-01' macro='tiddler topic-01SubtopicMenu'></div><div class='title' macro='view title'></div>
<div class='viewer' macro='view text wikified'></div><div class='tagClear'></div>
<!--}}}-->
{{tableindex{
|[[Subject01]]|[[Subject02]]|[[subtopic3]]|
}}}
<!--{{{-->
<div class='toolbar' macro='toolbar closeTiddler closeOthers +editTiddler > fields syncing permalink references jump'></div>
<div class='topic1' macro='tiddler topic1SubtopicMenu'></div>
<div class='title' macro='view title'></div>
<div class='viewer' macro='view text wikified'></div>
<div class='tagClear'></div>
<!--}}}-->
<!--{{{-->
<div class='toolbar' macro='toolbar closeTiddler closeOthers +editTiddler > fields syncing permalink references jump'></div>
<div class='webview' macro='tiddler webviewindex'></div>
<div class='title' macro='view title'></div>
<div class='viewer' macro='view text wikified'></div>
<div class='tagClear'></div>
<!--}}}-->
{{tableindex{
|[[Welcome|Welcome to the Webview TiddlyWiki]]|[[Instructions]]|[[Subtopic menu instructions]]|
}}}
config.options.chkSaveBackups = false;
config.options.chkEnableAnimations = false;
config.options.chkShowRightSidebar= false;
config.options.chkSinglePageMode= true;
config.options.chkSinglePagePermalink= false;