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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

hr {height:1px;}

a {text-decoration:none;}

dt {font-weight:bold;}

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

.txtOptionInput {width:11em;}

#contentWrapper .chkOptionInput {border:0;}

.externalLink {text-decoration:underline;}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

.whenBackstage {display:none;}
.backstageVisible .whenBackstage {display:block;}
/*}}}*/
/***
StyleSheet for use when a translation requires any css style changes.
This StyleSheet can be used directly by languages such as Chinese, Japanese and Korean which use a logographic writing system and need larger font sizes.
***/

/*{{{*/
body {font-size:0.8em;}

#sidebarOptions {font-size:1.05em;}
#sidebarOptions a {font-style:normal;}
#sidebarOptions .sliderPanel {font-size:0.95em;}

.subtitle {font-size:0.8em;}

.viewer table.listView {font-size:0.95em;}

.htmlarea .toolbarHA table {border:1px solid ButtonFace; margin:0em 0em;}
/*}}}*/
/*{{{*/
@media print {
#mainMenu, #sidebar, #messageArea, .toolbar, #backstageButton {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
/***
|''Name:''|ASCIIsvgPlugin|
|''Description:''|Mathematical vector graphics based on [[ASCIIsvg|http://www1.chapman.edu/~jipsen/asciisvg.html]]|
|''Version:''|1.0.0|
|''Date:''|Sep 12, 2007|
|''Source:''|http://www.math.ist.utl.pt/~psoares/addons.html|
|''Documentation:''|[[ASCIIsvgPlugin Documentation|ASCIIsvgPluginDoc]]|
|''Author:''|Paulo Soares|
|''License:''|[[Creative Commons Attribution-Share Alike 3.0 License|http://creativecommons.org/licenses/by-sa/3.0/]]|
|''~CoreVersion:''|2.1.0|
***/
//{{{
Story.prototype.ASCIIsvgRefreshTiddler = Story.prototype.refreshTiddler;
Story.prototype.refreshTiddler = function(title,minorUpdate) {
	setTimeout('drawPictures()',100);
	return(this.ASCIIsvgRefreshTiddler(title,minorUpdate));
}

config.shadowTiddlers.ASCIIsvgPluginDoc="The documentation is available [[here.|http://www.math.ist.utl.pt/~psoares/addons.html#ASCIIsvgPluginDoc]]";
//}}}
!Description
This plugin is a wrapper for a modified version of Peter Jipsen's [[ASCIIsvg|http://www1.chapman.edu/~jipsen/asciisvg.html]]. The main changes are:
#mouseover effects over the figures were removed (too much clumsy code to so little results...)
#a unique id for each figure is mandatory
#small changes in some functions' names (for improved coherence)
Most of the syntax was preserved so, to be able to draw beautiful SVG pictures in your ~TiddlyWiki you should take a look at the [[ASCIIsvg|http://www1.chapman.edu/~jipsen/asciisvg.html]] site.

The plugin is known to do a good job with Mozilla Firefox 2.0 and Opera 9.23. I'm not sure about the awful Internet Explorer (with the Adobe SVG plugin).
!Installation
This is not a self-contained plugin. To install it, download the modified ~ASCIIsvg code [[here|http://www.math.ist.utl.pt/~psoares/TWASCIIsvg.js]] and this other [[one|http://www.math.ist.utl.pt/~psoares/d.svg]], and put them next to your ~TiddlyWiki file. Next, add the following line to the MarkupPreHead tiddler:
{{{
<script type="text/javascript" src="TWASCIIsvg.js"></script>
}}}
Finally, copy the ASCIIsvgPlugin tiddler to your ~TiddlyWiki, give it the //systemConfig// tag, save and reload.
!Credits
A final word of appreciation for Peter Jipsen's fine work on promoting beautiful math in the web.
/%
*There is a new homework assignment listed at [[Homework]], due at the beginning of class on Tuesday, March 24.
*Your first test will be on Thursday, February 12.  Review and practice sheets are listed at [[Tests]].

Welcome to MAT 336.

A supplement for Test 2 is available at [[Tests]].  The final exam is scheduled for Tuesday, December 9, 11:30a-2:30p.

A review guide and sample questions for Test 2 (scheduled for Thursday, November 20) can now be found at [[Tests]].
%/
*Try clicking (memorize) in both columns (to decide which side to start with).
| !Palette<br><script label="(memorize)">return Mem.start(place)</script> | !Definition<br><script label="(memorize)">return Mem.start(place)</script> |
|Division Algorithm |Let $a$ and $b$ be integers with $b > 0.$  Then there exist unique integers $q$ and $r$ for which $a = bq + r$ and $0 \le r < b.$|
|Binary Operation (on a set $G$) |A function that assigns to each ordered pair of elements of $G$ an element of $G.$|
|Cayley Table |A table of results of a binary operation, written in the form of a multiplication table.|
|Closure |The condition that members of an ordered pair from a set $G$ combine to yield a member of $G.$|
|Group |A set $G$ together with a binary operation for which the following properties are satisfied: $(ab)c = a(bc)$ for all $a,b,c \in G$ (associativity); there exists an element $e \in G$ for which $ae = ea = a$ for all $a \in G$ (identity exists); for each element $a \in G,$ there is an element $b \in G$ for which $ab = ba = e$ (inverses exist).|
|Abelian Group $G$ |A group $G$ such that $ab=ba$ for all $a,b \in G.$|
|Uniqueness of the Identity |A group contains only one identity element.|
|Cancellation |In a group, left and right cancellation hold:  $ab = ac$ implies $b=c$ (left cancellation); $ba=ca$ implies $b=c$ (right cancellation).|
|Uniqueness of Inverses |For each element $a$ in a group $G,$ there is a unique element $b \in G$ for which $ab=ba=e.$|
<<tabs CayleyTables
Z4 "Z4" [[Cyclic 4]]
V4 "V4" [[Klein 4]]
Z5 "Z5" [[Cyclic 5]]
S3 "S3" [[Symmetric 3]]
D8 "D8" [[Dihedral 8]]>>
*Instructor
**Dr. Michael Freeze
*MAT 336 meeting time
**Tuesdays and Thursdays 11:00a-12:15p in Bear 164
*Office Location
**Bear Hall 124
*Office Hours
**MWF 9:00-10:00a or by appointment
*Phone
**910.795.1385
*Email
**freezem at uncw dot edu
*Try clicking (memorize) in both columns (to decide which side to start with).
| !Palette<br><script label="(memorize)">return Mem.start(place)</script> | !Definition<br><script label="(memorize)">return Mem.start(place)</script> |
|Left coset of $H$ in $G$ containing $a$ |Given a subgroup $H$ of a group $G$ and an element $a \in G,$ $aH = \{ ah \vert h \in H \}$|
|Right coset of $H$ in $G$ containing $a$ |Given a subgroup $H$ of a group $G$ and an element $a \in G,$ $Ha = \{ ha \vert h \in H \}$|
|Properties of Cosets |If $H \le G$ and $a,b \in G,$ then: (1) $a \in aH;$ (2) $aH = H$ if and only if $a \in H;$ (3) $aH=bH$ or $aH \cap bH = \emptyset ;$  (4) $aH=bH$ if and only if $a^{-1}b \in H;$ (5) $\vert aH \vert = \vert bH \vert ;$ (6) $aH = Ha$ if and only if $H = aHa^{-1} ;$ (7) $aH \le G$ if and only if $a \in H$|
|Lagrange's Theorem |If $G$ is a finite group and $H \le G,$ then $\vert H \vert$ divides $\vert G \vert.$  Furthermore, the number of distinct left or right cosets of $H$ in $G$ is $\frac{\vert G \vert}{\vert H \vert}.$|
|Index of a subgroup, denoted $\vert G : H \vert$ |Given $H\le G,$ the number of distinct left cosets of $H$ in $G.$|
|Corollaries of Lagrange's Theorem |(1) If $G$ is a finite group and $H \le G<$ then $\vert G : H \vert = \frac{\vert G \vert}{\vert H \vert} ;$ (2) For each element $a \in G,$ $\vert a \vert$ divides $\vert G \vert ;$ (3) Groups of prime order are cyclic; (4) If $G$ is a finite group, then for any element $a \in G,$ $a^{\vert G \vert} = e ;$ (5) Fermat's Little Theorem|
|Fermat's Little Theorem |For every integer $a$ and every prime $p,$ $a^{p} \equiv a (\mbox{mod }p).$|
|Classification of groups of order $2p$ |Let $G$ be a group of order $2p,$ where $p$ is a prime greater than 2.  Then $G$ is isomorphic either to $\mathbb{Z}_{2p}$ or to $D_{2p}.$|
|Stabilizer of $i$ in $G,$ denoted $\mbox{stab}_{G}(i)$ |Let $G$ be a group of permutations of a set $S.$  Then $\mbox{stab}_{G}(i) = \{\phi \in G \vert \phi(i) = i\} .$|
|Orbit of $s$ in $G,$ denoted $\mbox{orb}_{G}(s)$ |Let $G$ be a group of permutations of a set $S.$  Then $\mbox{orb}_{G}(s) = \{ \phi(s) \vert \phi \in G \}.$|
|Orbit-Stabilizer Theorem |Let $G$ be a finite group of permutations of a set $S.$  Then, for any $i \in S ,$ $\vert G \vert = \vert \mbox{orb}_{G}(i) \vert \vert \mbox{stab}_{G}(i) \vert .$|
|Rotation group of a cube |The group of rotations of a cube is isomorphic to $S_4 .$|
!Text
//A First Course in Abstract Algebra with Applications//, 3rd ed., Joseph Rotman, 2006.
!Course Content
This course introduces the elementary concepts of group and ring theory. Groups will be considered through their actions on mathematical objects; rings will be considered through their arithmetic properties.
!Computer Use
This course may make use of the Maple and GAP software packages in addition to Java applets as aids in understanding concrete representations of groups.
!Attendance
You are expected to attend class on time each day. Attendance will be recorded on a regular basis.		
!Tests, Homework and Quizzes
Two tests and a final exam will be given. There will be no make-up tests without prior permission. Homework problems will be suggested for each section. Short, unannounced quizzes may also be given occasionally.
!Grading
Each of your two tests will contribute 25% toward your grade. Your combined homework grades will contribute an additional 25%, and your final exam will determine the remaining 25%.
!Plus/Minus Modifiers
A plus or minus may be used as a possible grade modifier, for final grades only, at the end of the semester.  Factors that influence the judgment to assign a + or – (or neither) are:  performance on the final exam, consistency of performance throughout the semester, proximity to a grade borderline, class participation and effort.	
!Academic Expectations
In choosing UNCW, you have become part of our community of scholars.  We recognize that the UNCW learning experience is challenging and requires hard work.  It also requires a commitment to make time available to do that hard work.  The university expects you to make academics your highest priority by dedicating your time and energy to training your mind and acquiring knowledge, and expects you to abide by the Academic Honor Code in the Student Handbook, Code of Student Life.  Academic success in critical thinking and problem solving prepares you for the changes and challenges you will encounter in the future.  Our faculty and academic support resources are readily available as partners in this effort, but the //primary responsibility for learning is yours//.
!Incompletes
A grade of I (incomplete) is given only if documented circumstances beyond the student’s control (e.g., medical, legal) render the student unable to complete the course work, and only if there is a reasonable possibility of passing the course. The grade I is not given for simply failing to meet the course requirements.
!Federal Americans with Disabilities Act
If you have a disability and need reasonable accommodation in order to participate fully in this course, you must be registered with the Office of Disability Services in Westside Hall (x3746).  You need to provide your instructor a copy of your Accommodations Letter within the first week of class or as soon as possible.  You should then meet with your instructor to make mutually agreeable arrangements based on the recommendations of the Accommodations Letter.
[img[cayley-tables/z4.png]]
[img[cayley-tables/z5.png]]
*Try clicking (memorize) in both columns (to decide which side to start with).
| !Palette<br><script label="(memorize)">return Mem.start(place)</script> | !Definition<br><script label="(memorize)">return Mem.start(place)</script> |
|Cyclic Group $G$ |Having an element $a$ which is a generator, i.e., for which $G = \langle a \rangle = \{ a^n \vert n \in Z \}.$|
|Criterion for $a^{i} = a^{j}$ |Let $a$ be an element of a group $G.$ If $a$ has infinite order, then all distinct powers of $a$ are distinct group elements. If $a$ has finite order $n,$ then $\langle a \rangle = \{e, a, a^2, \ldots , a^{n-1} \}$ and $a^{i} = a^{j}$ if and only if $n$ divides $i-j.$|
|Corollaries of criterion for $a^{i} = a^{j}$ |$\vert a \vert = \vert \langle a \rangle \vert ;$ $a^{k} = e$ implies $\vert a \vert$ divides $k.$|
|Criterion for $\langle a^{i} \rangle = \langle a^{j} \rangle$ |Let $\vert a \vert = n.$  Then $\langle a^{i} \rangle = \langle a^{j} \rangle$ if and only if $\mbox{gcd}(n,i) = \mbox{gcd}(n,j).$|
|Generators of cyclic subgroups |Let $G = \langle a \rangle$ be a cyclic group of order $n.$  Then $G = \langle a^{k} \rangle$ if and only if $\mbox{gcd}(n,k)=1.$|
|Generators of $\mathbb{Z}_{n}$ |An integer $k \in \mathbb{Z}_{n}$ is a generator of $\mathbb{Z}_{n}$ if and only if $\mbox{gcd}(n,k)=1.$|
|Fundamental Theorem of Cyclic Groups |Every subgroup of a cyclic group is cyclic.  Moreover, if $\vert \langle a \rangle \vert =n,$ then the order of any subgroup of $\langle a \rangle$ is a divisor of $n.$  In addition, for each positive divisor $k$ of $n,$ the group $\langle a \rangle$ has exactly one subgroup of order $k,$ namely $\langle a^{n/k} \rangle.$|
|Subgroups of $\mathbb{Z}_{n}$ |For each positive divisor $k$ of $n,$ the set $\langle n/k \rangle$ is the unique subgroup of $\mathbb{Z}_{n}$ of order $k.$  Furthermore, these are the only subgroups of $\mathbb{Z}_{n}>$|
|Number of elements of each order in a cyclic group |If $d$ is a positive divisor of $n,$ the number of elements of order $d$ in a cyclic group of order $n$ is $\phi(d).$|
|Number of elements of order $d$ in a finite group |In a finite group, the number of elements of order $d$ is divisible by $\phi(d).$|
|Euler phi function, denoted $\phi(d)$ |Let $\phi(1)=1.$  For $n > 1,$ $\phi(n)$ is the number of positive integers less than $n$ and relatively prime to $n.$|
|Subgroup lattice |A diagram showing the relationships among the various subgroups of a group.|
[[Schedule]]
[img[cayley-tables/d8.png]]
Note that many theorems for $\mathbb{Z}$ have polynomial analogues in $k[x],$ where $k$ is a field.  In fact, as long as the leading coefficient of $f(x)$ is a unit, we may divide by $f(x).$

<<<
''Theorem (Division Algorithm)''
Let $R$ be a commutative ring, let $f(x),g(x) \in R[x],$ and let the leading coefficient of $f(x)$ be a unit in $R.$
#There are polynomials $q(x),r(x) \in R[x]$ with $g(x)=q(x)f(x)+r(x),$ where either $r(x)=0$ or $deg(r) < deg(f).$
#If $R$ is a domain, then the polynomials $q(x)$ and $r(x)$ in part 1 are unique.
<<<

A typical problem is to find roots of polynomials.

<<<
''Definition''
If $f(x) \in k[x],$ where $k$ is a field, then a ''//root// of $f(x)$ in $k$'' is an element $a \in k$ with $f(a)=0.$
<<<
<<<
''Lemma''
Let $f(x) \in k[x],$ where $k$ is a field, and let $a \in k.$  Then there is $q(x) \in k[x]$ with $f(x)=q(x)(x-a)+f(a).$
<<<
<<<
''Proposition''
If $f(x) \in k[x],$ where $k$ is a field, then $a \in k$ is a root of $f(x)$ in $k$ if and only if $x-a$ divides $f(x)$ in $k[x].$
<<<

<<<
''Theorem''
If $k$ is a field and $f(x) \in k[x]$ has degree $n,$ then $f(x)$ has at most $n$ distinct roots in $k.$
> //Proof.// By induction on $n.$

>Warning:  The theorem is false for arbitrary commutative rings.  Consider $x^2-1 \in \mathbb{I}_{8}[x].$
<<<

The prior theorem enables us to determine the structure of the group of units of a finite field.

Recall that if $G$ is a group of order $n$ with at most one cyclic subgroup of order $d$ for each $d$ dividing $n,$ then $G$ is cyclic.

<<<
''Theorem''
If $k$ is a field and $G$ is a finite subgroup of the multiplicative group $k^{\times},$ then $G$ is cyclic.  In particular, if $k$ itself is finite, then $k^{\times}$ is cyclic.
<<<

<<<
''Example''
Find a generator for the group of units of $\mathbb{F}_{4}.$
<<<

----

In order to describe the substructure of other rings, we introduce the notion of //ideal//.

<<<
''Definition''
An ''ideal'' in a commutative ring $R$ is a subset $I$ of $R$ such that
# $0 \in I$
# if $a,b \in I,$ then $a+b \in I$
# if $a \in I$ and $r \in R,$ then $ra \in I$
<<<

<<<
An ideal $I \neq R$ is called a ''proper'' ideal.
An ideal of the form $I = (b) = \{ rb : r \in R \}$ is called the ''principal'' ideal generated by $b.$
<<<

<<<
''Theorem''
Every ideal in $\mathbb{Z}$ is a principal ideal.
<<<

<<<
''Theorem''
If $k$ is a field, then every ideal $I$ in $k[x]$ is a principal ideal.  Moreover, if $I \neq \{0\},$ there is a unique monic polynomial that generates $I.$
> //Proof.//
>Choose a polynomial in $I$ of least degree.
<<<

<<<
''Definition''
A commutative ring $R$ is a ''PID'' (or ''principal ideal domain'') if it is a domain in which every ideal is a principal ideal.
<<<

There are commutative rings which are not principal.  Domains having a division algorithm, however, are principal.

<<<
''Definition''
A commutative ring $R$ is a ''Euclidean ring'' if it is a domain and there is a function $\partial : R^{\times} \rightarrow \mathbb{N}$  (where $R^{\times}$ denotes the nonzero elements of $R$) such that
# $\partial(f) \le \partial(fg)$ for all $f,g \in R^{\times}$
# for all $f,g \in R$ with $f \in R^{\times},$ there exist $q,r \in R$ with $g=qf+r,$ and either $r=0$ or $\partial(r) < \partial(f).$
<<<

<<<
''Example''
The Gaussian integers $\mathbb{Z}[i]$ form a Euclidean ring whose degree function $\partial(a+bi)=a^2+b^2$ is multiplicative.
<<<

Note that quotients and remainders may not be unique in $\mathbb{Z}[i]$.  Consider dividing $\alpha = 3+5i$ by $\beta = 2.$




<<<
''Definition''
A nonempty set $R$ with two operations, addition and multiplication, is a ring provided that:
# ($R$,+) is an (abelian) group
# Multiplication is associative
# There exists a multiplicative unity
# Multiplication distributes over addition
If multiplication is commutative, we say that $R$ is commutative.
<<<

<<<
''Example''
Many familiar structures are rings, including $\mathbb{Z},$ $\mathbb{Q},$ $\mathbb{R},$  $\mathbb{C},$ and $M_{n}(\mathbb{R}).$  

Note that $\mathbb{I}_{m}$ is also a ring.
<<<





The axiomatic structure of commutative rings provides the means to justify familiar and perplexing properties of multiplication of "negative numbers," independent of the type of "numbers" involved.

<<<
''Proposition''
Let $R$ be a commutative ring.
# $0 \cdot a = 0$ for all $a \in R$
# $(-1)(-a)=a$ for all $a \in R$
# $(-1)a = -a$ for all $a \in R$
# $(-a)(-b)=ab$ for all $a,b \in R$
<<<





<<<
''Definition''
$a - b := a + (-b)$
<<<

<<<
''Definition''
Given $n \in \mathbb{N},$ $n \neq 0,$ and $a \in R,$ we define
$na$ as the sum of $n$ copies of $a.$  We say $0a=0.$
<<<





<<<
''Proposition''
If $1=0,$ then $R = \{ 0 \}.$
<<<

<<<
''Definition''
An integral domain is a commutative ring $R$ with $1 \neq 0$ which satisfies the cancellation law:  if $ca = cb$ and $c \neq 0,$ then $a=b.$
<<<

<<<
''Proposition''
A nonzero commutative ring $R$ is a domain iff the product of any two nonzero elements of $R$ is nonzero.
<<<

<<<
''Question''
What is an example of a commutative ring which is not an integral domain?
<<<

<<<
''Definition''
Given $a,b \in R,$ $a \vert b$ in $R$ means that there exists $c \in R$ with $b=ca.$

Note that $0 \vert a$ iff $a=0.$

An element $d \in R$ with $d \neq 0$ is called a zero divisor of $R$ if there exists $c \in R$ with $cd=0.$
<<<



<<<
''Definition''
$u \in R$ is a unit if $u \vert 1$ in $R$.
<<<

<<<
''Example''
The units of $\mathbb{Z}$ are $\pm 1.$

The units of $\mathbb{Z}[i]$ are $\pm 1, \pm i.$
<<<


<<<
''Question''
In a commutative ring, is every element which is not a zero divisor necessarily a unit?
<<<





<<<
''Proposition''
Let $R$ be a domain and $a,b$ nonzero elements of $R.$  Then $a \vert b$ and $b \vert a$ iff $b = ua$ for some unit $u \in R.$
<<<

<<<
''Question''
What are the units in $\mathbf{I}_{m}?$
<<<



*Try clicking (memorize) in both columns (to decide which side to start with).
| !Palette<br><script label="(memorize)">return Mem.start(place)</script> | !Definition<br><script label="(memorize)">return Mem.start(place)</script> |
|Order of a group, denoted $\vert G \vert$ |The number of elements (finite or infinite) in $G.$|
|Order of an element, denoted $\vert g \vert$ |The smallest positive integer $n$ for which $g^n = e.$|
|Subgroup $H$ of $G,$ denoted $H \le G$ |A subset $H$ of a group $G$ that itself forms a group.|
|Proper subgroup $H$ of $G,$ denoted $H < G$ |A subgroup $H$ of $G$ that is not equal to $G.$|
|Trivial Subgroup |The subgroup consisting of the identity element alone.|
|One-step Subgroup Test |Let $G$ be a group and $H$ be a nonempty subset.  Then $H$ is a subgroup of $G$ if $ab^{-1}$ (or $a-b$ in additive notation) is in $H$ whenever $a$ and $b$ are in $H.$|
|Two-step subgroup Test |Let $G$ be a group and $H$ be a nonempty subset.  Then $H$ is a subgroup of $G$ if $ab$ is in $H$ whenever $a$ and $b$ are in $H,$ and $a^{-1}$ is in $H$ whenever $a$ is in $H.$|
|Finite Subgroup Test |Let $H$ be a finite nonempty subset of a group $G.$  Then $H \le G$ if $H$ is closed under the operation of $G.$|
|$\langle a \rangle$ is a subgroup |For any element $a$ of a group $G,$ $\langle a \rangle \le G.$|
|Center of a group, denoted $Z(G)$ |$Z(G) = \{ a \in G \vert ax=xa \mbox{ for all } x \in G \}.$|
|Center is a subgroup |$Z(G) \le G$|
|Centralizer of $a \in G,$ denoted $C(a)$ |$C(a)= \{x \in G \vert ax=xa \}$|
|$C(a)$ is a subgroup |For each $a$ in a group $G,$ $C(a) \le G.$|
<<slideShow>>
-s-
!History of Mathematics
Why study the history of mathematics?

-s-
!Pertinence
"It is interesting and pertinent that ... a true appreciation of a branch of mathematics is impossible without some acquaintance with the history of that branch, for mathematics is largely a study of ideas, and a genuine understanding of ideas is not possible without an analysis of origins." (Howard Eves)

"I am sure that no subject loses more than mathematics by any attempt to dissociate it from its history." (J.W.L. Glaisher)

-s-
!Organization of Study
How do we organize our study of the history of mathematics?

*Personalities
*Cultures
*Problems
*Theorems
*Issues

-s-
!Early Mathematical Periods

*Egyptian and Babylonian
**3000 BC - 260 AD
*Greek
**600 BC - 450 AD
*Chinese
**1030 BC - 1644 AD
*Hindu
**200 BC - 1250 AD
*Arabian
**650 - 1200 AD


-s-
!Late Mathematical Periods
*Dark Ages
**450 - 1120 AD
*Middle Ages
**950 - 1500 AD
*Renaissance
**1450 - 1700 AD
*Modern
**1700 AD - present


-s-
!Guidance of Study
What questions should we ask about historical sources?

*Context
**"Where does it come from?"
*Content
**"What is it about?"
*Significance
**"Why is it important?"


-s-
!Context and Content:  Egyptian and Babylonian Period

*Practical problems of central government
**Agriculture
**Surveying
**Taxation
**Trade
*Training of leaders

-s-
!Context and Content:  Greek Period
*Intellectual interest
**Geometry
**Astronomy
**Mechanics

-s-
!Context and Content:  Chinese Period
*Empire administration
**Agriculture
**Business
**Engineering
**Surveying

-s-
!Context and Content:  Hindu Period
*Arithmetic algorithms
*Numeral system
*Zero symbol
*Negative numbers

-s-
!Context and Content: Arabian Period
*Astronomy and spherical trigonometry
*Ornamentation


-s-
!Context and Content:  Middle Ages
*Cathedral schools
*Trade and arithmetic


-s-
!Context and Content:  Renaissance
*Commerce
**Navigation
**Banking
*Symbolism
*Kinematics


-s-
!Context and Content:  Modern Period
*Representation
**number
**function
*Foundations
**Construction of real numbers
**Set theory
*Non-Euclidean Geometry
*Abstract spaces

-s-
!Issues of Significance

*Encoding of knowledge
**Short-term
**Mid-term
**Long-term
*Conceptual Framework
**Number
**Approximate versus exact
**Geometry
**Algebra
**Set
*Limits of knowledge
**Algorithm versus demonstration
**Classification and certainty
**Creation versus discovery

from Rotman's //First Course in Abstract Algebra with Applications//, 3rd ed:

!Assigned Exercises
*Homework 1 (due Tuesday, January 20)
**p.15 1.3, 1.11; p.35 1.30, 1.31
*Homework 2 (due Thursday, January 22)
**p.53 1.47, 1.50; p.74 1.78, 1.86
*Homework 3 (due Thursday, February 5 )
**p.104ff 2.3, 2.13; p.124 2.25, 2.30
*Homework 4 (due Tuesday, February 10)
**p.146 2.40, 2.44, 2.46
*Homework 5 (due Thursday, February 26)
**p. 158 2.53,2.55,2.57
*Homework 6 (due Tuesday, March 24)
**p.169 2.68, 2.71; p.190ff 2.102, 2.106

!Suggested Exercises 
*Chapter 1
**1.1,1.3,1.5,1.10,1.11
**1.28,1.30,1.31,1.45
**1.46,1.47,1.49,1.50,1.58,1.60
**1.68,1.71,1.72
**1.77,1.78,1.80,1.86,1.88
*Chapter 2
**2.1,2.3,2.13,2.14
**2.21,2.25,2.30,2.35
**2.36,2.40,2.44,2.46
**2.52,2.53,2.55,2.57
**2.64,2.68,2.70,2.71,2.79
**2.95,2.98,2.102,2.106
**2.114,2.117,2.125,2.126
*Chapter 3
**3.1,3.3,3.4,3.6
**3.17,3.19,3.20,3.21
/%
**3.29,3.30,3.32,3.33
**3.41,3.42,3.43,3.44
**3.56,3.58,3.61,3.64
**3.82,3.85
**3.86,3.87,3.88,3.91
**3.92,3.97,3.98,3.99
%/
/***
|Name|InlineJavascriptPlugin|
|Source|http://www.TiddlyTools.com/#InlineJavascriptPlugin|
|Version|1.6.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||
|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.
!!!!!Usage
<<<
When installed, this plugin adds new wiki syntax for surrounding tiddler content with {{{<script>}}} and {{{</script>}}} markers, so that it can be treated as embedded javascript and executed each time the tiddler is rendered.

''Deferred execution from an 'onClick' link''
By including a {{{label="..."}}} parameter in the initial {{{<script>}}} marker, the plugin will create a link to an 'onclick' script that will only be executed when that specific link is clicked, rather than running the script each time the tiddler is rendered.  You may also include a {{{title="..."}}} parameter to specify the 'tooltip' text that will appear whenever the mouse is moved over the onClick link text

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

''Display script source in tiddler output''
By including the keyword parameter "show", in the initial {{{<script>}}} marker, the plugin will include the script source code in the output that it displays in the tiddler.

''Defining javascript functions and libraries:''
Although the external javascript file is loaded while the tiddler content is being rendered, any functions it defines will not be available for use until //after// the rendering has been completed.  Thus, you cannot load a library and //immediately// use it's functions within the same tiddler.  However, once that tiddler has been loaded, the library functions can be freely used in any tiddler (even the one in which it was initially loaded).

To ensure that your javascript functions are always available when needed, you should load the libraries from a tiddler that will be rendered as soon as your TiddlyWiki document is opened.  For example, you could put your {{{<script src="..."></script>}}} syntax into a tiddler called LoadScripts, and then add {{{<<tiddler LoadScripts>>}}} in your MainMenu tiddler.

Since the MainMenu is always rendered immediately upon opening your document, the library will always be loaded before any other tiddlers that rely upon the functions it defines.  Loading an external javascript library does not produce any direct output in the tiddler, so these definitions should have no impact on the appearance of your MainMenu.

''Creating dynamic tiddler content''
An important difference between this implementation of embedded scripting and conventional embedded javascript techniques for web pages is the method used to produce output that is dynamically inserted into the document:
* In a typical web document, you use the document.write() function to output text sequences (often containing HTML tags) that are then rendered when the entire document is first loaded into the browser window.
* However, in a ~TiddlyWiki document, tiddlers (and other DOM elements) are created, deleted, and rendered "on-the-fly", so writing directly to the global 'document' object does not produce the results you want (i.e., replacing the embedded script within the tiddler content), and completely replaces the entire ~TiddlyWiki document in your browser window.
* To allow these scripts to work unmodified, the plugin automatically converts all occurences of document.write() so that the output is inserted into the tiddler content instead of replacing the entire ~TiddlyWiki document.

If your script does not use document.write() to create dynamically embedded content within a tiddler, your javascript can, as an alternative, explicitly return a text value that the plugin can then pass through the wikify() rendering engine to insert into the tiddler display.  For example, using {{{return "thistext"}}} will produce the same output as {{{document.write("thistext")}}}.

//Note: your script code is automatically 'wrapped' inside a function, {{{_out()}}}, so that any return value you provide can be correctly handled by the plugin and inserted into the tiddler.  To avoid unpredictable results (and possibly fatal execution errors), this function should never be redefined or called from ''within'' your script code.//

''Accessing the ~TiddlyWiki DOM''
The plugin provides one pre-defined variable, 'place', that is passed in to your javascript code so that it can have direct access to the containing DOM element into which the tiddler output is currently being rendered.

Access to this DOM element allows you to create scripts that can:
* vary their actions based upon the specific location in which they are embedded
* access 'tiddler-relative' information (use findContainingTiddler(place))
* perform direct DOM manipulations (when returning wikified text is not enough)
<<<
!!!!!Examples
<<<
an "alert" message box:
><script show>
	alert('InlineJavascriptPlugin: this is a demonstration message');
</script>
dynamic output:
><script show>
	return (new Date()).toString();
</script>
wikified dynamic output:
><script show>
	return "link to current user: [["+config.options.txtUserName+"]]";
</script>
dynamic output using 'place' to get size information for current tiddler:
><script show>
   if (!window.story) window.story=window;
   var title=story.findContainingTiddler(place).id.substr(7);
   return title+" is using "+store.getTiddlerText(title).length+" bytes";
</script>
creating an 'onclick' button/link that runs a script:
><script label="click here" title="clicking this link will show an 'alert' box" show>
   if (!window.story) window.story=window;
   alert("Hello World!\nlinktext='"+place.firstChild.data+"'\ntiddler='"+story.findContainingTiddler(place).id.substr(7)+"'");
</script>
loading a script from a source url:
>http://www.TiddlyTools.com/demo.js contains:
>>{{{function demo() { alert('this output is from demo(), defined in demo.js') } }}}
>>{{{alert('InlineJavascriptPlugin: demo.js has been loaded'); }}}
><script src="demo.js" show>
	return "loading demo.js..."
</script>
><script label="click to execute demo() function" show>
	demo()
</script>
<<<
!!!!!Installation
<<<
import (or copy/paste) the following tiddlers into your document:
''InlineJavascriptPlugin'' (tagged with <<tag systemConfig>>)
<<<
!!!!!Revision History
<<<
''2007.02.19 [1.6.0]'' added support for title="..." to specify mouseover tooltip when using an onclick (label="...") script
''2006.10.16 [1.5.2]'' add newline before closing '}' in 'function out_' wrapper.  Fixes error caused when last line of script is a comment.
''2006.06.01 [1.5.1]'' when calling wikify() on script return value, pass hightlightRegExp and tiddler params so macros that rely on these values can render properly
''2006.04.19 [1.5.0]'' added 'show' parameter to force display of javascript source code in tiddler output
''2006.01.05 [1.4.0]'' added support 'onclick' scripts.  When label="..." param is present, a button/link is created using the indicated label text, and the script is only executed when the button/link is clicked.  'place' value is set to match the clicked button/link element.
''2005.12.13 [1.3.1]'' when catching eval error in IE, e.description contains the error text, instead of e.toString().  Fixed error reporting so IE shows the correct response text.  Based on a suggestion by UdoBorkowski
''2005.11.09 [1.3.0]'' for 'inline' scripts (i.e., not scripts loaded with src="..."), automatically replace calls to 'document.write()' with 'place.innerHTML+=' so script output is directed into tiddler content.  Based on a suggestion by BradleyMeck
''2005.11.08 [1.2.0]'' handle loading of javascript from an external URL via src="..." syntax
''2005.11.08 [1.1.0]'' pass 'place' param into scripts to provide direct DOM access 
''2005.11.08 [1.0.0]'' initial release
<<<
!!!!!Credits
<<<
This feature was developed by EricShulman from [[ELS Design Studios|http:/www.elsdesign.com]]
<<<
!!!!!Code
***/
//{{{
version.extensions.inlineJavascript= {major: 1, minor: 6, revision: 0, date: new Date(2007,2,19)};

config.formatters.push( {
	name: "inlineJavascript",
	match: "\\<script",
	lookahead: "\\<script(?: src=\\\"((?:.|\\n)*?)\\\")?(?: label=\\\"((?:.|\\n)*?)\\\")?(?: title=\\\"((?:.|\\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) {
			if (lookaheadMatch[1]) { // 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 = lookaheadMatch[1];
				document.body.appendChild(script); document.body.removeChild(script);
			}
			if (lookaheadMatch[5]) { // there is script code
				if (lookaheadMatch[4]) // show inline script code in tiddler output
					wikify("{{{\n"+lookaheadMatch[0]+"\n}}}\n",w.output);
				if (lookaheadMatch[2]) { // 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",lookaheadMatch[2]);
					link.onclick=function(){try{return(eval(this.code))}catch(e){alert(e.description?e.description:e.toString())}}
					link.code="function _out(place){"+lookaheadMatch[5]+"\n};_out(this);"
					link.setAttribute("title",lookaheadMatch[3]?lookaheadMatch[3]:"");
					link.setAttribute("href","javascript:;");
					link.style.cursor="pointer";
				}
				else { // run inline script code
					var code="function _out(place){"+lookaheadMatch[5]+"\n};_out(w.output);"
					code=code.replace(/document.write\(/gi,'place.innerHTML+=(');
					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;
		}
	}
} )
//}}}
*Try clicking (memorize) in both columns (to decide which side to start with).
| !Palette<br><script label="(memorize)">return Mem.start(place)</script> | !Definition<br><script label="(memorize)">return Mem.start(place)</script> |
|Division Algorithm |Let $a$ and $b$ be integers with $b > 0.$  Then there exist unique integers $q$ and $r$ for which $a = bq + r$ and $0 \le r < b.$|
|Well Ordering Principle |Every nonempty set of positive integers contains a smallest member.|
|GCD is a linear combination |For any nonzero integers $a$ and $b,$ there exist integers $s$ and $t$ for which $\mbox{gcd}(a,b) = as + bt.$  <br /> Furthermore, $\mbox{gcd}(a,b)$ is the smallest positive integers of the form $as+bt.$|
|Euclid's Lemma |For integers $a,b$ and prime $p,$ $p \vert ab$ implies $p \vert a$ or $p \vert b.$|
|Fundamental Theorem of Arithmetic |Every integer greater than $1$ is a prime or a product of primes.  This product is unique, except for the order in which factors appear.|
|Weak Principle of Mathematical Induction |Let $S$ be a set of integers containing $a.$  Suppose that $S$ has the property that whenever some integer $n \ge a$ belongs to $S,$ then the integer $n+1$ also belongs to $S.$  Then $S$ contains every integer greater than or equal to $a.$|
|Strong Principle of Mathematical Induction|Let $S$ be a set of integers containing $a.$  Suppose that $S$ has the property that whenever some integer $n \ge a$ belongs to $S,$ then every integer less than $n$ and greater than $a$ also belongs to $S.$  Then $S$ contains every integer greater than or equal to $a.$|
|Equivalence relation on a set $S$ |A set $R$ of ordered pairs of elements of $S$ such that: $(a,a) \in R$ for all $a \in S$ (reflexivity); $(a,b) \in R$ implies $(b,a) \in R$ for all $a,b \in S$ (symmetry); $(a,b) \in R$ and $(b,c) \in R$ imply $(a,c) \in R$ for all $a,b,c \in S$ (transitivity).|
|Equivalence class (of an element $a \in S$) |$[a] = \{ x \in S \vert x \sim a \}$|
|Partition of a set $S$ |A collection of nonempty disjoint subsets of $S$ whose union is $S.$|
|Equivalence Classes Partition |The equivalence classes of an equivalence relation on a set $S$ constitute a partition of $S.$  Conversely, for any partition $P$ of $S,$ there is an equivalence relation on $S$ whose equivalence classes are the elements of $P.$|
|Function from set $A$ to set $B$ |A rule that assigns to each element of $a \in A$ exactly one element $b \in B.$|
|Image of $A$ under $\phi: A \rightarrow B$ |The set of images of all elements of $A,$ i.e., $\{ \phi(a) \vert a \in A \}.$|
|Composition of functions $\psi \phi$ |Given $\phi: A \rightarrow B$ and $\psi: B \rightarrow C,$ the mapping from $A$ to $C$ defined by $(\psi \phi)(a) = \psi(\phi(a)).$|
|One-to-one function |A function $\phi: A \rightarrow B$ with the property that $\phi(a)=\phi(b)$ implies $a=b.$|
|Onto function |A function $\phi: A \rightarrow B$ with the property that for every $b \in B,$ there exists at least one $a \in A$ for which $\phi(a)=b.$|
 
Determine whether the following polynomials are irreducible in $\mathbb{Q}[x].$

# $f(x)=3x^2-7x-5$
# $f(x)=350x^3-25x^2+34x+1$
# $f(x)=2x^3-x-6$
# $f(x)=8x^3-6x-1$
# $f(x)=x^3+6x^2+5x+25$
# $f(x)=x^5-4x+2$
# $f(x)=x^4+x^2+x+1$
# $f(x)=x^4-10x^2+1$
# $f(x)=x^6-210x-616$
# $f(x)=350x^3+x^2+4x+1$

*Try clicking (memorize) in both columns (to decide which side to start with).
| !Palette<br><script label="(memorize)">return Mem.start(place)</script> | !Definition<br><script label="(memorize)">return Mem.start(place)</script> |
|Isomorphism |A one-to-one mapping $\phi$ from a group $G$ onto another group $\overline{G}$ that is operation preserving, i.e., $\phi(ab) = \phi(a)\phi(b)$ for all $a,b \in G.$|
|Isomorphic (pertaining to two groups) |Having an isomorphism between two groups.|
|Cayley's Theorem |Every group is isomorphic to a set of permutations.|
|Properties of isomorphisms acting on elements |Suppose that $\phi$ is an isomorphism from a group $G$ onto another group $\overline{G}.$  Then (1) $\phi$ carries the identity of $G$ to the identity of $\overline{G};$ (2) For every integer $n$ and for every element $a \in G,$ $\phi(a^n) = [\phi(a)]^n;$ (3) For elements $a,b \in G,$ $a$ and $b$ commute if and only if $\phi(a)$ and $\phi(b)$ commute; (4) $\vert a \vert = \vert \phi(a) \vert$ for all $a \in G;$ (5) For a fixed integer $k$ and a fixed group element $b \in G,$ $x^k = b$ has the same number of solutions in $G$ as does the equation $x^k = \phi(b)$ in $\overline{G}.$|
|Properties of isomorphisms acting on groups |Suppose that $\phi$ is an isomorphism from a group $G$ onto another group $\overline{G}.$  Then: (1) $G$ is Abelian if and only if $\overline{G}$ is Abelian; (2) $G$ is cyclic if and only if $\overline{G}$ is cyclic; (3) $\phi^{-1}$ is an isomorphisms from $\overline{G}$ onto $G;$ (4) If $K \le G,$ then $\phi(K) = \{ \phi(k) \vert k \in K \} \le G.$|
|Automorphism (of a group) |An isomorphism of a group onto itself.|
|Inner Automorphism induced by a, denoted $\phi_{a}$ |The function defined by $\phi_{a}(x) = axa^{-1}$ for all $x \in G.$|
|$\mbox{Aut}(G)$ and $\mbox{Inn}(G)$ are groups |The set of automorphisms of a group and the set of inner automorphisms of a group are both groups under function composition.|
|Automorphisms of $\mathbb{Z}_{n}$ are multiplication maps |For every positive integer $n,$ $\mbox{Aut}(\mathbb{Z}_{n}) \cong U(n).$|
[img[cayley-tables/v4.png]]
/***
|''Name:''|LaTeXMathMLPlugin|
|''Description:''|~LaTeX plugin with ~MathML output based on [[LaTeXMathML|http://www.maths.nottingham.ac.uk/personal/drw/lm.html]]|
|''Version:''|1.1|
|''Date:''|Oct 06, 2007|
|''Source:''|http://www.math.ist.utl.pt/~psoares/addons.html|
|''Documentation:''|[[LaTeXMathMLPlugin Documentation|LaTeXMathMLPluginDoc]]|
|''Author:''|Paulo Soares|
|''License:''|[[Creative Commons Attribution-Share Alike 3.0 License|http://creativecommons.org/licenses/by-sa/3.0/]]|
|''~CoreVersion:''|2.1.0|
***/
//{{{
config.macros.LaTeXMathMLPlugin = {
	AMnames: [],
	isIE: document.createElementNS==null,
	AMmathml: "http://www.w3.org/1998/Math/MathML",
	AMcal: [0xEF35,0x212C,0xEF36,0xEF37,0x2130,0x2131,0xEF38,0x210B,0x2110,0xEF39,0xEF3A,0x2112,0x2133,0xEF3B,0xEF3C,0xEF3D,0xEF3E,0x211B,0xEF3F,0xEF40,0xEF41,0xEF42,0xEF43,0xEF44,0xEF45,0xEF46],
	AMfrk: [0xEF5D,0xEF5E,0x212D,0xEF5F,0xEF60,0xEF61,0xEF62,0x210C,0x2111,0xEF63,0xEF64,0xEF65,0xEF66,0xEF67,0xEF68,0xEF69,0xEF6A,0x211C,0xEF6B,0xEF6C,0xEF6D,0xEF6E,0xEF6F,0xEF70,0xEF71,0x2128],
	AMbbb: [0xEF8C,0xEF8D,0x2102,0xEF8E,0xEF8F,0xEF90,0xEF91,0x210D,0xEF92,0xEF93,0xEF94,0xEF95,0xEF96,0x2115,0xEF97,0x2119,0x211A,0x211D,0xEF98,0xEF99,0xEF9A,0xEF9B,0xEF9C,0xEF9D,0xEF9E,0x2124],
	CONST: 0, UNARY: 1, BINARY: 2, INFIX: 3, LEFTBRACKET: 4, RIGHTBRACKET: 5, SPACE: 6, UNDEROVER: 7, DEFINITION: 8, TEXT: 9, BIG: 10, LONG: 11, STRETCHY: 12, MATRIX: 13,
	AMsymbols: [
	//Greek letters
		{input:"\\alpha", tag:"mi", output:"\u03B1", ttype:0},
		{input:"\\beta", tag:"mi", output:"\u03B2", ttype:0},
		{input:"\\gamma", tag:"mi", output:"\u03B3", ttype:0},
		{input:"\\delta", tag:"mi", output:"\u03B4", ttype:0},
		{input:"\\epsilon", tag:"mi", output:"\u03B5", ttype:0},
		{input:"\\varepsilon", tag:"mi", output:"\u025B", ttype:0},
		{input:"\\zeta", tag:"mi", output:"\u03B6", ttype:0},
		{input:"\\eta", tag:"mi", output:"\u03B7", ttype:0},
		{input:"\\theta", tag:"mi", output:"\u03B8", ttype:0},
		{input:"\\vartheta", tag:"mi", output:"\u03D1", ttype:0},
		{input:"\\iota", tag:"mi", output:"\u03B9", ttype:0},
		{input:"\\kappa", tag:"mi", output:"\u03BA", ttype:0},
		{input:"\\lambda", tag:"mi", output:"\u03BB", ttype:0},
		{input:"\\mu", tag:"mi", output:"\u03BC", ttype:0},
		{input:"\\nu", tag:"mi", output:"\u03BD", ttype:0},
		{input:"\\xi", tag:"mi", output:"\u03BE", ttype:0},
		{input:"\\pi", tag:"mi", output:"\u03C0", ttype:0},
		{input:"\\varpi", tag:"mi", output:"\u03D6", ttype:0},
		{input:"\\rho", tag:"mi", output:"\u03C1", ttype:0},
		{input:"\\varrho", tag:"mi", output:"\u03F1", ttype:0},
		{input:"\\varsigma", tag:"mi", output:"\u03C2", ttype:0},
		{input:"\\sigma", tag:"mi", output:"\u03C3", ttype:0},
		{input:"\\tau", tag:"mi", output:"\u03C4", ttype:0},
		{input:"\\upsilon", tag:"mi", output:"\u03C5", ttype:0},
		{input:"\\phi", tag:"mi", output:"\u03C6", ttype:0},
		{input:"\\varphi", tag:"mi", output:"\u03D5", ttype:0},
		{input:"\\chi", tag:"mi", output:"\u03C7", ttype:0},
		{input:"\\psi", tag:"mi", output:"\u03C8", ttype:0},
		{input:"\\omega", tag:"mi", output:"\u03C9", ttype:0},
		{input:"\\Gamma", tag:"mo", output:"\u0393", ttype:0},
		{input:"\\Delta", tag:"mo", output:"\u0394", ttype:0},
		{input:"\\Theta", tag:"mo", output:"\u0398", ttype:0},
		{input:"\\Lambda", tag:"mo", output:"\u039B", ttype:0},
		{input:"\\Xi", tag:"mo", output:"\u039E", ttype:0},
		{input:"\\Pi", tag:"mo", output:"\u03A0", ttype:0},
		{input:"\\Sigma", tag:"mo", output:"\u03A3", ttype:0},
		{input:"\\Upsilon", tag:"mo", output:"\u03A5", ttype:0},
		{input:"\\Phi", tag:"mo", output:"\u03A6", ttype:0},
		{input:"\\Psi", tag:"mo", output:"\u03A8", ttype:0},
		{input:"\\Omega", tag:"mo", output:"\u03A9", ttype:0},
	//fractions
		{input:"\\frac12", tag:"mo", output:"\u00BD", ttype:0},
		{input:"\\frac14", tag:"mo", output:"\u00BC", ttype:0},
		{input:"\\frac34", tag:"mo", output:"\u00BE", ttype:0},
		{input:"\\frac13", tag:"mo", output:"\u2153", ttype:0},
		{input:"\\frac23", tag:"mo", output:"\u2154", ttype:0},
		{input:"\\frac15", tag:"mo", output:"\u2155", ttype:0},
		{input:"\\frac25", tag:"mo", output:"\u2156", ttype:0},
		{input:"\\frac35", tag:"mo", output:"\u2157", ttype:0},
		{input:"\\frac45", tag:"mo", output:"\u2158", ttype:0},
		{input:"\\frac16", tag:"mo", output:"\u2159", ttype:0},
		{input:"\\frac56", tag:"mo", output:"\u215A", ttype:0},
		{input:"\\frac18", tag:"mo", output:"\u215B", ttype:0},
		{input:"\\frac38", tag:"mo", output:"\u215C", ttype:0},
		{input:"\\frac58", tag:"mo", output:"\u215D", ttype:0},
		{input:"\\frac78", tag:"mo", output:"\u215E", ttype:0},
	//binary operation symbols
		{input:"\\pm", tag:"mo", output:"\u00B1", ttype:0},
		{input:"\\mp", tag:"mo", output:"\u2213", ttype:0},
		{input:"\\triangleleft",tag:"mo", output:"\u22B2", ttype:0},
		{input:"\\triangleright",tag:"mo",output:"\u22B3", ttype:0},
		{input:"\\cdot", tag:"mo", output:"\u22C5", ttype:0},
		{input:"\\star", tag:"mo", output:"\u22C6", ttype:0},
		{input:"\\ast", tag:"mo", output:"\u002A", ttype:0},
		{input:"\\times", tag:"mo", output:"\u00D7", ttype:0},
		{input:"\\div", tag:"mo", output:"\u00F7", ttype:0},
		{input:"\\circ", tag:"mo", output:"\u2218", ttype:0},
		{input:"\\bullet", tag:"mo", output:"\u2022", ttype:0},
		{input:"\\oplus", tag:"mo", output:"\u2295", ttype:0},
		{input:"\\ominus", tag:"mo", output:"\u2296", ttype:0},
		{input:"\\otimes", tag:"mo", output:"\u2297", ttype:0},
		{input:"\\bigcirc", tag:"mo", output:"\u25CB", ttype:0},
		{input:"\\oslash", tag:"mo", output:"\u2298", ttype:0},
		{input:"\\odot", tag:"mo", output:"\u2299", ttype:0},
		{input:"\\land", tag:"mo", output:"\u2227", ttype:0},
		{input:"\\wedge", tag:"mo", output:"\u2227", ttype:0},
		{input:"\\lor", tag:"mo", output:"\u2228", ttype:0},
		{input:"\\vee", tag:"mo", output:"\u2228", ttype:0},
		{input:"\\cap", tag:"mo", output:"\u2229", ttype:0},
		{input:"\\cup", tag:"mo", output:"\u222A", ttype:0},
		{input:"\\sqcap", tag:"mo", output:"\u2293", ttype:0},
		{input:"\\sqcup", tag:"mo", output:"\u2294", ttype:0},
		{input:"\\uplus", tag:"mo", output:"\u228E", ttype:0},
		{input:"\\amalg", tag:"mo", output:"\u2210", ttype:0},
		{input:"\\bigtriangleup",tag:"mo",output:"\u25B3", ttype:0},
		{input:"\\bigtriangledown",tag:"mo",output:"\u25BD", ttype:0},
		{input:"\\dag", tag:"mo", output:"\u2020", ttype:0},
		{input:"\\dagger", tag:"mo", output:"\u2020", ttype:0},
		{input:"\\ddag", tag:"mo", output:"\u2021", ttype:0},
		{input:"\\ddagger", tag:"mo", output:"\u2021", ttype:0},
		{input:"\\lhd", tag:"mo", output:"\u22B2", ttype:0},
		{input:"\\rhd", tag:"mo", output:"\u22B3", ttype:0},
		{input:"\\unlhd", tag:"mo", output:"\u22B4", ttype:0},
		{input:"\\unrhd", tag:"mo", output:"\u22B5", ttype:0},
	//Big Operators
		{input:"\\sum", tag:"mo", output:"\u2211", ttype:7},
		{input:"\\prod", tag:"mo", output:"\u220F", ttype:7},
		{input:"\\bigcap", tag:"mo", output:"\u22C2", ttype:7},
		{input:"\\bigcup", tag:"mo", output:"\u22C3", ttype:7},
		{input:"\\bigwedge", tag:"mo", output:"\u22C0", ttype:7},
		{input:"\\bigvee", tag:"mo", output:"\u22C1", ttype:7},
		{input:"\\bigsqcap", tag:"mo", output:"\u2A05", ttype:7},
		{input:"\\bigsqcup", tag:"mo", output:"\u2A06", ttype:7},
		{input:"\\coprod", tag:"mo", output:"\u2210", ttype:7},
		{input:"\\bigoplus", tag:"mo", output:"\u2A01", ttype:7},
		{input:"\\bigotimes", tag:"mo", output:"\u2A02", ttype:7},
		{input:"\\bigodot", tag:"mo", output:"\u2A00", ttype:7},
		{input:"\\biguplus", tag:"mo", output:"\u2A04", ttype:7},
		{input:"\\int", tag:"mo", output:"\u222B", ttype:0},
		{input:"\\oint", tag:"mo", output:"\u222E", ttype:0},
	//binary relation symbols
		{input:":=", tag:"mo", output:":=", ttype:0},
		{input:"\\lt", tag:"mo", output:"<", ttype:0},
		{input:"\\gt", tag:"mo", output:">", ttype:0},
		{input:"\\ne", tag:"mo", output:"\u2260", ttype:0},
		{input:"\\neq", tag:"mo", output:"\u2260", ttype:0},
		{input:"\\le", tag:"mo", output:"\u2264", ttype:0},
		{input:"\\leq", tag:"mo", output:"\u2264", ttype:0},
		{input:"\\leqslant", tag:"mo", output:"\u2264", ttype:0},
		{input:"\\ge", tag:"mo", output:"\u2265", ttype:0},
		{input:"\\geq", tag:"mo", output:"\u2265", ttype:0},
		{input:"\\geqslant", tag:"mo", output:"\u2265", ttype:0},
		{input:"\\equiv", tag:"mo", output:"\u2261", ttype:0},
		{input:"\\ll", tag:"mo", output:"\u226A", ttype:0},
		{input:"\\gg", tag:"mo", output:"\u226B", ttype:0},
		{input:"\\doteq", tag:"mo", output:"\u2250", ttype:0},
		{input:"\\prec", tag:"mo", output:"\u227A", ttype:0},
		{input:"\\succ", tag:"mo", output:"\u227B", ttype:0},
		{input:"\\preceq", tag:"mo", output:"\u227C", ttype:0},
		{input:"\\succeq", tag:"mo", output:"\u227D", ttype:0},
		{input:"\\subset", tag:"mo", output:"\u2282", ttype:0},
		{input:"\\supset", tag:"mo", output:"\u2283", ttype:0},
		{input:"\\subseteq", tag:"mo", output:"\u2286", ttype:0},
		{input:"\\supseteq", tag:"mo", output:"\u2287", ttype:0},
		{input:"\\sqsubset", tag:"mo", output:"\u228F", ttype:0},
		{input:"\\sqsupset", tag:"mo", output:"\u2290", ttype:0},
		{input:"\\sqsubseteq", tag:"mo", output:"\u2291", ttype:0},
		{input:"\\sqsupseteq", tag:"mo", output:"\u2292", ttype:0},
		{input:"\\sim", tag:"mo", output:"\u223C", ttype:0},
		{input:"\\simeq", tag:"mo", output:"\u2243", ttype:0},
		{input:"\\approx", tag:"mo", output:"\u2248", ttype:0},
		{input:"\\cong", tag:"mo", output:"\u2245", ttype:0},
		{input:"\\Join", tag:"mo", output:"\u22C8", ttype:0},
		{input:"\\bowtie", tag:"mo", output:"\u22C8", ttype:0},
		{input:"\\in", tag:"mo", output:"\u2208", ttype:0},
		{input:"\\ni", tag:"mo", output:"\u220B", ttype:0},
		{input:"\\owns", tag:"mo", output:"\u220B", ttype:0},
		{input:"\\propto", tag:"mo", output:"\u221D", ttype:0},
		{input:"\\vdash", tag:"mo", output:"\u22A2", ttype:0},
		{input:"\\dashv", tag:"mo", output:"\u22A3", ttype:0},
		{input:"\\models", tag:"mo", output:"\u22A8", ttype:0},
		{input:"\\perp", tag:"mo", output:"\u22A5", ttype:0},
		{input:"\\smile", tag:"mo", output:"\u2323", ttype:0},
		{input:"\\frown", tag:"mo", output:"\u2322", ttype:0},
		{input:"\\asymp", tag:"mo", output:"\u224D", ttype:0},
		{input:"\\notin", tag:"mo", output:"\u2209", ttype:0},
	//matrices
		{input:"\\begin{eqnarray}", output:"X", ttype:13, invisible:true},
		{input:"\\begin{array}", output:"X", ttype:13, invisible:true},
		{input:"\\\\", output:"}&{", ttype:8},
		{input:"\\end{eqnarray}", output:"}}", ttype:8},
		{input:"\\end{array}", output:"}}", ttype:8},
	//grouping and literal brackets -- ieval is for IE
		{input:"\\big", tag:"mo", output:"X", atval:"1.2", ieval:"2.2", ttype:10},
		{input:"\\Big", tag:"mo", output:"X", atval:"1.6", ieval:"2.6", ttype:10},
		{input:"\\bigg", tag:"mo", output:"X", atval:"2.2", ieval:"3.2", ttype:10},
		{input:"\\Bigg", tag:"mo", output:"X", atval:"2.9", ieval:"3.9", ttype:10},
		{input:"\\left", tag:"mo", output:"X", ttype:4},
		{input:"\\right", tag:"mo", output:"X", ttype:5},
		{input:"{", output:"{", ttype:4, invisible:true},
		{input:"}", output:"}", ttype:5, invisible:true},
		{input:"(", tag:"mo", output:"(", atval:"1", ttype:12},
		{input:"[", tag:"mo", output:"[", atval:"1", ttype:12},
		{input:"\\lbrack", tag:"mo", output:"[", atval:"1", ttype:12},
		{input:"\\{", tag:"mo", output:"{", atval:"1", ttype:12},
		{input:"\\lbrace", tag:"mo", output:"{", atval:"1", ttype:12},
		{input:"\\langle", tag:"mo", output:"\u2329", atval:"1", ttype:12},
		{input:"\\lfloor", tag:"mo", output:"\u230A", atval:"1", ttype:12},
		{input:"\\lceil", tag:"mo", output:"\u2308", atval:"1", ttype:12},
	// rtag:"mi" causes space to be inserted before a following sin, cos, etc.
	// (see function AMparseExpr() )
		{input:")", tag:"mo",output:")", rtag:"mi",atval:"1",ttype:12},
		{input:"]", tag:"mo",output:"]", rtag:"mi",atval:"1",ttype:12},
		{input:"\\rbrack",tag:"mo",output:"]", rtag:"mi",atval:"1",ttype:12},
		{input:"\\}", tag:"mo",output:"}", rtag:"mi",atval:"1",ttype:12},
		{input:"\\rbrace",tag:"mo",output:"}", rtag:"mi",atval:"1",ttype:12},
		{input:"\\rangle",tag:"mo",output:"\u232A", rtag:"mi",atval:"1",ttype:12},
		{input:"\\rfloor",tag:"mo",output:"\u230B", rtag:"mi",atval:"1",ttype:12},
		{input:"\\rceil", tag:"mo",output:"\u2309", rtag:"mi",atval:"1",ttype:12},
	// "|", "\\|", "\\vert" and "\\Vert" modified later: lspace = rspace = 0em
		{input:"|", tag:"mo", output:"\u2223", atval:"1", ttype:12},
		{input:"\\|", tag:"mo", output:"\u2225", atval:"1", ttype:12},
		{input:"\\vert", tag:"mo", output:"\u2223", atval:"1", ttype:12},
		{input:"\\Vert", tag:"mo", output:"\u2225", atval:"1", ttype:12},
		{input:"\\mid", tag:"mo", output:"\u2223", atval:"1", ttype:12},
		{input:"\\parallel", tag:"mo", output:"\u2225", atval:"1", ttype:12},
		{input:"/", tag:"mo", output:"/", atval:"1.01", ttype:12},
		{input:"\\backslash", tag:"mo", output:"\u2216", atval:"1", ttype:12},
		{input:"\\setminus", tag:"mo", output:"\\", ttype:0},
	//miscellaneous symbols
		{input:"\\!", tag:"mspace", atname:"width", atval:"-0.167em", ttype:6},
		{input:"\\,", tag:"mspace", atname:"width", atval:"0.167em", ttype:6},
		{input:"\\>", tag:"mspace", atname:"width", atval:"0.222em", ttype:6},
		{input:"\\:", tag:"mspace", atname:"width", atval:"0.222em", ttype:6},
		{input:"\\;", tag:"mspace", atname:"width", atval:"0.278em", ttype:6},
		{input:"~", tag:"mspace", atname:"width", atval:"0.333em", ttype:6},
		{input:"\\quad", tag:"mspace", atname:"width", atval:"1em", ttype:6},
		{input:"\\qquad", tag:"mspace", atname:"width", atval:"2em", ttype:6},
		{input:"\\prime", tag:"mo", output:"\u2032", ttype:0},
		{input:"'", tag:"mo", output:"\u02B9", ttype:0},
		{input:"''", tag:"mo", output:"\u02BA", ttype:0},
		{input:"'''", tag:"mo", output:"\u2034", ttype:0},
		{input:"''''", tag:"mo", output:"\u2057", ttype:0},
		{input:"\\ldots", tag:"mo", output:"\u2026", ttype:0},
		{input:"\\cdots", tag:"mo", output:"\u22EF", ttype:0},
		{input:"\\vdots", tag:"mo", output:"\u22EE", ttype:0},
		{input:"\\ddots", tag:"mo", output:"\u22F1", ttype:0},
		{input:"\\forall", tag:"mo", output:"\u2200", ttype:0},
		{input:"\\exists", tag:"mo", output:"\u2203", ttype:0},
		{input:"\\Re", tag:"mo", output:"\u211C", ttype:0},
		{input:"\\Im", tag:"mo", output:"\u2111", ttype:0},
		{input:"\\aleph", tag:"mo", output:"\u2135", ttype:0},
		{input:"\\hbar", tag:"mo", output:"\u210F", ttype:0},
		{input:"\\ell", tag:"mo", output:"\u2113", ttype:0},
		{input:"\\wp", tag:"mo", output:"\u2118", ttype:0},
		{input:"\\emptyset", tag:"mo", output:"\u2205", ttype:0},
		{input:"\\infty", tag:"mo", output:"\u221E", ttype:0},
		{input:"\\surd", tag:"mo", output:"\\sqrt{}", ttype:8},
		{input:"\\partial", tag:"mo", output:"\u2202", ttype:0},
		{input:"\\nabla", tag:"mo", output:"\u2207", ttype:0},
		{input:"\\triangle", tag:"mo", output:"\u25B3", ttype:0},
		{input:"\\therefore", tag:"mo", output:"\u2234", ttype:0},
		{input:"\\angle", tag:"mo", output:"\u2220", ttype:0},
		{input:"\\diamond", tag:"mo", output:"\u22C4", ttype:0},
		{input:"\\Diamond", tag:"mo", output:"\u25C7", ttype:0},
		{input:"\\neg", tag:"mo", output:"\u00AC", ttype:0},
		{input:"\\lnot", tag:"mo", output:"\u00AC", ttype:0},
		{input:"\\bot", tag:"mo", output:"\u22A5", ttype:0},
		{input:"\\top", tag:"mo", output:"\u22A4", ttype:0},
		{input:"\\square", tag:"mo", output:"\u25AB", ttype:0},
		{input:"\\Box", tag:"mo", output:"\u25A1", ttype:0},
		{input:"\\wr", tag:"mo", output:"\u2240", ttype:0},
	//standard functions
	//Note DEFINITION *must* have tag:"mo" to work properly
		{input:"\\arccos", tag:"mi", output:"arccos", ttype:1, func:true},
		{input:"\\arcsin", tag:"mi", output:"arcsin", ttype:1, func:true},
		{input:"\\arctan", tag:"mi", output:"arctan", ttype:1, func:true},
		{input:"\\arg", tag:"mi", output:"arg", ttype:1, func:true},
		{input:"\\cos", tag:"mi", output:"cos", ttype:1, func:true},
		{input:"\\cosh", tag:"mi", output:"cosh", ttype:1, func:true},
		{input:"\\cot", tag:"mi", output:"cot", ttype:1, func:true},
		{input:"\\coth", tag:"mi", output:"coth", ttype:1, func:true},
		{input:"\\csc", tag:"mi", output:"csc", ttype:1, func:true},
		{input:"\\deg", tag:"mi", output:"deg", ttype:1, func:true},
		{input:"\\det", tag:"mi", output:"det", ttype:1, func:true},
		{input:"\\dim", tag:"mi", output:"dim", ttype:1, func:true}, //0?
		{input:"\\exp", tag:"mi", output:"exp", ttype:1, func:true},
		{input:"\\gcd", tag:"mi", output:"gcd", ttype:1, func:true}, //0?
		{input:"\\hom", tag:"mi", output:"hom", ttype:1, func:true},
		{input:"\\inf", tag:"mo", output:"inf", ttype:7},
		{input:"\\ker", tag:"mi", output:"ker", ttype:1, func:true},
		{input:"\\lg", tag:"mi", output:"lg", ttype:1, func:true},
		{input:"\\lim", tag:"mo", output:"lim", ttype:7},
		{input:"\\liminf", tag:"mo", output:"liminf", ttype:7},
		{input:"\\limsup", tag:"mo", output:"limsup", ttype:7},
		{input:"\\ln", tag:"mi", output:"ln", ttype:1, func:true},
		{input:"\\log", tag:"mi", output:"log", ttype:1, func:true},
		{input:"\\max", tag:"mo", output:"max", ttype:7},
		{input:"\\min", tag:"mo", output:"min", ttype:7},
		{input:"\\Pr", tag:"mi", output:"Pr", ttype:1, func:true},
		{input:"\\sec", tag:"mi", output:"sec", ttype:1, func:true},
		{input:"\\sin", tag:"mi", output:"sin", ttype:1, func:true},
		{input:"\\sinh", tag:"mi", output:"sinh", ttype:1, func:true},
		{input:"\\sup", tag:"mo", output:"sup", ttype:7},
		{input:"\\tan", tag:"mi", output:"tan", ttype:1, func:true},
		{input:"\\tanh", tag:"mi", output:"tanh", ttype:1, func:true},
	//arrows
		{input:"\\gets", tag:"mo", output:"\u2190", ttype:0},
		{input:"\\leftarrow", tag:"mo", output:"\u2190", ttype:0},
		{input:"\\to", tag:"mo", output:"\u2192", ttype:0},
		{input:"\\rightarrow", tag:"mo", output:"\u2192", ttype:0},
		{input:"\\leftrightarrow", tag:"mo", output:"\u2194", ttype:0},
		{input:"\\uparrow", tag:"mo", output:"\u2191", ttype:0},
		{input:"\\downarrow", tag:"mo", output:"\u2193", ttype:0},
		{input:"\\updownarrow", tag:"mo", output:"\u2195", ttype:0},
		{input:"\\Leftarrow", tag:"mo", output:"\u21D0", ttype:0},
		{input:"\\Rightarrow", tag:"mo", output:"\u21D2", ttype:0},
		{input:"\\Leftrightarrow", tag:"mo", output:"\u21D4", ttype:0},
		{input:"\\iff", tag:"mo", output:"~\\Longleftrightarrow~", ttype:8},
		{input:"\\Uparrow", tag:"mo", output:"\u21D1", ttype:0},
		{input:"\\Downarrow", tag:"mo", output:"\u21D3", ttype:0},
		{input:"\\Updownarrow", tag:"mo", output:"\u21D5", ttype:0},
		{input:"\\mapsto", tag:"mo", output:"\u21A6", ttype:0},
		{input:"\\longleftarrow", tag:"mo", output:"\u2190", ttype:11},
		{input:"\\longrightarrow", tag:"mo", output:"\u2192", ttype:11},
		{input:"\\longleftrightarrow", tag:"mo", output:"\u2194", ttype:11},
		{input:"\\Longleftarrow", tag:"mo", output:"\u21D0", ttype:11},
		{input:"\\Longrightarrow", tag:"mo", output:"\u21D2", ttype:11},
		{input:"\\Longleftrightarrow", tag:"mo", output:"\u21D4", ttype:11},
		{input:"\\longmapsto", tag:"mo", output:"\u21A6", ttype:0}, // disaster if LONG
	//commands with argument
		{input:"\\sqrt", tag:"msqrt", output:"sqrt", ttype:1},
		{input:"\\root", tag:"mroot", output:"root", ttype:2},
		{input:"\\frac", tag:"mfrac", output:"/", ttype:2},
		{input:"\\stackrel", tag:"mover", output:"stackrel", ttype:2},
		{input:"\\atop", tag:"mfrac", output:"", ttype:3},
		{input:"\\choose", tag:"mfrac", output:"", ttype:3},
		{input:"_", tag:"msub", output:"_", ttype:3},
		{input:"^", tag:"msup", output:"^", ttype:3},
		{input:"\\mathrm", tag:"mtext", output:"text", ttype:9},
		{input:"\\mbox", tag:"mtext", output:"mbox", ttype:9},
	//diacritical marks
		{input:"\\acute", tag:"mover", output:"\u00B4", ttype:1, acc:true},
		{input:"\\grave", tag:"mover", output:"\u0060", ttype:1, acc:true},
		{input:"\\breve", tag:"mover", output:"\u02D8", ttype:1, acc:true},
		{input:"\\check", tag:"mover", output:"\u02C7", ttype:1, acc:true},
		{input:"\\dot", tag:"mover", output:".", ttype:1, acc:true},
		{input:"\\ddot", tag:"mover", output:"..", ttype:1, acc:true},
		{input:"\\mathring", tag:"mover", output:"\u00B0", ttype:1, acc:true},
		{input:"\\vec", tag:"mover", output:"\u20D7", ttype:1, acc:true},
		{input:"\\overrightarrow",tag:"mover",output:"\u20D7", ttype:1, acc:true},
		{input:"\\overleftarrow",tag:"mover", output:"\u20D6", ttype:1, acc:true},
		{input:"\\hat", tag:"mover", output:"\u005E", ttype:1, acc:true},
		{input:"\\widehat", tag:"mover", output:"\u0302", ttype:1, acc:true},
		{input:"\\tilde", tag:"mover", output:"~", ttype:1, acc:true},
		{input:"\\widetilde", tag:"mover", output:"\u02DC", ttype:1, acc:true},
		{input:"\\bar", tag:"mover", output:"\u203E", ttype:1, acc:true},
		{input:"\\overbrace", tag:"mover", output:"\u23B4", ttype:1, acc:true},
		{input:"\\overline", tag:"mover", output:"\u00AF", ttype:1, acc:true},
		{input:"\\underbrace", tag:"munder", output:"\u23B5", ttype:1, acc:true},
		{input:"\\underline", tag:"munder", output:"\u00AF", ttype:1, acc:true},
	//typestyles and fonts
		{input:"\\displaystyle",tag:"mstyle",atname:"displaystyle",atval:"true", ttype:1},
		{input:"\\textstyle",tag:"mstyle",atname:"displaystyle",atval:"false", ttype:1},
		{input:"\\scriptstyle",tag:"mstyle",atname:"scriptlevel",atval:"1", ttype:1},
		{input:"\\scriptscriptstyle",tag:"mstyle",atname:"scriptlevel",atval:"2", ttype:1},
		{input:"\\textrm", tag:"mstyle", output:"\\mathrm", ttype: 8},
		{input:"\\mathbf", tag:"mstyle", atname:"mathvariant", atval:"bold", ttype:1},
		{input:"\\textbf", tag:"mstyle", atname:"mathvariant", atval:"bold", ttype:1},
		{input:"\\mathit", tag:"mstyle", atname:"mathvariant", atval:"italic", ttype:1},
		{input:"\\textit", tag:"mstyle", atname:"mathvariant", atval:"italic", ttype:1},
		{input:"\\mathtt", tag:"mstyle", atname:"mathvariant", atval:"monospace", ttype:1},
		{input:"\\texttt", tag:"mstyle", atname:"mathvariant", atval:"monospace", ttype:1},
		{input:"\\mathsf", tag:"mstyle", atname:"mathvariant", atval:"sans-serif", ttype:1},
		{input:"\\mathbb", tag:"mstyle", atname:"mathvariant", atval:"double-struck", ttype:1, codes:this.AMbbb},
		{input:"\\mathcal",tag:"mstyle", atname:"mathvariant", atval:"script", ttype:1, codes:this.AMcal},
		{input:"\\mathfrak",tag:"mstyle",atname:"mathvariant", atval:"fraktur",ttype:1, codes:this.AMfrk}
	],
	AMcompareNames: function(s1,s2) {
			if (s1.input > s2.input) return 1
			else return -1;
	},
	init: function() {
		this.AMsymbols.sort(this.AMcompareNames);
		for (var i=0; i<this.AMsymbols.length; i++) this.AMnames[i] = this.AMsymbols[i].input;
	},
	AMcreateElementMathML: function(t) {
		if (this.isIE) return document.createElement("m:"+t);
		else return document.createElementNS(this.AMmathml,t);
	},
	AMcreateMmlNode: function(t,frag) {
		if (this.isIE) var node = document.createElement("m:"+t);
		else var node = document.createElementNS(this.AMmathml,t);
		node.appendChild(frag);
		return node;
	},
	newCommand: function(oldstr,newstr) {
		this.AMsymbols = this.AMsymbols.concat([{input:oldstr, tag:"mo", output:newstr, ttype:this.DEFINITION}]);
	},
	AMremoveCharsAndBlanks: function(str,n) {
		//remove n characters and any following blanks
		var st;
		st = str.slice(n);
		for (var i=0; i<st.length && st.charCodeAt(i)<=32; i=i+1);
		return st.slice(i);
	},
	AMposition: function(arr, str, n) {
		// return position >=n where str appears or would be inserted
		// assumes arr is sorted
		if (n==0) {
			var h,m;
			n = -1;
			h = arr.length;
			while (n+1<h) {
				m = (n+h) >> 1;
				if (arr[m]<str) n = m; else h = m;
			}
			return h;
		} else
			for (var i=n; i<arr.length && arr[i]<str; i++);
				return i; // i=arr.length || arr[i]>=str
	},
	AMgetSymbol: function(str) {
		//return maximal initial substring of str that appears in AMnames
		//return null if there is none
		var k = 0; //new pos
		var j = 0; //old pos
		var mk; //match pos
		var st;
		var tagst;
		var match = "";
		var more = true;
		for (var i=1; i<=str.length && more; i++) {
			st = str.slice(0,i); //initial substring of length i
			j = k;
			k = this.AMposition(this.AMnames, st, j);
			if (k<this.AMnames.length && str.slice(0,this.AMnames[k].length)==this.AMnames[k]){
				match = this.AMnames[k];
				mk = k;
				i = match.length;
			}
			more = k<this.AMnames.length && str.slice(0,this.AMnames[k].length)>=this.AMnames[k];
		}
		this.AMpreviousSymbol=this.AMcurrentSymbol;
		if (match!=""){
			this.AMcurrentSymbol=this.AMsymbols[mk].ttype;
			return this.AMsymbols[mk];
		}
		this.AMcurrentSymbol=this.CONST;
		k = 1;
		st = str.slice(0,1); //take 1 character
		if ("0"<=st && st<="9") tagst = "mn";
		else tagst = (("A">st || st>"Z") && ("a">st || st>"z")?"mo":"mi");
		return {input:st, tag:tagst, output:st, ttype:this.CONST};
	},
	AMpreviousSymbol: null,
	AMcurrentSymbol: null,
	AMparseSexpr: function(str) { //parses str and returns [node,tailstr,(node)tag]
		var symbol, node, result, result2, i, st,// rightvert = false,
		newFrag = document.createDocumentFragment();
		str = this.AMremoveCharsAndBlanks(str,0);
		symbol = this.AMgetSymbol(str); //either a token or a bracket or empty
		if (symbol == null || symbol.ttype == this.RIGHTBRACKET)
			return [null,str,null];
		if (symbol.ttype == this.DEFINITION) {
			str = symbol.output+this.AMremoveCharsAndBlanks(str,symbol.input.length);
			symbol = this.AMgetSymbol(str);
			if (symbol == null || symbol.ttype == this.RIGHTBRACKET)
				return [null,str,null];
		}
		str = this.AMremoveCharsAndBlanks(str,symbol.input.length);
		switch (symbol.ttype) {
		case this.SPACE:
			node = this.AMcreateElementMathML(symbol.tag);
			node.setAttribute(symbol.atname,symbol.atval);
			return [node,str,symbol.tag];
		case this.UNDEROVER:
			if (this.isIE) {
				if (symbol.input.substr(0,4) == "\\big") { // botch for missing symbols
					str = "\\"+symbol.input.substr(4)+str; // make \bigcup = \cup etc.
					symbol = this.AMgetSymbol(str);
					symbol.ttype = this.UNDEROVER;
					str = this.AMremoveCharsAndBlanks(str,symbol.input.length);
				}
			}
			return [this.AMcreateMmlNode(symbol.tag,document.createTextNode(symbol.output)),str,symbol.tag];
		case this.CONST:
			var output = symbol.output;
			if (this.isIE) {
				if (symbol.input == "'")
					output = "\u2032";
				else if (symbol.input == "''")
					output = "\u2033";
				else if (symbol.input == "'''")
					output = "\u2033\u2032";
				else if (symbol.input == "''''")
					output = "\u2033\u2033";
				else if (symbol.input == "\\square")
					output = "\u25A1"; // same as \Box
				else if (symbol.input.substr(0,5) == "\\frac") {
					// botch for missing fractions
					var denom = symbol.input.substr(6,1);
					if (denom == "5" || denom == "6") {
						str = symbol.input.replace(/\\frac/,"\\frac ")+str;
						return [node,str,symbol.tag];
					}
				}
			}
			node = this.AMcreateMmlNode(symbol.tag,document.createTextNode(output));
			return[node,str,symbol.tag];
		case this.LONG: // added by DRW
			node = this.AMcreateMmlNode(symbol.tag,document.createTextNode(symbol.output));
			node.setAttribute("minsize","1.5");
			node.setAttribute("maxsize","1.5");
			node = this.AMcreateMmlNode("mover",node);
			node.appendChild(this.AMcreateElementMathML("mspace"));
			return [node,str,symbol.tag];
		case this.STRETCHY: // added by DRW
			if (this.isIE && symbol.input == "\\backslash")
				symbol.output = "\\"; // doesn't expand, but then nor does "\u2216"
			node = this.AMcreateMmlNode(symbol.tag,document.createTextNode(symbol.output));
			if (symbol.input == "|" || symbol.input == "\\vert" || symbol.input == "\\|" || symbol.input == "\\Vert") {
				node.setAttribute("lspace","0em");
				node.setAttribute("rspace","0em");
			}
			node.setAttribute("maxsize",symbol.atval); // don't allow to stretch here
			if (symbol.rtag != null)
				return [node,str,symbol.rtag];
			else
				return [node,str,symbol.tag];
		case this.BIG: // added by DRW
			var atval = symbol.atval;
			if (this.isIE)
				atval = symbol.ieval;
			symbol = this.AMgetSymbol(str);
			if (symbol == null)
				return [null,str,null];
			str = this.AMremoveCharsAndBlanks(str,symbol.input.length);
			node = this.AMcreateMmlNode(symbol.tag,document.createTextNode(symbol.output));
			if (this.isIE) { // to get brackets to expand
				var space = this.AMcreateElementMathML("mspace");
				space.setAttribute("height",atval+"ex");
				node = this.AMcreateMmlNode("mrow",node);
				node.appendChild(space);
			} else { // ignored in IE
				node.setAttribute("minsize",atval);
				node.setAttribute("maxsize",atval);
			}
			return [node,str,symbol.tag];
		case this.LEFTBRACKET: //read (expr+)
			if (symbol.input == "\\left") { // left what?
				symbol = this.AMgetSymbol(str);
				if (symbol != null) {
					if (symbol.input == ".")
						symbol.invisible = true;
					str = this.AMremoveCharsAndBlanks(str,symbol.input.length);
				}
			}
			result = this.AMparseExpr(str,true,false);
			if (symbol==null || (typeof symbol.invisible == "boolean" && symbol.invisible))
				node = this.AMcreateMmlNode("mrow",result[0]);
			else {
				node = this.AMcreateMmlNode("mo",document.createTextNode(symbol.output));
				node = this.AMcreateMmlNode("mrow",node);
				node.appendChild(result[0]);
			}
			return [node,result[1],result[2]];
		case this.MATRIX: //read (expr+)
			if (symbol.input == "\\begin{array}") {
				var mask = "";
				symbol = this.AMgetSymbol(str);
				str = this.AMremoveCharsAndBlanks(str,0);
				if (symbol == null)
					mask = "l";
				else {
					str = this.AMremoveCharsAndBlanks(str,symbol.input.length);
					if (symbol.input != "{")
						mask = "l";
					else do {
						symbol = this.AMgetSymbol(str);
						if (symbol != null) {
							str = this.AMremoveCharsAndBlanks(str,symbol.input.length);
							if (symbol.input != "}")
								mask = mask+symbol.input;
						}
					} while (symbol != null && symbol.input != "" && symbol.input != "}");
				}
				result = this.AMparseExpr("{"+str,true,true);
				node = this.AMcreateMmlNode("mtable",result[0]);
				mask = mask.replace(/l/g,"left ");
				mask = mask.replace(/r/g,"right ");
				mask = mask.replace(/c/g,"center ");
				node.setAttribute("columnalign",mask);
				node.setAttribute("displaystyle","false");
				if (this.isIE)
					return [node,result[1],null];
				// trying to get a *little* bit of space around the array
				// (IE already includes it)
				var lspace = this.AMcreateElementMathML("mspace");
				lspace.setAttribute("width","0.167em");
				var rspace = this.AMcreateElementMathML("mspace");
				rspace.setAttribute("width","0.167em");
				var node1 = this.AMcreateMmlNode("mrow",lspace);
				node1.appendChild(node);
				node1.appendChild(rspace);
				return [node1,result[1],null];
			} else { // eqnarray
				result = this.AMparseExpr("{"+str,true,true);
				node = this.AMcreateMmlNode("mtable",result[0]);
				if (this.isIE)
					node.setAttribute("columnspacing","0.25em"); // best in practice?
				else
					node.setAttribute("columnspacing","0.167em"); // correct (but ignored?)
				node.setAttribute("columnalign","right center left");
				node.setAttribute("displaystyle","true");
				node = this.AMcreateMmlNode("mrow",node);
				return [node,result[1],null];
			}
		case this.TEXT:
			if (str.charAt(0)=="{") i=str.indexOf("}");
			else i = 0;
			if (i==-1) i = str.length;
			st = str.slice(1,i);
			if (st.charAt(0) == " ") {
				node = this.AMcreateElementMathML("mspace");
				node.setAttribute("width","0.33em"); // was 1ex
				newFrag.appendChild(node);
			}
			newFrag.appendChild(this.AMcreateMmlNode(symbol.tag,document.createTextNode(st)));
			if (st.charAt(st.length-1) == " ") {
				node = this.AMcreateElementMathML("mspace");
				node.setAttribute("width","0.33em"); // was 1ex
				newFrag.appendChild(node);
			}
			str = this.AMremoveCharsAndBlanks(str,i+1);
			return [this.AMcreateMmlNode("mrow",newFrag),str,null];
		case this.UNARY:
			result = this.AMparseSexpr(str);
			if (result[0]==null) return [this.AMcreateMmlNode(symbol.tag,document.createTextNode(symbol.output)),str];
			if (typeof symbol.func == "boolean" && symbol.func) { // functions hack
				st = str.charAt(0);
				if (st=="^" || st=="_" || st==",") {
					return [this.AMcreateMmlNode(symbol.tag,document.createTextNode(symbol.output)),str,symbol.tag];
				} else {
					node = this.AMcreateMmlNode("mrow",this.AMcreateMmlNode(symbol.tag,document.createTextNode(symbol.output)));
					if (this.isIE) {
						var space = this.AMcreateElementMathML("mspace");
						space.setAttribute("width","0.167em");
						node.appendChild(space);
					}
					node.appendChild(result[0]);
					return [node,result[1],symbol.tag];
				}
			}
			if (symbol.input == "\\sqrt") { // sqrt
				if (this.isIE) { // set minsize, for \surd
					var space = this.AMcreateElementMathML("mspace");
					space.setAttribute("height","1.2ex");
					space.setAttribute("width","0em"); // probably no effect
					node = this.AMcreateMmlNode(symbol.tag,result[0])
					node.appendChild(space);
					return [node,result[1],symbol.tag];
				} else
					return [this.AMcreateMmlNode(symbol.tag,result[0]),result[1],symbol.tag];
			} else if (typeof symbol.acc == "boolean" && symbol.acc) { // accent
				node = this.AMcreateMmlNode(symbol.tag,result[0]);
				var output = symbol.output;
				if (this.isIE) {
					if (symbol.input == "\\hat")
						output = "\u0302";
					else if (symbol.input == "\\widehat")
						output = "\u005E";
					else if (symbol.input == "\\bar")
						output = "\u00AF";
					else if (symbol.input == "\\grave")
						output = "\u0300";
					else if (symbol.input == "\\tilde")
						output = "\u0303";
				}
				var node1 = this.AMcreateMmlNode("mo",document.createTextNode(output));
				if (symbol.input == "\\vec" || symbol.input == "\\check") // don't allow to stretch
					node1.setAttribute("maxsize","1.2"); // why doesn't "1" work? \vec nearly disappears in firefox
				if (this.isIE && symbol.input == "\\bar")
					node1.setAttribute("maxsize","0.5");
				if (symbol.input == "\\underbrace" || symbol.input == "\\underline")
					node1.setAttribute("accentunder","true");
				else
					node1.setAttribute("accent","true");
				node.appendChild(node1);
				if (symbol.input == "\\overbrace" || symbol.input == "\\underbrace")
					node.ttype = UNDEROVER;
				return [node,result[1],symbol.tag];
			} else { // font change or displaystyle command
				if (!this.isIE && typeof symbol.codes != "undefined") {
					for (i=0; i<result[0].childNodes.length; i++)
						if (result[0].childNodes[i].nodeName=="mi" || result[0].nodeName=="mi") {
							st = (result[0].nodeName=="mi"?result[0].firstChild.nodeValue:result[0].childNodes[i].firstChild.nodeValue);
						var newst = [];
						for (var j=0; j<st.length; j++)
							if (st.charCodeAt(j)>64 && st.charCodeAt(j)<91) newst = newst + String.fromCharCode(symbol.codes[st.charCodeAt(j)-65]);
							else newst = newst + st.charAt(j);
						if (result[0].nodeName=="mi")
							result[0]=this.AMcreateElementMathML("mo").appendChild(document.createTextNode(newst));
						else result[0].replaceChild(this.AMcreateElementMathML("mo").appendChild(document.createTextNode(newst)),result[0].childNodes[i]);
					}
				}
				node = this.AMcreateMmlNode(symbol.tag,result[0]);
				node.setAttribute(symbol.atname,symbol.atval);
				if (symbol.input == "\\scriptstyle" || symbol.input == "\\scriptscriptstyle")
					node.setAttribute("displaystyle","false");
				return [node,result[1],symbol.tag];
			}
		case this.BINARY:
			result = this.AMparseSexpr(str);
			if (result[0]==null) return [this.AMcreateMmlNode("mo",document.createTextNode(symbol.input)),str,null];
			result2 = this.AMparseSexpr(result[1]);
			if (result2[0]==null) return [this.AMcreateMmlNode("mo",document.createTextNode(symbol.input)),str,null];
			if (symbol.input=="\\root" || symbol.input=="\\stackrel")
				newFrag.appendChild(result2[0]);
			newFrag.appendChild(result[0]);
			if (symbol.input=="\\frac") newFrag.appendChild(result2[0]);
			return [this.AMcreateMmlNode(symbol.tag,newFrag),result2[1],symbol.tag];
		case this.INFIX:
			str = this.AMremoveCharsAndBlanks(str,symbol.input.length);
			return [this.AMcreateMmlNode("mo",document.createTextNode(symbol.output)),str,symbol.tag];
		default:
			return [this.AMcreateMmlNode(symbol.tag,document.createTextNode(symbol.output)),str,symbol.tag];
		}
 	},
	AMparseIexpr: function(str) {
		var symbol, sym1, sym2, node, result, tag, underover;
		str = this.AMremoveCharsAndBlanks(str,0);
		sym1 = this.AMgetSymbol(str);
		result = this.AMparseSexpr(str);
		node = result[0];
		str = result[1];
		tag = result[2];
		symbol = this.AMgetSymbol(str);
		if (symbol.ttype == this.INFIX) {
			str = this.AMremoveCharsAndBlanks(str,symbol.input.length);
			result = this.AMparseSexpr(str);
			if (result[0] == null) // show box in place of missing argument
				result[0] = this.AMcreateMmlNode("mo",document.createTextNode("\u25A1"));
			str = result[1];
			tag = result[2];
			if (symbol.input == "_" || symbol.input == "^") {
				sym2 = this.AMgetSymbol(str);
				tag = null; // no space between x^2 and a following sin, cos, etc.
				// This is for \underbrace and \overbrace
				underover = ((sym1.ttype == this.UNDEROVER) || (node.ttype == this.UNDEROVER));
				if (symbol.input == "_" && sym2.input == "^") {
					str = this.AMremoveCharsAndBlanks(str,sym2.input.length);
					var res2 = this.AMparseSexpr(str);
					str = res2[1];
					tag = res2[2]; // leave space between x_1^2 and a following sin etc.
					node = this.AMcreateMmlNode((underover?"munderover":"msubsup"),node);
					node.appendChild(result[0]);
					node.appendChild(res2[0]);
				} else if (symbol.input == "_") {
					node = this.AMcreateMmlNode((underover?"munder":"msub"),node);
					node.appendChild(result[0]);
				} else {
					node = this.AMcreateMmlNode((underover?"mover":"msup"),node);
					node.appendChild(result[0]);
				}
				node = this.AMcreateMmlNode("mrow",node); // so sum does not stretch
			} else {
				node = this.AMcreateMmlNode(symbol.tag,node);
				if (symbol.input == "\\atop" || symbol.input == "\\choose")
					node.setAttribute("linethickness","0ex");
				node.appendChild(result[0]);
				if (symbol.input == "\\choose")
					node = this.AMcreateMmlNode("mfenced",node);
			}
		}
		 return [node,str,tag];
	},
	AMparseExpr: function(str,rightbracket,matrix) {
 		var symbol, node, result, i, tag,
		newFrag = document.createDocumentFragment();
		do {
			str = this.AMremoveCharsAndBlanks(str,0);
			result = this.AMparseIexpr(str);
			node = result[0];
			str = result[1];
			tag = result[2];
			symbol = this.AMgetSymbol(str);
			if (node!=undefined) {
				if ((tag == "mn" || tag == "mi") && symbol!=null && typeof symbol.func == "boolean" && symbol.func) {
					// Add space before \sin in 2\sin x or x\sin x
					var space = this.AMcreateElementMathML("mspace");
					space.setAttribute("width","0.167em");
					node = this.AMcreateMmlNode("mrow",node);
					node.appendChild(space);
				}
				newFrag.appendChild(node);
			}
		} while ((symbol.ttype != this.RIGHTBRACKET) && symbol!=null && symbol.output!="");
		tag = null;
		if (symbol.ttype == this.RIGHTBRACKET) {
			if (symbol.input == "\\right") { // right what?
				str = this.AMremoveCharsAndBlanks(str,symbol.input.length);
				symbol = this.AMgetSymbol(str);
				if (symbol != null && symbol.input == ".")
					symbol.invisible = true;
				if (symbol != null)
					tag = symbol.rtag;
			}
			if (symbol!=null)
				str = this.AMremoveCharsAndBlanks(str,symbol.input.length); // ready to return
			var len = newFrag.childNodes.length;
			if (matrix && len>0 && newFrag.childNodes[len-1].nodeName == "mrow" && len>1 && newFrag.childNodes[len-2].nodeName == "mo" && newFrag.childNodes[len-2].firstChild.nodeValue == "&") { //matrix
				var pos = []; // positions of ampersands
				var m = newFrag.childNodes.length;
				for (i=0; matrix && i<m; i=i+2) {
					pos[i] = [];
					node = newFrag.childNodes[i];
					for (var j=0; j<node.childNodes.length; j++)
						if (node.childNodes[j].firstChild.nodeValue=="&") pos[i][pos[i].length]=j;
				}
				var row, frag, n, k, table = document.createDocumentFragment();
				for (i=0; i<m; i=i+2) {
					row = document.createDocumentFragment();
					frag = document.createDocumentFragment();
					node = newFrag.firstChild; // <mrow> -&-&...&-&- </mrow>
					n = node.childNodes.length;
					k = 0;
					for (j=0; j<n; j++) {
						if (typeof pos[i][k] != "undefined" && j==pos[i][k]){
							node.removeChild(node.firstChild); //remove &
							row.appendChild(this.AMcreateMmlNode("mtd",frag));
							k++;
						} else frag.appendChild(node.firstChild);
					}
					row.appendChild(this.AMcreateMmlNode("mtd",frag));
					if (newFrag.childNodes.length>2) {
						newFrag.removeChild(newFrag.firstChild); //remove <mrow> </mrow>
						newFrag.removeChild(newFrag.firstChild); //remove <mo>&</mo>
					}
					table.appendChild(this.AMcreateMmlNode("mtr",row));
				}
				return [table,str];
			}
			if (typeof symbol.invisible != "boolean" || !symbol.invisible) {
				node = this.AMcreateMmlNode("mo",document.createTextNode(symbol.output));
				newFrag.appendChild(node);
			}
		}
		return [newFrag,str,tag];
	},
	AMparseMath: function(str) {
		var result, node = this.AMcreateElementMathML("mstyle");
		node.appendChild(this.AMparseExpr(str.replace(/^\s+/g,""),false,false)[0]);
		node = this.AMcreateMmlNode("math",node);
		return node;
	},
	AMstrarr2docFrag: function(arr) {
		var newFrag=document.createDocumentFragment();
		newFrag.appendChild(this.AMparseMath(arr));
		return newFrag;
	}
};

config.macros.LaTeXMathMLPlugin.init();

config.formatters.push({
	name: "eqmath0",
	match: "\\$\\$",
	lookaheadRegExp: /\$\$((?:.|\n)*?)\$\$/mg,
	handler: function(w){
		this.lookaheadRegExp.lastIndex = w.matchStart;
		var lookaheadMatch = this.lookaheadRegExp.exec(w.source);
		if(lookaheadMatch){
			var eq = createTiddlyElement(w.output,"div");
			eq.style.textAlign='center';
			eq.appendChild(config.macros.LaTeXMathMLPlugin.AMstrarr2docFrag("\\displaystyle\{"+lookaheadMatch[1]+"\}"));
			w.nextMatch = lookaheadMatch.index + lookaheadMatch[0].length;
		}
	}
});

config.formatters.push({
	name: "eqmath1",
	match: "\\$",
	lookaheadRegExp: /\$((?:.|\n)*?)\$/mg,
	handler: function(w){
		this.lookaheadRegExp.lastIndex = w.matchStart;
		var lookaheadMatch = this.lookaheadRegExp.exec(w.source);
		if(lookaheadMatch){
			var eq = createTiddlyElement(w.output,"span");
			eq.appendChild(config.macros.LaTeXMathMLPlugin.AMstrarr2docFrag(lookaheadMatch[1]));
			w.nextMatch = lookaheadMatch.index + lookaheadMatch[0].length;
		}
	}
});

config.shadowTiddlers.LaTeXMathMLPluginDoc="The documentation is available [[here.|http://www.math.ist.utl.pt/~psoares/addons.html#LaTeXMathMLPluginDoc]]";
//}}}
//{{{
with(config.macros.LaTeXMathMLPlugin){
	newCommand("\\nle","\u2270");
	newCommand("\\R","\u211D");
	init();
}
//}}}
!Description
This plugin is a modification of  a set of ~JavaScript functions to convert ~LaTeX math notation to Presentation ~MathML written by Douglas Woodall. The original notice can be found at the end of this text. The most important changes were:
#the substitution mechanism of ~LaTeX snippets (enclosed by {{{$...$}}} or {{{$$...$$}}}) was replaced by a couple of ~TiddlyWiki formatters
#centered equations (enclosed by {{{$$...$$}}}) are properly handled
#~MathML output can be decorated by CSS rules such as
{{{
math {
 font-family: sans-serif,arial;
 color: red;
}
}}}
!Installation
To use this plugin with Internet Explorer (IE) it is needed the [[MathPlayer|http://www.dessci.com/en/products/mathplayer/]] plugin for IE and the following lines should be added to the MarkupPreHead tiddler:
{{{
<html xmlns:m="http://www.w3.org/1998/Math/MathML">
<object id="mathplayer" classid="clsid:32F66A20-7614-11D4-BD11-00104BD3F987"></object>
<?import namespace="m" implementation="#mathplayer"?>
}}}
!Adding new symbols
The standard symbol table can be extended by adding additional symbols. This is done by adding a few lines of ~JavaScript code as in [[here|LaTeXMathMLPluginComp]].
You first have to find the four-digit hexadecimal Unicode value for these symbols by looking them up at, say, [[here|http://www.w3.org/TR/MathML2/chapter6.html#chars.entity.tables]].
!Credits
A final word of appreciation for the work of Douglas Woodall and Peter Jipsen on promoting the presentation of beautiful math in the web.
!Revision history
*1.1 06/10/2007
**Complete refactoring of the code. No more global variables!
*1.0.1 15/09/2007
**Included missing function 'newcommand' that allows the extension of the set of symbols available
*1.0.0 12/09/2007
**Initial release 
!Original notice
{{{
LaTeXMathML.js
==============

This file, in this form, is due to Douglas Woodall, June 2006.
It contains JavaScript functions to convert (most simple) LaTeX
math notation to Presentation MathML.  It was obtained by
downloading the file ASCIIMathML.js from
	http://www1.chapman.edu/~jipsen/mathml/asciimathdownload/
and modifying it so that it carries out ONLY those conversions
that would be carried out in LaTeX.  A description of the original
file, with examples, can be found at
	www1.chapman.edu/~jipsen/mathml/asciimath.html
	ASCIIMathML: Math on the web for everyone

Here is the header notice from the original file:

ASCIIMathML.js
==============
This file contains JavaScript functions to convert ASCII math notation
to Presentation MathML. The conversion is done while the (X)HTML page
loads, and should work with Firefox/Mozilla/Netscape 7+ and Internet
Explorer 6+MathPlayer (http://www.dessci.com/en/products/mathplayer/).
Just add the next line to your (X)HTML page with this file in the same folder:
<script type="text/javascript" src="ASCIIMathML.js"></script>
This is a convenient and inexpensive solution for authoring MathML.

Version 1.4.7 Dec 15, 2005, (c) Peter Jipsen http://www.chapman.edu/~jipsen
Latest version at http://www.chapman.edu/~jipsen/mathml/ASCIIMathML.js
For changes see http://www.chapman.edu/~jipsen/mathml/asciimathchanges.txt
If you use it on a webpage, please send the URL to jipsen@chapman.edu

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or (at
your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License (at http://www.gnu.org/copyleft/gpl.html)
for more details.
}}}
*Tuesday, January 15
**[[Integration by Substitution Lab Answers (mws)|labs/Lab - Integration by Substitution Answers.mws]]
The University Learning Center, located on the first floor of Westside Hall, provides tutoring for basic studies mathematics and statistics courses.  Math Services also provides course-specific review and problem sessions, and help with math study skills and math anxiety.

No appointment is needed during open lab hours.

Web: [[www.uncw.edu/stuaff/uls|http://www.uncw.edu/stuaff/uls]]
Phone: 962-7857
Email: ULC@uncw.edu
/%
Please note that the following lecture outlines from Fall 2006 are under revision.  Topics covered in Fall 2007 may differ.

*[[Overview (pdf)|lectures/mat346lecture0.pdf]]
*[[Problem Studies (pdf)|lectures/mat346lecture2.pdf]]
*[[Egypt and Mesopotamia (pdf)|lectures/mat346lecture3.pdf]]
*[[Greek Mathematics to the Time of Euclid (pdf)|lectures/mat346lecture4.pdf]]
*[[Euclid and his Elements (pdf)|lectures/mat346lecture4b.pdf]]
*[[Greek Mathematics from Archimedes to Ptolemy (pdf)|lectures/mat346lecture6.pdf]]
*[[Greek Mathematics from Diophantus to Hypatia (pdf)|lectures/mat346lecture7.pdf]]
*[[Ancient and Medieval China (pdf)|lectures/mat346lecture8.pdf]]
*[[Ancient and Medieval India (pdf)|lectures/mat346lecture9b.pdf]]
*[[Mathematics in Medieval Europe (pdf)|lectures/mat346lecture10.pdf]]
*[[Mathematics in the Renaissance 1 (pdf)|lectures/mat346lecture11.pdf]]
*[[Mathematics in the Renaissance 2 (pdf)|lectures/mat346lecture12.pdf]]
*[[Calculus in the Seventeenth Century (pdf)|lectures/mat346lecture14.pdf]]
*[[Algebra and Number Theory in the Eighteenth Century (pdf)|lectures/mat346lecture16.pdf]]
*[[Geometry in the Eighteenth Century (pdf)|lectures/mat346lecture17.pdf]]
*[[Algebra and Number Theory in the Nineteenth Century 1 (pdf)|lectures/mat346lecture18.pdf]]
*[[Algebra and Number Theory in the Nineteenth Century 2 (pdf)|lectures/mat346lecture19.pdf]]
*[[Analysis in the Nineteenth Century 1 (pdf)|lectures/mat346lecture21.pdf]]
*[[Analysis in the Nineteenth Century 2 (pdf)|lectures/mat346lecture22.pdf]]
%/
Fonts can be found [[here|http://web.mit.edu/ist/topics/webpublishing/mathml/index.html]].
[[Schedule]]
[[Notable Dates]]
[[Homework]]
[[Tests]]
[[Course Policies]]
[[Contact Information]]
[[Resources]]
<<toggleSideBar '' '' hide>>

/%
^^TiddlyWiki <<version>>
© 2007 [[UnaMesa|http://www.unamesa.org/]]^^
[[Learning Center]]
[[Lecture Notes]]
%/
<!--{{{-->
<link rel='alternate' type='application/rss+xml' title='RSS' href='index.xml'/>
<script type="text/javascript" src="TWASCIIsvg.js"></script>
<!--}}}-->
A famous result due to [[Euler|http://www-groups.dcs.st-and.ac.uk/~history/Mathematicians/Euler.html]] in ~LaTeX: $\sum_{n=1}^{+\infty}{\frac1{n^2}=\frac{\pi^2}6$

and again using {{{displaystyle}}}: $\displaystyle{\sum_{n=1}^{+\infty} \frac{1}{n^2}=\frac{\pi^2}{6}}$

and finally as a centered equation $$\sum_{n=1}^{+\infty} \frac{1}{n^2}=\frac{\pi^2}{6}.$$
Here is a graph of $x-\frac{x^3}{6}$ and $\sin(x)$ (double click on this tiddler to see the <embed> tag that produced it).
<html>
<center>
<embed id="graph"; src="d.svg";
script='width=300; height=150;
xmin=-2pi; xmax=2pi; xscl=1; axes(); stroke="red"
plot(sin(x))
stroke="blue"; strokedasharray="10,10"
plot(x-x^3/6,-4,4)'>
</center>
</html>
and a diagram illustrating why Pythagoras' Theorem holds:
<html>
<center>
<embed id="pythagoras"; src="d.svg";
script='width=400; height=170;
xmin=-4; xmax=4; xscl=1; ymin=1; noAxes(); noButton();
fill="yellow"
rect([1,1],[4,4])
rect([-4,1],[-1,4])
fill="red"
rect([-2,1],[-1,2])
fill="blue"
rect([-4,2],[-2,4])
fill="green"
path([[1,2],[2,4],[4,3],[3,1],[1,2]])
fill="none"
path([[-4,1],[-2,2],[-1,4]])'>
</center>
</html>
/***
!!!<<gradient horiz #fc3 #fff>>&nbsp;MemorizablePlugin^^<<tiddler CloseThisOpen with: ThirdPartyPlugins  '« back'>>|<<toolbar editTiddler>>» ^^>>
|Name|MemorizablePlugin|
|Source|URL: http://memorizable.com|
|Version|1.0.0|
|Author|Craig D. Muth Copyright (c) 2007|
|For use in TiddlyWiki see|http://tinyurl.com/34fjk6|
***/
//{{{
// License
//
// Note: This is a modified version of the X11 (aka MIT) open source
// license.  It lets you use, modify, distribute and sell, etc.,
// requiring only that you leave the "Help" and "About Memorizable
// Tables" links (under "Options") in tact.  If you desire to use the
// software without these links please contact the author.
//
// COPYRIGHT AND PERMISSION NOTICE for Memorizable Tables
//
// Copyright (c) 2007, Craig D. Muth, memorizable.com
// Author's Website URL: http://memorizable.com
//
// All rights reserved.
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use, copy,
// modify, merge, publish, distribute, and/or sell copies of the
// Software, and to permit persons to whom the Software is furnished
// to do so, subject to the following conditions:
//
// The above copyright notice, Author's Website URL, and this
// permission notice shall be included in all copies or substantial
// portions of the Software, and any hyperlinks in the user interface
// in the Software which refer to any page on the Author's Website may
// not be removed, disabled, altered, obscured, or repositioned.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE
// COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR
// ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY
// DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
// WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
// ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
// OF THIS SOFTWARE.
//
// Except as contained in this notice, the name of a copyright holder
// shall not be used in advertising or otherwise to promote the sale,
// use or other dealings in this Software without prior written
// authorization of the copyright holder.
//

Mem = new Object();

Mem.blankRowCount = 9;
Mem.mGray = "#d8d4c0";
Mem.mGreen = "#fff";
Mem.mClicked = "#b8b4a0";

Mem.myCellIndex = function(th) {
 var cells = th.parentNode.cells;
 var inn = 0;
 for(var x=0; x<cells.length; x++) {
  if(cells.item(x) == th)
   inn = x;
 }
 return inn;
}
Mem.start = function( item ) {
 var columnClicked;

 item.parentNode.parentNode.parentNode.parentNode.isMem = true;
 var t = this.setT( item );

 columnClicked = Mem.myCellIndex(item.parentNode);

 // If already in progress
 if( t.s && t.s.tbodyBackup ) {
  // Kill blinking processes
  this.tChile('directionsDiv').cycles = 1;
  Mem.restore();
 }

 // Create new if necessary
 if( typeof( t.s ) != 'object')
  t.s = new Array();

 t.s.column = columnClicked;

 // Create backup
 var bak = t.tBodies[0].cloneNode( true );
 t.s.tbodyBackup = bak;

 // Init correct count
 t.s.correctCount = 0;

 t.s.pending = new Array();

 var initialLength = t.tBodies[0].rows.length;
 for(var x=1; x<initialLength; x++) {
  // Build up list of indexes
  t.s.pending[t.s.pending.length] = t.tBodies[0].rows[1];
  // Remove from table
  t.tBodies[0].removeChild( t.tBodies[0].rows[1] );
 }

 t.s.totalQuestions = t.s.pending.length;

 var tds = t.s.pending[0].getElementsByTagName("TD");
 var numberOfColumns=tds.length;

 // Add blank rows to end
 for(var x=1; x<t.s.pending.length; x++) {
  if( x <= this.blankRowCount ) {
   var tr = document.createElement("TR");

   // For each column
   for(var y=0; y<numberOfColumns; y++) {
     var td = document.createElement("TD");  td.innerHTML = "&nbsp;";
     tr.appendChild( td );
   }
   t.tBodies[0].appendChild( tr );
  }
 }

 // If hidden blank rows
 if( t.s.pending.length > this.blankRowCount + 1 ) {

   // Add ... row
   var tr = document.createElement("TR");
   var td = document.createElement("TD");
   //   td.innerHTML = ". &nbsp; . &nbsp; .";
   td.innerHTML = "<div style='text-align: center; font-weight: bold; font-size: 6px; font-family: arial black; margin-top: 2px;'>. &nbsp; &nbsp; . &nbsp; &nbsp; .</div>";
   var colspan = document.createAttribute("COLSPAN");
   colspan.nodeValue=numberOfColumns;
   td.setAttributeNode(colspan);
   tr.appendChild( td );
   //numberOfColumns
   t.tBodies[0].appendChild( tr );

 }

 this.shuffle( t.s.pending ); t.s.pending.reverse(); this.shuffle( t.s.pending );

 // Add buttons, etc. to end of table.
 var tr = document.createElement("TR");
 var statusTd = document.createElement("TD");
 statusTd.id = 'statusTd';
 tr.appendChild( statusTd );
 var colspan = document.createAttribute("COLSPAN");
 colspan.nodeValue=numberOfColumns;
 statusTd.setAttributeNode(colspan);
 t.tBodies[0].appendChild( tr );


 // Create placeholders for buttons, etc.
 statusTd.innerHTML = "\
  <div id=mode style='text-align:right; height:19px; font-size:10px; color:#666;'>" + Mem.getModeDiv(0) + "</div>\
  <div id=directionsDiv style='margin-bottom:4px; text-align: left; font-size:10px; font-family:verdana,arial,sans-serif; color:#666;'></div>\
  <div id=buttons style='float:left; height:21px;'></div>\
  <div id=options style='padding: 5px 0px 0px 8px; width:55px; margin-top:0px; float:right;'><a href='#' onclick='return Mem.showOptions(this);' id=optionsLink>Options</a></div>\
  <div id=progress style='margin-top:6px; float:right; font-size:8px; font-family:impact; color:#aaa; text-align:right; vertical-align:middle; '></div>\
" + this.getOptions();

 // Enable options if enabled before
 if( t.s.optionsOn )
  this.showOptions( statusTd );

 this.presentQuestion();

 this.glow(100);
 t.s.mode = "flashcard";

 return false;
}

Mem.addEvent = function( obj, type, fn ) {
 if ( obj.attachEvent ) {
  obj['e'+type+fn] = fn;
  obj[type+fn] = function() {obj['e'+type+fn]( window.event );}
  obj.attachEvent( 'on'+type, obj[type+fn] );
 } else
  obj.addEventListener( type, fn, false );
}

Mem.getQuestionCell = function() {
 return Mem.t.s.pending[0].cells[ Mem.t.s.column ];
}

Mem.createProgressBar = function() {
 var progress = "";
 var progressDups = "";
 var foundAlready = new Array();
 for(var x=0; x<Mem.t.s.pending.length ;x++) {

  // If found already
  if( foundAlready[ Mem.t.s.pending[x].innerHTML ] )
   progressDups += "|";
  else
   progress += "|";

  // Remember we found this one
  foundAlready[ Mem.t.s.pending[x].innerHTML ] = true;
 }
 return progress + "<span style='color:#f00;'>" + progressDups + "</span>";
}


Mem.presentQuestion = function() {

 this.tChile('directionsDiv').innerHTML = 
  "<div style='text-align:center;'>Guess the answer <b style='color:#4d0'>in your head</b>.<span style='font-size:7px;'></span> Then click <b>show answer</b>, or type <b>1</b>.</div>";
 this.tChile('buttons').innerHTML = "<button id=showAnswer style='margin-right:111px; width:11em; margin-bottom:1px; font-family: verdana,arial,sans-serif; font-size:9px;' onclick='Mem.showAnswer( this )' >show answer &nbsp;<span style='color:#aaa;text-decoration:underline;'>1</span></button>";

 var iveGuessed = this.tChile('showAnswer');
 Mem.addEvent( iveGuessed, 'mouseover', function(){ if(typeof( iveGuessedOnMouseOver ) =='function') iveGuessedOnMouseOver() } );
 Mem.addEvent( iveGuessed, 'mouseout', function(){ if(typeof( iveGuessedOnMouseOver ) =='function') iveGuessedOnMouseOut() } );

 // Add pending row
 Mem.t.tBodies[0].insertBefore( Mem.t.s.pending[0], Mem.t.tBodies[0].rows[ Mem.t.s.correctCount + 1 ] );

 // Insert "guess the answer", remembering old value
 var questionCell = this.getQuestionCell();
 Mem.t.s.questionCellOld = questionCell.innerHTML;
 questionCell.innerHTML = "<span style='text-decoration:none; color:#4d0; font-weight:bold; cursor:pointer;' title=\"Guess the answer in your head.  Then, click the 'show answer' button.\">what&nbsp;goes&nbsp;here?</span>";

 // Help alert
 Mem.addEvent( questionCell.getElementsByTagName("SPAN")[0], 'mousedown', function(){ alert('Guess the answer in your head.  Then, click the \'show answer\' button at the bottom of the table.') } );

 this.tChile('progress').innerHTML = this.createProgressBar();
}

Mem.showAnswer = function( button, noScroll ) {
 var t = this.setT( button );

 // Exit if other mode
 if( t.s.mode != "flashcard" )
  return;

 // Exit if no answer to show
 if( t.s.questionCellOld == null )
  return;

 var questionCell = this.getQuestionCell();
 questionCell.innerHTML = t.s.questionCellOld;
 t.s.questionCellOld = null;

 // Default
 var iWasRightText = "I was right";

 // Count how many of this remaining
 var timesFound = 0;
 for(var x=0; x<t.s.pending.length ;x++)
  if( t.s.pending[x].innerHTML == t.s.pending[0].innerHTML )
   timesFound++;

 // If not the last time
 if( timesFound > 1 )
  iWasRightText = "show later";

 this.tChile('directionsDiv').innerHTML = 
  "<div style='text-align:center;'>Press the appropriate button based on your guess, or type <b>1</b> or <b>2</b>.</div>";
 this.tChile('buttons').innerHTML = "\
<button id=iWasWrong style='width:11em; padding:0px; margin: 0px 12px 1px 0px; font-family: verdana,arial,sans-serif; font-size:9px;' onclick='Mem.answer( false, this )'>I was wrong &nbsp;<span style='color:#aaa;text-decoration:underline;'>1</span></button>\
<button id=iWasRight class='iWasRightButton' style='width:10em; margin-bottom:1px; font-family: verdana,arial,sans-serif; font-size:9px;' onclick='Mem.answer( true, this )' >" + iWasRightText + " &nbsp;<span style='color:#aaa;text-decoration:underline;'>2</span></button>\
";
 this.tChile('progress').innerHTML = this.createProgressBar();

 var iWasRight = this.tChile('iWasRight');
 var iWasWrong = this.tChile('iWasWrong');
 Mem.addEvent( iWasRight, 'mouseover', function(){ if(typeof( iWasRightOnMouseOver ) =='function') iWasRightOnMouseOver() } );
 Mem.addEvent( iWasRight, 'mouseout', function(){ if(typeof( iWasRightOnMouseOut ) =='function') iWasRightOnMouseOut() } );
 Mem.addEvent( iWasWrong, 'mouseover', function(){ if(typeof( iWasWrongOnMouseOver ) =='function') iWasWrongOnMouseOver() } );
 Mem.addEvent( iWasWrong, 'mouseout', function(){ if(typeof( iWasWrongOnMouseOut ) =='function') iWasWrongOnMouseOut() } );

 if(! noScroll)
  this.scrollDownIfNecessary( this.tChile('statusTd') );

}

Mem.answer = function( correct, button, noScroll ) {

 var t = this.setT( button );

 // If answer not shown
 if( t.s.questionCellOld != null )
  return;

 // If other mode
 if( t.s.mode != "flashcard" )
  return;

 var dup = this.currentIsDuplicate();
 var last = t.s.pending[0];

 // Remove from front of pending
 t.s.pending.splice( 0, 1 );

 var allRows = t.tBodies[0].rows;

 if( correct ) {
  // If elsewhere in pending, remove from table
  if( dup )
   t.tBodies[0].removeChild( last );

  // If pending is empty, they're finished
  if( t.s.pending.length == 0 ) {
   this.finished();
   return;
  }

  // If not dup, increase count of correct
  if( ! dup ) {
   t.s.correctCount++;

   // If enough rows in table, remove last one (blank or ...)
   if( t.s.correctCount + this.blankRowCount >= t.s.totalQuestions - 1 )
    t.tBodies[0].removeChild( allRows[allRows.length - 2] );
  }
 }
 // If they missed it
 else {

  // Remove from table
  t.tBodies[0].removeChild( last );
  t.s.pending.push( last );
  t.s.pending.splice( 2, 0, last );
 }

 this.presentQuestion();

 if(this.tChile('directionsDiv').cycles >= 3)
  this.tChile('directionsDiv').cycles = 2;

 if(! noScroll)
  this.scrollDownIfNecessary( this.tChile('statusTd') );
}

Mem.currentIsDuplicate = function() {
 for(var x=1; x<Mem.t.s.pending.length ;x++) {
  if( Mem.t.s.pending[x] == Mem.t.s.pending[0] )
   return true;
 }
 return false;
}

Mem.message = function( s ) {
 var d = document.createElement('div');
 var t = document.createTextNode( s );
 d.appendChild(t);
 document.body.appendChild(d);
}

Mem.shuffle = function( list ) {
  var holder, swaps, i, j;
  for (swaps=0; swaps<(list.length*2); swaps++) {
    i = Math.floor(Math.random()*list.length);
    j = Math.floor(Math.random()*list.length);
    holder = list[i];
    list[i] = list[j];
    list[j]=holder;
  }
  return list;
}

Mem.dump = function( o ) {
 var s = "";
 for(m in o)
  s += m + ", ";
 return s;
}

Mem.keyWasPressed = function( keyp ) {

 var pressed;
 if( navigator.appName == "Netscape" ) pressed = keyp.which;
 if( navigator.appVersion.indexOf("MSIE") != -1 ) pressed = event.keyCode;

 // In case no table in progress
 try {
  // Show answer
  if ( ( pressed == "1".charCodeAt(0) ) || ( pressed == 97 ) ) {
   // If answer not shown yet
   if( Mem.t.s.questionCellOld != null )
    Mem.showAnswer();
   else
    Mem.answer( false );
  }

  // TODO make sure there are no modifiers held down (because of ctrl-r)
  // I was right
  if ( ( pressed == "2".charCodeAt(0) ) || ( pressed == 98 ) )
   Mem.answer( true );

 } catch(e) {}
}

Mem.memorizeAllTables = function( item, onlyDoTheseTables ) {

 // If we are a "hide" link
 if( item.innerHTML == "close" ) {
  item.innerHTML = item.innerHTML_old;

  var removeThis = item.parentNode.getElementsByTagName("DIV")[0];
  // Close and exit
  item.parentNode.removeChild( removeThis );
  return false;
 }

 // Change link to 'close'
 item.innerHTML_old = item.innerHTML;
 item.innerHTML = "close";

 // Create table in new div
 var d = document.createElement("div");
 d.innerHTML = "\
 <table class=\"memorizableAll\"><tr> \
   <th>Left Side <a style=\"font-size: 9px;\" href=\"#\" onclick=\"return Mem.start(this)\">(memorize)</a></th> \
   <th>Right Side <a style=\"font-size: 9px;\" href=\"#\" onclick=\"return Mem.start(this)\">(memorize)</a></th>\
 </tr></table>";

 // Get ref to it
 var tb = d.getElementsByTagName("TBODY")[0];

 var memTableCount = 0;

 // Convert list to map
 var onlyMap = [];
 if( onlyDoTheseTables )
  for(var x=0; x<onlyDoTheseTables.length; x++)
   onlyMap[ onlyDoTheseTables[x].toString() ] = true;

 // For each table
 var ts = document.getElementsByTagName("table");
 for(var x=0; x<ts.length; x++) {

  // In case null pointer when seeking anchor
  try {

   // If mem table
   if( ts[x].id == "memTable" ) {
    memTableCount++;

    if( onlyDoTheseTables && ! onlyMap[memTableCount.toString()] )
     continue;

    var rs = ts[x].rows;

    // If in progress, use backup
    if( ts[x].s && ts[x].s.tbodyBackup )
     rs = ts[x].s.tbodyBackup.rows;

    // Add each row to the table    
    for(var z=1; z<rs.length; z++)
     tb.appendChild( rs[z].cloneNode( true ) );
   }
  } catch(e) {}
 }

 // Append div
 item.parentNode.appendChild( d )

 // Start a session, using the 2nd "(memorize)" link
 Mem.start( d.getElementsByTagName("A")[1] );

 return false;
}

// Returns Y coord of top of element.
Mem.findY = function( o ) {
 var curtop = 0;
 if (o.offsetParent) {
  curtop = o.offsetTop
  while (o = o.offsetParent)
   curtop += o.offsetTop
 }
 return curtop;
}

// Get distance from page top to window bottom
Mem.getWindowBottomY = function() {
 // Get scrollY
 var scrollY = document.body.scrollTop;
 if( window.pageYOffset )
  scrollY = window.pageYOffset

 var winY = document.body.clientHeight;
 if( window.innerHeight )
  winY = window.innerHeight;

 return scrollY + winY;
}

Mem.scrollDownIfNecessary = function( obj ) {
 // If last row close to getting off-screen
 if( this.findY( obj ) + 55 > this.getWindowBottomY() ) {
  // Scroll down smoothly
  var myInterval = window.setInterval(function () { window.scrollBy( 0, 2 ); }, 10);
  window.setTimeout(function () { clearInterval(myInterval); },650);
 }
}

Mem.startFirst = function(level) {
 var as = byid('memTable').getElementsByTagName('a');
 var a = as.length == 1 ? as[0] : as[1];
 Mem.start( a );

 // If 2, start another record
 if(level == 2) {
  Mem.showAnswer(this.tChile('showAnswer'), true);
  Mem.answer(true, this.tChile('iWasRightButton'), true);
  this.tChile('directionsDiv').cycles = 100;
 }
}

Mem.parents = function(node, levels) {
 for(x=1;x<=levels;x++) node = node.parentNode;
 return node; 
}

Mem.showOptions = function(node) {

 this.setT(node);
 this.tChile('optionsLink').style.display="none";
 this.tChile('optionsBox').style.display="block";

 Mem.t.s.optionsOn = true;

 // Don't let clicking on options change default table
 this.restoreTBody();

 return false;
}

Mem.hideOptions = function(node) {

 this.setT(node);
 this.tChile('optionsLink').style.display="block";
 this.tChile('optionsBox').style.display="none";

 Mem.t.s.optionsOn = false;

 // Don't let clicking on options change default table
 this.restoreTBody();

 return false;
}

Mem.close = function( node ) {

 var t = this.setT( node );

 // Don't re-open options
 Mem.t.s.optionsOn = false;

 Mem.restore();

 // Invoke hook if reset
 if(node != null) {
  // In case method not there
  try {
   mem_close( t );
  } catch(e) {}
 }

 return false;
}

Mem.finished = function() {

 var directions = this.tChile('directionsDiv');
 var buttons = this.tChile('buttons');
 // Default values
 directions.innerHTML = "<div style='text-align:center;'>Congratulations, you've finished.</div>";
 buttons.innerHTML = "";

 // Restore rows
 this.addRowsFromBackup();

 // Call hook
 try {
  mem_finished( [directions, buttons] );
 } catch(e) {}

 Mem.glow(2, "finished");
 return false;
}

Mem.startOver = function( node ) {

 var t = this.setT( node );

 if( t.s.mode == "flashcard" )
  Mem.start( t.getElementsByTagName('a')[t.s.column] );

 else if( t.s.mode == "matching" )
  Mem.startMatching( t );

 return false;
}


Mem.startMatching = function( node ) {
 var t = this.setT( node );

 t.s.match0 = t.s.match1 = null;

 // Change help text
 this.tChile('mode').innerHTML = Mem.getModeDiv(1);
 this.tChile('directionsDiv').innerHTML = 
  "<div style='text-align:center;'><b>Note:</b> this table has been <i style='font-weight:bold; color:#f90; cursor: pointer;'><span onclick='Mem.startOver(this);'>shuffled</span></i>. Click items to identify matches.</div>";
 this.tChile('buttons').innerHTML = "";
 this.tChile('progress').innerHTML = "";

 var rows = t.rows;

 // Add rows from backup
 this.addRowsFromBackup();

 // Format them
 rows = t.rows;
 for(var x=1; x<(rows.length-1); x++) {
  var tds = rows[x].cells;
  // Add click events
  Mem.addEvent( tds[0], 'click', function(){ Mem.matchingClicked( this, 0 ) } );
  Mem.addEvent( tds[1], 'click', function(){ Mem.matchingClicked( this, 1 ) } );
  tds[0].style.cursor = tds[1].style.cursor = "pointer";
  tds[0].style.background = tds[1].style.background = tds[0].style.endColor = tds[1].style.endColor = Mem.mGray;
  // Add indexes
  tds[0].mIndex = tds[1].mIndex = x;
 }

 // Shuffle columns
 for (swaps=0; swaps<(rows.length*4); swaps++) {
  Mem.swapOnce(rows,0);
  Mem.swapOnce(rows,1);
 }

 this.glow(100);

 t.s.mode = "matching";

 return false; 
}

Mem.matchingClicked = function(cell, side) {

 // Exit if already correct
 if(cell.mState == "correct")
  return;

 var t = this.setT( cell );

 var rows = t.rows;
 // Update colors of others, and count remaining
 var remaining = 0;
 for(var x=1; x<(rows.length-1); x++) {
  var td = rows[x].cells[side];

  // If gray, clear it
  if((cell != td) && (td.mState == "guess")) {
   td.mState = null;
   td.style.background = td.endColor= Mem.mGray;
  }

  if(td.mState != "correct")  remaining++;
 }

 // Remember this was clicked
 if(side == 0)  t.s.match0 = cell;
 else  t.s.match1 = cell;

 // If already guessed
 if(cell.mState == "guess") {
  cell.mState = null;
  cell.style.background = cell.endColor = Mem.mGray;
  // Clear it
  if(side == 0)  t.s.match0 = null;
  else  t.s.match1 = null;

 } else {
  // Make it selected
  cell.mState = "guess";
  cell.style.background = cell.endColor = Mem.mClicked;
 }

 // Exit if neither are selected
 if(! (t.s.match0 && t.s.match1))
  return;

 // Go through backup table and look for matches
 var found = false;
 var backupRows = t.s.tbodyBackup.getElementsByTagName('tr');

 for(var x=1; x<backupRows.length; x++) {
  var tds = backupRows[x].getElementsByTagName('td');
  if((trim(t.s.match0.innerHTML) == trim(tds[0].innerHTML))
  && (trim(t.s.match1.innerHTML) == trim(tds[1].innerHTML)))
   found = true;
 }

 // If match
 if(found) {
  var directions = this.tChile('directionsDiv');
  if(directions.cycles > 2)
   directions.cycles = 2;

  // Make me dark green
  t.s.match0.mState = t.s.match1.mState = "correct";
  t.s.match0.endColor = t.s.match1.endColor = Mem.mGreen;
  t.s.match0.style.cursor = t.s.match1.style.cursor = "";

  // If finished - congrats message, restore rows
  if(remaining == 1) {
   directions.innerHTML = "<div style='text-align:center;'>Congratulations, you've finished. \
&nbsp; Try <a href='#' onclick='return Mem.flashcardMode(this)'>flashcard mode</a>.</div>";
   Mem.glow(2, "finished");
   this.addRowsFromBackup();
  } else {
   cell.style.background = Mem.mGray;
   Mem.glow(1, "green", t.s.match0, Mem.mGreen);
   Mem.glow(1, "green", t.s.match1, Mem.mGreen);
  }
  t.s.match0 = t.s.match1 = null;

  return;
 }

 // Must not have been found
 cell.style.background = Mem.mGray;
 Mem.glow(1, "red", cell, Mem.mClicked);

}

Mem.swapOnce = function( rows, index ) {
 var r1 = rows[Math.floor(Math.random() * (rows.length-2)) + 1];
 var r2 = rows[Math.floor(Math.random() * (rows.length-2)) + 1];
 var c1 = r1.cells[index];
 r1.replaceChild(r2.cells[index], c1);
 if(index == 0)
  r2.insertBefore(c1, r2.cells[0]);
 else
  r2.appendChild(c1);
}

Mem.getModeDiv = function( index ) {

 var r = "\
<span style='width:260px; text-align:right; padding: 0px 0px 2px 10px; letter-spacing:2px;\
border-left: solid #ccc 1px; \
border-bottom: solid #ccc 1px;'>\
";

 var modes = [["flashcard mode", "return Mem.flashcardMode(this)"], ["matching mode", "return Mem.startMatching(this)"]];
 for(var x=0; x<modes.length; x++) {

  if( x > 0 ) r += " | ";

  if(index == x)
   r += "<b>" + modes[x][0] + "</b>";
  else
   r += "<a style='color:#aaa;' href='#' onclick=\"" + modes[x][1] + "\">" + modes[x][0] + "</a>";

 }   
 r += "</span>";

 return r;
}

Mem.getOptions = function() {
 return "\
 <div style='display:none; line-height:17px; margin:27px 6px 4px 6px; padding: 3px 4px 4px 20px; border:dashed #fc0 2px;' id=optionsBox>\
  <a style='float:right; margin-top:-7px; font-size:9px;' href='#' onClick='return Mem.hideOptions(this)'>Hide Options</a>\
  -&nbsp;<a target='_blank' href='http://memorizable.com/Help'>Help</a>\
  &nbsp; &nbsp; -&nbsp;<a onclick='return Mem.startOver(this)' href='#'>Restart</a>\
  &nbsp; &nbsp; -&nbsp;<a onclick='return Mem.close(this)' href='#'>Cancel</a>\
 <br>\
  -&nbsp;<a target='_blank' href='http://memorizable.com/About_Memorizable_Tables'>About Memorizable Tables</a>\
 </div>\
 ";
}

Mem.setT = function(node) {

 // Return current, if no change
 if(! node)
  return this.t;

 // Remember last, for restoreTBody
 if(( typeof( Mem.t ) == 'object'))
   Mem.lastT = Mem.t;

 // Climb up parent until we find table
 while( ! node.isMem )
  node = node.parentNode;

 this.t = node;

 return node;
}

Mem.lookupT = function(nodex) {

 // Climb up parent until we find table
 while(! nodex.isMem)
  nodex = nodex.parentNode;

 return nodex;
}


Mem.restoreTBody = function() {
 Mem.t = Mem.lastT;
}

Mem.restore = function() {
 var orig = Mem.t.s.tbodyBackup;
 Mem.t.replaceChild( orig, Mem.t.tBodies[0] );
 Mem.t = orig.parentNode;
 // Whipe out ref to backup
 Mem.t.s.tbodyBackup = null;
}

Mem.addRowsFromBackup = function() {
 var t = this.t;
 var rows = t.rows;
 // Delete rows - except top and bottom
 var length = rows.length;
 for(var x=1; x<=length-2; x++)
  t.tBodies[0].removeChild( rows[length - (x+1)] );

 // Make copies from backup, add them to table
 var bak = t.s.tbodyBackup.cloneNode( true );
 var backupRows = bak.getElementsByTagName('tr');
 var length = backupRows.length;
 for(var x=1; x<length; x++)
  t.tBodies[0].insertBefore( backupRows[1], rows[rows.length-1] );
}


Mem.glow = function(cycles, color, glowDiv, endColor) {

 // Remember table
 if(!glowDiv) {
  glowDiv = this.tChile('directionsDiv');
  // Do nothing if already going
  if(glowDiv.cycles >= 1)
    return;
 }

 glowDiv.cycles = cycles;

 if(!endColor)
  endColor = "#fff";
 // Set end color to cell
 glowDiv.endColor = endColor;

 var glowLevel = color == "green" ? 35 : 0;
 var glowIncrement = color == "red" ? 8 : 2;
 if(color == "green") glowIncrement = 1;

 var myInterval = window.setInterval(function () {
  // Stop if cycles over
  if(glowDiv.cycles <= 0) {
   clearInterval(myInterval);
   return;
  }

  // Change level
  glowLevel += glowIncrement;
  // Go darker
  if(glowLevel < 0) {
   glowIncrement = 2;
   glowLevel += glowIncrement;
   // If this is the end, set it to the end color
   if(--glowDiv.cycles == 0) {
    glowDiv.style.background = glowDiv.endColor;
    return;
   }
  }
  // Go lighter
  if(glowLevel > 44) {
   glowIncrement = -2;
   glowLevel += glowIncrement;
   if(glowDiv.cycles == 1) {
    glowIncrement = color == "red" ? -6 : -1;
    if(color == "green") glowIncrement = -6;
   }
  }

  if(color == "red")
    Mem.glowColor(glowDiv, glowLevel, 180, 1, -2, -2);
  else if(color == "green")
    Mem.glowColor(glowDiv, glowLevel, 255, -3, 0, -5);
  else if(color == "finished")
    Mem.glowColor(glowDiv, glowLevel, 255, -2, 0, -4);
  else  // Orange
    Mem.glowColor(glowDiv, glowLevel, 255, 0, -1, -4);

 }, 43);
}

Mem.glowColor = function(glowDiv, glowLevel, start, r, g, b) {
  glowDiv.style.background = "rgb(" + (start+glowLevel*r) + "," + (start+glowLevel*g) + "," + (start+glowLevel*b) + ")";
}

Mem.chile = function(root, idName) {

 var maybe = root.getElementsByTagName( '*' );

 for(var x=0; x<maybe.length; x++)
  if( maybe[x].id == idName )
   return maybe[x];
}

Mem.tChile = function(idName) {

 return this.chile(this.t, idName);
}

Mem.flashcardMode = function(node) {

 Mem.setT(node);
 return Mem.start( Mem.t.getElementsByTagName('a')[Mem.t.s.column] );
}


function trim( s ) {
 return s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1");
}

function byid( key ) {
  return document.getElementById( key );
}

Mem.addEvent( document, "keydown", Mem.keyWasPressed );

//}}}
*Test 1
**Thursday, February 12
*Test 2
**Thursday, April 16
*Final Exam
**Tuesday, May 5, 11:30a-2:30p
Investigate the relation between sizes of [[orbits and stabilizers|resources/GridOrbit/GridOrbit.html]].
/***
|<html><a name="Top"/></html>''Name:''|PartTiddlerPlugin|
|''Version:''|1.0.9 (2007-07-14)|
|''Source:''|http://tiddlywiki.abego-software.de/#PartTiddlerPlugin|
|''Author:''|UdoBorkowski (ub [at] abego-software [dot] de)|
|''Licence:''|[[BSD open source license]]|
|''CoreVersion:''|2.1.3|
|''Browser:''|Firefox 1.0.4+; InternetExplorer 6.0|
!Table of Content<html><a name="TOC"/></html>
* <html><a href="javascript:;" onclick="window.scrollAnchorVisible('Description',null, event)">Description, Syntax</a></html>
* <html><a href="javascript:;" onclick="window.scrollAnchorVisible('Applications',null, event)">Applications</a></html>
** <html><a href="javascript:;" onclick="window.scrollAnchorVisible('LongTiddler',null, event)">Refering to Paragraphs of a Longer Tiddler</a></html>
** <html><a href="javascript:;" onclick="window.scrollAnchorVisible('Citation',null, event)">Citation Index</a></html>
** <html><a href="javascript:;" onclick="window.scrollAnchorVisible('TableCells',null, event)">Creating "multi-line" Table Cells</a></html>
** <html><a href="javascript:;" onclick="window.scrollAnchorVisible('Tabs',null, event)">Creating Tabs</a></html>
** <html><a href="javascript:;" onclick="window.scrollAnchorVisible('Sliders',null, event)">Using Sliders</a></html>
* <html><a href="javascript:;" onclick="window.scrollAnchorVisible('Revisions',null, event)">Revision History</a></html>
* <html><a href="javascript:;" onclick="window.scrollAnchorVisible('Code',null, event)">Code</a></html>
!Description<html><a name="Description"/></html>
With the {{{<part aPartName> ... </part>}}} feature you can structure your tiddler text into separate (named) parts. 
Each part can be referenced as a "normal" tiddler, using the "//tiddlerName//''/''//partName//" syntax (e.g. "About/Features").  E.g. you may create links to the parts (e.g. {{{[[Quotes/BAX95]]}}} or {{{[[Hobbies|AboutMe/Hobbies]]}}}), use it in {{{<<tiddler...>>}}} or {{{<<tabs...>>}}} macros etc.


''Syntax:'' 
|>|''<part'' //partName// [''hidden''] ''>'' //any tiddler content// ''</part>''|
|//partName//|The name of the part. You may reference a part tiddler with the combined tiddler name "//nameOfContainerTidder//''/''//partName//. <<br>>If you use a partName containing spaces you need to quote it (e.g. {{{"Major Overview"}}} or {{{[[Shortcut List]]}}}).|
|''hidden''|When defined the content of the part is not displayed in the container tiddler. But when the part is explicitly referenced (e.g. in a {{{<<tiddler...>>}}} macro or in a link) the part's content is displayed.|
|<html><i>any&nbsp;tiddler&nbsp;content</i></html>|<html>The content of the part.<br>A part can have any content that a "normal" tiddler may have, e.g. you may use all the formattings and macros defined.</html>|
|>|~~Syntax formatting: Keywords in ''bold'', optional parts in [...]. 'or' means that exactly one of the two alternatives must exist.~~|
<html><sub><a href="javascript:;" onclick="window.scrollAnchorVisible('Top',null, event)">[Top]</sub></a></html>

!Applications<html><a name="Applications"/></html>
!!Refering to Paragraphs of a Longer Tiddler<html><a name="LongTiddler"/></html>
Assume you have written a long description in a tiddler and now you want to refer to the content of a certain paragraph in that tiddler (e.g. some definition.) Just wrap the text with a ''part'' block, give it a nice name, create a "pretty link" (like {{{[[Discussion Groups|Introduction/DiscussionGroups]]}}}) and you are done.

Notice this complements the approach to first writing a lot of small tiddlers and combine these tiddlers to one larger tiddler in a second step (e.g. using the {{{<<tiddler...>>}}} macro). Using the ''part'' feature you can first write a "classic" (longer) text that can be read "from top to bottom" and later "reuse" parts of this text for some more "non-linear" reading.

<html><sub><a href="javascript:;" onclick="window.scrollAnchorVisible('Top',null, event)">[Top]</sub></a></html>

!!Citation Index<html><a name="Citation"/></html>
Create a tiddler "Citations" that contains your "citations". 
Wrap every citation with a part and a proper name. 

''Example''
{{{
<part BAX98>Baxter, Ira D. et al: //Clone Detection Using Abstract Syntax Trees.// 
in //Proc. ICSM//, 1998.</part>

<part BEL02>Bellon, Stefan: //Vergleich von Techniken zur Erkennung duplizierten Quellcodes.// 
Thesis, Uni Stuttgart, 2002.</part>

<part DUC99>Ducasse, Stéfane et al: //A Language Independent Approach for Detecting Duplicated Code.// 
in //Proc. ICSM//, 1999.</part>
}}}

You may now "cite" them just by using a pretty link like {{{[[Citations/BAX98]]}}} or even more pretty, like this {{{[[BAX98|Citations/BAX98]]}}}.

<html><sub><a href="javascript:;" onclick="window.scrollAnchorVisible('Top',null, event)">[Top]</sub></a></html>

!!Creating "multi-line" Table Cells<html><a name="TableCells"/></html>
You may have noticed that it is hard to create table cells with "multi-line" content. E.g. if you want to create a bullet list inside a table cell you cannot just write the bullet list
{{{
* Item 1
* Item 2
* Item 3
}}}
into a table cell (i.e. between the | ... | bars) because every bullet item must start in a new line but all cells of a table row must be in one line.

Using the ''part'' feature this problem can be solved. Just create a hidden part that contains the cells content and use a {{{<<tiddler >>}}} macro to include its content in the table's cell.

''Example''
{{{
|!Subject|!Items|
|subject1|<<tiddler ./Cell1>>|
|subject2|<<tiddler ./Cell2>>|

<part Cell1 hidden>
* Item 1
* Item 2
* Item 3
</part>
...
}}}

Notice that inside the {{{<<tiddler ...>>}}} macro you may refer to the "current tiddler" using the ".".

BTW: The same approach can be used to create bullet lists with items that contain more than one line.

<html><sub><a href="javascript:;" onclick="window.scrollAnchorVisible('Top',null, event)">[Top]</sub></a></html>

!!Creating Tabs<html><a name="Tabs"/></html>
The build-in {{{<<tabs ...>>}}} macro requires that you defined an additional tiddler for every tab it displays. When you want to have "nested" tabs you need to define a tiddler for the "main tab" and one for every tab it contains. I.e. the definition of a set of tabs that is visually displayed at one place is distributed across multiple tiddlers.

With the ''part'' feature you can put the complete definition in one tiddler, making it easier to keep an overview and maintain the tab sets.

''Example''
The standard tabs at the sidebar are defined by the following eight tiddlers:
* SideBarTabs
* TabAll
* TabMore
* TabMoreMissing
* TabMoreOrphans
* TabMoreShadowed
* TabTags
* TabTimeline

Instead of these eight tiddlers one could define the following SideBarTabs tiddler that uses the ''part'' feature:
{{{
<<tabs txtMainTab 
    Timeline Timeline SideBarTabs/Timeline 
    All 'All tiddlers' SideBarTabs/All 
    Tags 'All tags' SideBarTabs/Tags 
    More 'More lists' SideBarTabs/More>>
<part Timeline hidden><<timeline>></part>
<part All hidden><<list all>></part>
<part Tags hidden><<allTags>></part>
<part More hidden><<tabs txtMoreTab 
    Missing 'Missing tiddlers' SideBarTabs/Missing 
    Orphans 'Orphaned tiddlers' SideBarTabs/Orphans 
    Shadowed 'Shadowed tiddlers' SideBarTabs/Shadowed>></part>
<part Missing hidden><<list missing>></part>
<part Orphans hidden><<list orphans>></part>
<part Shadowed hidden><<list shadowed>></part>
}}}

Notice that you can easily "overwrite" individual parts in separate tiddlers that have the full name of the part.

E.g. if you don't like the classic timeline tab but only want to see the 100 most recent tiddlers you could create a tiddler "~SideBarTabs/Timeline" with the following content:
{{{
<<forEachTiddler 
		sortBy 'tiddler.modified' descending 
		write '(index < 100) ? "* [["+tiddler.title+"]]\n":""'>>
}}}
<html><sub><a href="javascript:;" onclick="window.scrollAnchorVisible('Top',null, event)">[Top]</sub></a></html>

!!Using Sliders<html><a name="Sliders"/></html>
Very similar to the build-in {{{<<tabs ...>>}}} macro (see above) the {{{<<slider ...>>}}} macro requires that you defined an additional tiddler that holds the content "to be slid". You can avoid creating this extra tiddler by using the ''part'' feature

''Example''
In a tiddler "About" we may use the slider to show some details that are documented in the tiddler's "Details" part.
{{{
...
<<slider chkAboutDetails About/Details details "Click here to see more details">>
<part Details hidden>
To give you a better overview ...
</part>
...
}}}

Notice that putting the content of the slider into the slider's tiddler also has an extra benefit: When you decide you need to edit the content of the slider you can just doubleclick the content, the tiddler opens for editing and you can directly start editing the content (in the part section). In the "old" approach you would doubleclick the tiddler, see that the slider is using tiddler X, have to look for the tiddler X and can finally open it for editing. So using the ''part'' approach results in a much short workflow.

<html><sub><a href="javascript:;" onclick="window.scrollAnchorVisible('Top',null, event)">[Top]</sub></a></html>

!Revision history<html><a name="Revisions"/></html>
* v1.0.9 (2007-07-14)
** Bugfix: Error when using the SideBarTabs example and switching between "More" and "Shadow". Thanks to cmari for reporting the issue.
* v1.0.8 (2007-06-16)
** Speeding up display of tiddlers containing multiple pard definitions. Thanks to Paco Rivière for reporting the issue.
** Support "./partName" syntax inside <<tabs ...>> macro
* v1.0.7 (2007-03-07)
** Bugfix: <<tiddler "./partName">> does not always render correctly after a refresh (e.g. like it happens when using the "Include" plugin). Thanks to Morris Gray for reporting the bug.
* v1.0.6 (2006-11-07)
** Bugfix: cannot edit tiddler when UploadPlugin by Bidix is installed. Thanks to José Luis González Castro for reporting the bug.
* v1.0.5 (2006-03-02)
** Bugfix: Example with multi-line table cells does not work in IE6. Thanks to Paulo Soares for reporting the bug.
* v1.0.4 (2006-02-28)
** Bugfix: Shadow tiddlers cannot be edited (in TW 2.0.6). Thanks to Torsten Vanek for reporting the bug.
* v1.0.3 (2006-02-26)
** Adapt code to newly introduced Tiddler.prototype.isReadOnly() function (in TW 2.0.6). Thanks to Paulo Soares for reporting the problem.
* v1.0.2 (2006-02-05)
** Also allow other macros than the "tiddler" macro use the "." in the part reference (to refer to "this" tiddler)
* v1.0.1 (2006-01-27)
** Added Table of Content for plugin documentation. Thanks to RichCarrillo for suggesting.
** Bugfix: newReminder plugin does not work when PartTiddler is installed. Thanks to PauloSoares for reporting.
* v1.0.0 (2006-01-25)
** initial version
<html><sub><a href="javascript:;" onclick="window.scrollAnchorVisible('Top',null, event)">[Top]</sub></a></html>

!Code<html><a name="Code"/></html>
<html><sub><a href="javascript:;" onclick="window.scrollAnchorVisible('Top',null, event)">[Top]</sub></a></html>
***/
//{{{
//============================================================================
//                           PartTiddlerPlugin

// Ensure that the PartTiddler Plugin is only installed once.
//
if (!version.extensions.PartTiddlerPlugin) {



version.extensions.PartTiddlerPlugin = {
    major: 1, minor: 0, revision: 9,
    date: new Date(2007, 6, 14), 
    type: 'plugin',
    source: "http://tiddlywiki.abego-software.de/#PartTiddlerPlugin"
};

if (!window.abego) window.abego = {};
if (version.major < 2) alertAndThrow("PartTiddlerPlugin requires TiddlyWiki 2.0 or newer.");

//============================================================================
// Common Helpers

// Looks for the next newline, starting at the index-th char of text. 
//
// If there are only whitespaces between index and the newline 
// the index behind the newline is returned, 
// otherwise (or when no newline is found) index is returned.
//
var skipEmptyEndOfLine = function(text, index) {
	var re = /(\n|[^\s])/g;
	re.lastIndex = index;
	var result = re.exec(text);
	return (result && text.charAt(result.index) == '\n') 
			? result.index+1
			: index;
}


//============================================================================
// Constants

var partEndOrStartTagRE = /(<\/part>)|(<part(?:\s+)((?:[^>])+)>)/mg;
var partEndTagREString = "<\\/part>";
var partEndTagString = "</part>";

//============================================================================
// Plugin Specific Helpers

// Parse the parameters inside a <part ...> tag and return the result.
//
// @return [may be null] {partName: ..., isHidden: ...}
//
var parseStartTagParams = function(paramText) {
	var params = paramText.readMacroParams();
	if (params.length == 0 || params[0].length == 0) return null;
	
	var name = params[0];
	var paramsIndex = 1;
	var hidden = false;
	if (paramsIndex < params.length) {
		hidden = params[paramsIndex] == "hidden";
		paramsIndex++;
	}
	
	return {
		partName: name, 
		isHidden: hidden
	};
}

// Returns the match to the next (end or start) part tag in the text, 
// starting the search at startIndex.
// 
// When no such tag is found null is returned, otherwise a "Match" is returned:
// [0]: full match
// [1]: matched "end" tag (or null when no end tag match)
// [2]: matched "start" tag (or null when no start tag match)
// [3]: content of start tag (or null if no start tag match)
//
var findNextPartEndOrStartTagMatch = function(text, startIndex) {
	var re = new RegExp(partEndOrStartTagRE);
	re.lastIndex = startIndex;
	var match = re.exec(text);
	return match;
}

//============================================================================
// Formatter

// Process the <part ...> ... </part> starting at (w.source, w.matchStart) for formatting.
//
// @return true if a complete part section (including the end tag) could be processed, false otherwise.
//
var handlePartSection = function(w) {
	var tagMatch = findNextPartEndOrStartTagMatch(w.source, w.matchStart);
	if (!tagMatch) return false;
	if (tagMatch.index != w.matchStart || !tagMatch[2]) return false;

	// Parse the start tag parameters
	var arguments = parseStartTagParams(tagMatch[3]);
	if (!arguments) return false;
	
	// Continue processing
	var startTagEndIndex = skipEmptyEndOfLine(w.source, tagMatch.index + tagMatch[0].length);
	var endMatch = findNextPartEndOrStartTagMatch(w.source, startTagEndIndex);
	if (endMatch && endMatch[1]) {
		if (!arguments.isHidden) {
			w.nextMatch = startTagEndIndex;
			w.subWikify(w.output,partEndTagREString);
		}
		w.nextMatch = skipEmptyEndOfLine(w.source, endMatch.index + endMatch[0].length);
		
		return true;
	}
	return false;
}

config.formatters.push( {
    name: "part",
    match: "<part\\s+[^>]+>",
	
	handler: function(w) {
		if (!handlePartSection(w)) {
			w.outputText(w.output,w.matchStart,w.matchStart+w.matchLength);
		}
	}
} )

//============================================================================
// Extend "fetchTiddler" functionality to also recognize "part"s of tiddlers 
// as tiddlers.

var currentParent = null; // used for the "." parent (e.g. in the "tiddler" macro)

// Return the match to the first <part ...> tag of the text that has the
// requrest partName.
//
// @return [may be null]
//
var findPartStartTagByName = function(text, partName) {
	var i = 0;
	
	while (true) {
		var tagMatch = findNextPartEndOrStartTagMatch(text, i);
		if (!tagMatch) return null;

		if (tagMatch[2]) {
			// Is start tag
	
			// Check the name
			var arguments = parseStartTagParams(tagMatch[3]);
			if (arguments && arguments.partName == partName) {
				return tagMatch;
			}
		}
		i = tagMatch.index+tagMatch[0].length;
	}
}

// Return the part "partName" of the given parentTiddler as a "readOnly" Tiddler 
// object, using fullName as the Tiddler's title. 
//
// All remaining properties of the new Tiddler (tags etc.) are inherited from 
// the parentTiddler.
// 
// @return [may be null]
//
var getPart = function(parentTiddler, partName, fullName) {
	var text = parentTiddler.text;
	var startTag = findPartStartTagByName(text, partName);
	if (!startTag) return null;
	
	var endIndexOfStartTag = skipEmptyEndOfLine(text, startTag.index+startTag[0].length);
	var indexOfEndTag = text.indexOf(partEndTagString, endIndexOfStartTag);

	if (indexOfEndTag >= 0) {
		var partTiddlerText = text.substring(endIndexOfStartTag,indexOfEndTag);
		var partTiddler = new Tiddler();
		partTiddler.set(
						fullName,
						partTiddlerText,
						parentTiddler.modifier,
						parentTiddler.modified,
						parentTiddler.tags,
						parentTiddler.created);
		partTiddler.abegoIsPartTiddler = true;
		return partTiddler;
	}
	
	return null;
}

// Hijack the store.fetchTiddler to recognize the "part" addresses.
//
var hijackFetchTiddler = function() {
	var oldFetchTiddler = store.fetchTiddler ;
	store.fetchTiddler = function(title) {
		var result = oldFetchTiddler.apply(this, arguments);
		if (!result && title) {
			var i = title.lastIndexOf('/');
			if (i > 0) {
				var parentName = title.substring(0, i);
				var partName = title.substring(i+1);
				var parent = (parentName == ".") 
						? store.resolveTiddler(currentParent)
						: oldFetchTiddler.apply(this, [parentName]);
				if (parent) {
					return getPart(parent, partName, parent.title+"/"+partName);
				}
			}
		}
		return result;	
	};
};

// for debugging the plugin is not loaded through the systemConfig mechanism but via a script tag. 
// At that point in the "store" is not yet defined. In that case hijackFetchTiddler through the restart function.
// Otherwise hijack now.
if (!store) {
	var oldRestartFunc = restart;
	window.restart = function() {
		hijackFetchTiddler();
		oldRestartFunc.apply(this,arguments);
	};
} else
	hijackFetchTiddler();




// The user must not edit a readOnly/partTiddler
//

config.commands.editTiddler.oldIsReadOnlyFunction = Tiddler.prototype.isReadOnly;

Tiddler.prototype.isReadOnly = function() {
	// Tiddler.isReadOnly was introduced with TW 2.0.6.
	// For older version we explicitly check the global readOnly flag
	if (config.commands.editTiddler.oldIsReadOnlyFunction) {
		if (config.commands.editTiddler.oldIsReadOnlyFunction.apply(this, arguments)) return true;
	} else {
		if (readOnly) return true;
	}

	return this.abegoIsPartTiddler;
}

config.commands.editTiddler.handler = function(event,src,title)
{
	var t = store.getTiddler(title);
	// Edit the tiddler if it either is not a tiddler (but a shadowTiddler)
	// or the tiddler is not readOnly
	if(!t || !t.abegoIsPartTiddler)
		{
		clearMessage();
		story.displayTiddler(null,title,DEFAULT_EDIT_TEMPLATE);
		story.focusTiddler(title,"text");
		return false;
		}
}

// To allow the "./partName" syntax in macros we need to hijack 
// the invokeMacro to define the "currentParent" while it is running.
// 
var oldInvokeMacro = window.invokeMacro;
function myInvokeMacro(place,macro,params,wikifier,tiddler) {
	var oldCurrentParent = currentParent;
	if (tiddler) currentParent = tiddler;
	try {
		oldInvokeMacro.apply(this, arguments);
	} finally {
		currentParent = oldCurrentParent;
	}
}
window.invokeMacro = myInvokeMacro;

// To correctly support the "./partName" syntax while refreshing we need to hijack 
// the config.refreshers.tiddlers to define the "currentParent" while it is running.
// 
(function() {
	var oldTiddlerRefresher= config.refreshers.tiddler;
	config.refreshers.tiddler = function(e,changeList) {
		var oldCurrentParent = currentParent;
		try {
			currentParent = e.getAttribute("tiddler");
			return oldTiddlerRefresher.apply(this,arguments);
		} finally {
			currentParent = oldCurrentParent;
		}
	};
})();

// Support "./partName" syntax inside <<tabs ...>> macro
(function() {
	var extendRelativeNames = function(e, title) {
		var nodes = e.getElementsByTagName("a");
		for(var i=0; i<nodes.length; i++) {
			var node = nodes[i];
			var s = node.getAttribute("content");
			if (s && s.indexOf("./") == 0)
				node.setAttribute("content",title+s.substr(1));
		}
	};
	var oldHandler = config.macros.tabs.handler;
	config.macros.tabs.handler = function(place,macroName,params,wikifier,paramString,tiddler) {
		var result = oldHandler.apply(this,arguments);
		if (tiddler)
			extendRelativeNames(place, tiddler.title);
		return result;
	};
})();

// Scroll the anchor anchorName in the viewer of the given tiddler visible.
// When no tiddler is defined use the tiddler of the target given event is used.
window.scrollAnchorVisible = function(anchorName, tiddler, evt) {
	var tiddlerElem = null;
	if (tiddler) {
		tiddlerElem = document.getElementById(story.idPrefix + tiddler);
	}
	if (!tiddlerElem && evt) {
		var target = resolveTarget(evt);
		tiddlerElem = story.findContainingTiddler(target);
	}
	if (!tiddlerElem) return;

	var children = tiddlerElem.getElementsByTagName("a");
	for (var i = 0; i < children.length; i++) {
		var child = children[i];
		var name = child.getAttribute("name");
		if (name == anchorName) {
			var y = findPosY(child);
			window.scrollTo(0,y);
			return;
		}
	}
}

} // of "install only once"
//}}}

/***
<html><sub><a href="javascript:;" onclick="scrollAnchorVisible('Top',null, event)">[Top]</sub></a></html>

!Licence and Copyright
Copyright (c) abego Software ~GmbH, 2006 ([[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.

<html><sub><a href="javascript:;" onclick="scrollAnchorVisible('Top',null, event)">[Top]</sub></a></html>
***/
/%
*[[Quiz 1 (pdf)|quizzes/mat336fall08quiz1ver1.pdf]] | [[answers (pdf)|quizzes/mat336fall08quiz1ver1answers.pdf]]
*[[Quiz 2 (pdf)|quizzes/mat336fall08quiz2ver1.pdf]] | [[answers (pdf)|quizzes/mat336fall08quiz2ver1answers.pdf]]
*[[Quiz 3 (pdf)|quizzes/mat336fall08quiz3ver1.pdf]] | [[answers (pdf)|quizzes/mat336fall08quiz3ver1answers.pdf]]
*[[Quiz 4 (pdf)|quizzes/mat336fall08quiz4ver1.pdf]] | [[answers (pdf)|quizzes/mat336fall08quiz4ver1answers.pdf]]
%/
!Note Cards
Robbie Cantey has kindly provided note cards covering roughly the first half of the course material, with the hope that they may help some other terrified Modern Algebra students to feel a little more secure.
[[Front|resources/Test1NoteCards(front).docx]] | [[Back|resources/Test1NoteCards(back).docx]]

!Advice
[[Advice on writing and reading mathematics|advice/advice-on-writing-and-reading-2008Sep02.html]]

!Maple Worksheet
[[Fermat's Little Theorem - Necklaces|resources/mat336spring09-fermat-little-theorem-2009Jan15.mws]]

<<tabs Schedule
Jan "January" Schedule/January
Feb "February" Schedule/February
Mar "March" Schedule/March
Apr "April" Schedule/April
May "May" Schedule/May
>>
<part January hidden>
*Thursday, January 8
**Section 1.1-1.2: Preliminaries
*Tuesday, January 13
**Section 1.3-1.4: Greatest Common Divisor; Fundamental Theorem of Arithmetic
*Thursday, January 15
**Section 1.5: Congruences; Fermat's Little Theorem
*Tuesday, January 20
**Section 2.1: Functions
*Thursday, January 22
**Section 2.2: Permutations
*Tuesday, January 27
**Section 2.2 continued
*Thursday, January 29
**Section 2.3: Groups and examples
</part>
<part February hidden>
*Tuesday, February 3
**Section 2.3 continued
*Thursday, February 5
**Section 2.4: Subgroups
*Tuesday, February 10
**Review
*Thursday, February 12
**Test 1
*Tuesday, February 17
**Debriefing
*Thursday, February 19
**Section 2.4: Orbits and Stabilizers
*Tuesday, February 24
**Section 2.4: Lagrange's Theorem
*Thursday, February 26
**Section 2.5: Cosets and Normal Subgroups
</part>
<part March hidden>
*Tuesday, March 3
**Section 2.5: Group Homomorphisms
*Thursday, March 5
**Test
*Tuesday, March 10
**Spring Break
*Thursday, March 12
**Spring Break
*Tuesday, March 17
**Section 2.6: Quotient groups
*Thursday, March 19
**Question and answer
*Tuesday, March 24
**Section 2.6: Isomorphism theorems
*Thursday, March 26
**Section 2.6 continued
*Tuesday, March 31
**Class cancelled
</part>
<part April hidden>
*Thursday, April 2
**Section 3.1: Commutative Rings
*Tuesday, April 7
**Section 3.2: Fields
*Thursday, April 9
**Easter Holiday
*Tuesday, April 14
**Review
*Thursday, April 16
**Test 2
*Tuesday, April 21
**Debriefing
*Thursday, April 23
**Review
*Tuesday, April 28
**Reading Day
</part>
<part May hidden>
*Tuesday, May 5
**Final Exam, 11:30a-2:30p
</part>
<<slideShow>>


-s-
!Integers and Natural Numbers

*Define integer, natural number, divisor, prime, composite

*Least Integer Axiom (Well Ordering Property)


-s-
!The Idea of Proof
*What constitutes a proof?

*Validity and soundness of arguments


-s-
!Elementary Proof Techniques
*Modus Ponens ...is Latin for ‘bridge method’, and is the basic mathematical maneuver. 
**Example:  All primes $p > 2$ are odd.  17 is prime.  Thus, 17 is odd.
**Common fallacy: Converse need not be true.
***Example: All primes $p > 2$ are odd.  15 is odd.  Thus, 15 is prime.

*Reductio ad absurdum ...is Latin for 'Reduction to absurdity', and is often called proof by contradiction.
**Example:  All men are mortal.  Zeus is not mortal.  Thus, Zeus is not a man.
**Example:  Thm:  There are infinitely many prime numbers.

*Dichotomy ...is Greek for 'cutting in two', and is sometimes called case-by-case analysis.
**Example:  Thm:  For $n$ an integer, $n^2+1$ is not divisible by 4.


-s-
!Mathematical Induction
*Proof by induction ...a mathematically precise way of reducing a big problem to a slightly smaller problem.
**Example:  Thm: Every integer $n \ge 2$ is either a prime or a product of primes.
**Example:  Prop: $1+ \cdots + n = \frac{n(n+1)}{2}$


-s-
!Arithmetic Mean - Geometric Mean Inequality
*Prop:  For positive real numbers $x,y$ we have
$$\frac{x+y}{2} \ge \sqrt{xy}.$$

*Extended form



-s-
!Strong Mathematical Induction
*Strong mathematical induction assumes an apparently stronger inductive hypothesis.
**Example:  A formula for the $n$th Fibonnaci number.



-s-
!Binomial Theorem
*Problem:  What are the coefficients in the expansion of $(1+x)^n ?$


-s-
!Binomial Coefficients
*Lemma:  ${n+1} \choose r  = n \choose {r-1} + n \choose r$

*Prop:  $n \choose r = \frac{n!}{r!(n-r)!}$


<<slideShow>>

-s-
!Sets



-s-
!Combining Sets



-s-
!Functions



-s-
!Combining Functions



-s-
!Countable and Uncountable



-s-
!Equivalence Relations






!Definition
If $X$ is a set, then a list in $X$ is a function $f: \{1,2,\ldots,n\} \rightarrow X.$  If a list $f$ in $X$ is a bijections (so that $X$ is now a finite set with $\vert X \vert = n$), then $f$ is called an arrangement of $X.$

!Definition
A permutation of a possibly infinite set $X$ is a bijection $\alpha : X \rightarrow X.$

!Definition
The family of all the permutations of a set $X,$ denoted by $S_{X},$ is called the symmetric group on $X.$  When $X=\{1,2,\ldots,n\},$ $S_{X}$ is usually denoted by $S_{n},$ and it is called the symmetric group on $n$ letters.

!Definition
If $\alpha \in S_{n}$ and $i \in \{1,2,\ldots,n\},$ then $\alpha$ fixes $i$ if $\alpha(i)=i,$ and $\alpha$ moves $i$ if $\alpha(i) \ne i.$

!Definition
Let $i_1,i_2,\ldots,i_r$ be distinct integers in $\{1,2,\ldots,n\}.$  If $\alpha \in S_n$ fixes the other integers (if any) and if $\alpha(i_1)=i_2, \alpha(i_2)=i_3, \ldots \alpha(i_r)=i_1,$ then $\alpha$ is called an $r$-cycle.  One also says that $\alpha$ is a cycle of length $r.$

!Definition
Two permutations $\alpha,\beta \in S_n$ are disjoint if every $i$ moved by one is fixed by the other: if $\alpha(i) \ne i,$ then $\beta(i) = i,$ and if $\beta(j) \ne j,$ then $\alpha(j) = j.$  A family $\beta_1,\ldots,\beta_t$ of permutations is disjoint if each pair of them is disjoint.

!Lemma
Disjoint permutations $\alpha,\beta \in S_n$ commute.

!Proposition
Every permutation $\alpha \in S_n$ is either a cycle or a product of disjoint cycles.

!Definition
A complete factorization of a permutation $\alpha$ is a factorization of $\alpha$ into disjoint cycles that contains one 1-cycle $(i)$ for every $i$ fixed by $\alpha.$

!Theorem
Let $\alpha \in S_n$ and let $\alpha = \beta_1 \cdots \beta_t$ be a complete factorization into disjoint cycles.  This factorization is unique except for the order in which the cycles occur.

!Definition
Two permutations $\alpha, \beta \in S_n$ have the same cycle structure if their complete factorizations have the same number of $r$-cycles for each $r \ge 1.$

!Proposition
If $\gamma, \alpha \in S_n,$ then $\alpha \gamma \alpha^{-1}$ has the same cycle structure as $\gamma.$

!Proposition
If $n \ge 2,$ then every $\alpha \in S_n$ is a product of transpositions.

!Definition
If $\alpha \in S_n$ and $\alpha = \beta_1 \cdots \beta_t$ is a complete factorization into $t$ disjoint cycles, then the signum of $\alpha$ is defined by $\mbox{sgn}(\alpha)=(-1)^{n-t}.$

!Theorem
For all $\alpha,\beta \in S_n,$ $\mbox{sgn}(\alpha \beta) = \mbox{sgn}(\alpha) \mbox{sgn}(\beta).$

!Definition
A permutation $\alpha \in S_n$ is even if $\mbox{sgn}(\alpha)=1,$ and $\alpha$ is odd if $\mbox{sgn}(\alpha)=-1.$  We say that $\alpha$ and $\beta$ have the same parity if both are even or both are odd.

!Theorem
Let $\alpha \in S_n.$  Then $\alpha$ is even if and only if $\alpha$ is a product of an even number of permutations.


<<slideShow>>



-s-
!Integration by Parts

*Recall that the product rule for differentiation states
$$\frac{d}{dx} [ f(x)g(x) ] = f'(x)g(x) + f(x)g'(x).$$

*Integrating, we find that
$$\int f(x)g'(x)dx = f(x)g(x) - \int g(x)f'(x)dx.$$

*Making the substitutions $u = f(x)$ and $v = g(x),$ we obtain
$$\int u \, dv = uv - \int v \mbox{ } du.$$


-s-
!Example

*Consider $\int x \, \sin x \mbox{ } dx$.

*We must choose $u$ and $dv$ appropriately to apply the integration by parts formula.

*In this case, we may choose $u=x$ and $dv = \sin x \mbox{ } dx .$

*Then we have $du=dx$ and $v = -\cos x .$

*It follows that
$$\begin{eqnarray} \int x \sin x \mbox{ } dx & = & x \cdot -\cos x - \int -\cos x \mbox{ } dx \\
& = & -x \cos x + \int \cos x \mbox{ } dx \\
& = & -x \cos x + \sin x + C \end{eqnarray}$$
Spring 2009
MAT 336 Introductory Modern Algebra I
<<slideShow>> - A simple slide show that keeps the TW style 
<<slideShow style:'MySSStyleSheet' clock:'+'>> - A themed slide show with a clock showing the presentation elapsed time
<<slideShow repeat clock:'-20'>> - A looping slide show with a 20 minutes countdown clock
<<slideShow slidePause:1000>> - A timed slideshow that runs once
<<slideShow slidePause:1000 repeat>> - A timed looping slideshow
-s-
!The [[SlideShowPlugin]]
Press F11 to go fullscreen and adjust the font sizes with Ctrl++ Ctrl+- (or Ctrl+mousewheel).

This plugin was developed by Paulo Soares and Clint Checketts.
{{Comment{This block is not shown in the slide show.
@@Don't show me!!!@@}}}
-s-
!How slides are separated
In a tiddler, you start each slide with the markup {{{-s-}}}
-s-
Slides don't have to have titles like this poor one but can have images.
[img[photos/lisboa-0.jpg]]
-s-
!A slide with subsections and a long title
Check to TOC below to see how this slide title is abbreviated.
!!Section 1
This is a section
!!!Subsection 1.1
This is a subsection
!!!Subsection 1.2
This is another subsection
!!!!Subsubsection 1.2.1
This is a subsubsection
-s-
!Using the keyboard
The following keys are defined:
*Left arrow - previous overlay
*Down arrow - previous slide
*Right arrow - next overlay
*Up arrow - next slide
*Home - first slide
*End - last slide
*Escape - exit slide show
*Spacebar - pause/resume slide show in auto advance mode
-s-
!Slide show parameters
*The slide show can be themed by providing a ~StyleSheet ({{{<<slideShow style:'MyStyleSheet'>>}}})
*By default, there is a clock at bottom of the browser window that displays the current time. This clock can also show the presentation elapsed time with {{{<<slideShow clock:'+'>>}}} or a countdown clock with {{{<<slideShow clock:'-20'>>}}} (for 20 minutes). In these two cases, if you click on the clock display it will be restarted
*The slide show can be set to loop ({{{<<slideShow repeat>>}}})
*You can set it so each slide changes after X milliseconds ({{{<<slideShow slidePause:X>>}}}) (auto advance mode)
*Use auto start mode to begin the slideshow the moment the tiddler is opened ({{{<<slideShow autostart>>>}}})
*You can disable overlays with {{{<<slideShow noOverlays>>}}}
*These parameters can be mixed and matched in any order: {{{<<slideShow slidePause:1000 repeat>>}}} is the same as {{{<<slideShow repeat slidePause:1000>>}}}
-s-
!Overlays
To see how incremental display works use the left and right mouse buttons.
{{Overlay1{You can}}} {{Overlay2{present things}}} {{Overlay1{in an arbitrary order!!!}}}
{{Overlay3{Its a bit harder with lists but it works:}}}
<html>
<ol>
<li class="Overlay4">First item</li>
<li class="Overlay5">Second item</li>
<li class="Overlay4">Last item</li>
</ol>
</html>
{{Comment{You can hide comments on a slide that won't display in the slide show}}}
<!--{{{-->
<div id='displayArea'>
<div id='tiddlerDisplay'></div>
</div>
<!--}}}-->
/***
|''Name:''|SlideShowPlugin|
|''Description:''|Creates a simple slide show type display|
|''Version:''|1.5.1|
|''Date:''|Nov 10, 2006|
|''Source:''|http://www.math.ist.utl.pt/~psoares/addons.html|
|''Author:''|Paulo Soares (psoares (at) math (dot) ist (dot) utl (dot) pt) and [[Clint Checketts|http://www.checkettsweb.com]]|
|''License:''|[[BSD open source license]]|
|''~CoreVersion:''|2.1.0|
|''Browser:''|Firefox 1.0.4+; Firefox 1.5; InternetExplorer 6.0|
<<tiddler SlideShowPluginDoc>>
!Code
***/
//{{{
config.macros.slideShow = {label: "slide show", maxTOCLength: 30};
config.macros.slideShow.messages = {gotoLabel: "Go to slide:"};
config.views.wikified.slideShow = {text: "slide show", tooltip: "Start slide show"};
config.views.wikified.slideShow.quit = {text: "end", tooltip: "Quit the slide show"};
config.views.wikified.slideShow.firstSlide = {text: "<<", tooltip: "first slide"};
config.views.wikified.slideShow.previousSlide = {text: "<", tooltip: "previous slide"};
config.views.wikified.slideShow.nextSlide = {text: ">", tooltip: "next slide"};
config.views.wikified.slideShow.lastSlide = {text: ">>", tooltip: "last slide"};
config.views.wikified.slideShow.resetClock = {text: " ", tooltip: "reset"};

config.formatters.push( {
 name: "SlideSeparator",
 match: "^-s-+$\\n?",
 handler: function(w)
 {
 createTiddlyElement(w.output,"hr",null,'slideSeparator');
 }
}
)

function changeStyleSheet(tiddlerName) {
 if (tiddlerName == null) tiddlerName = "StyleSheet";
 setStylesheet(store.getRecursiveTiddlerText("StyleSheetColors"),"StyleSheetColors");
 setStylesheet(store.getRecursiveTiddlerText("StyleSheetLayout"),"StyleSheetLayout");
 var theCSS = store.getRecursiveTiddlerText(tiddlerName,"");
 setStylesheet(theCSS,"StyleSheet");
}

//Excellent (and versatile) reparser created by Paul Petterson for parsing the paramString in a macro
function reparse( params ) {
 var re = /([^:\s]+)(?:\:((?:\d+)|(?:["'](?:[^"']+)["']))|\s|$)/g;
 var ret = new Array() ;
 var m ;
 while( (m = re.exec( params )) != null ) ret[ m[1] ] = m[2]?m[2]:true ;
 return ret ;
}

function getElementsByClass(searchClass,node,tag) {
 var classElements = new Array();
 if ( node == null ) node = document;
 if ( tag == null ) tag = '*';
 var els = node.getElementsByTagName(tag);
 var elsLen = els.length;
 var pattern = new RegExp("(^|\\s)"+searchClass+"(\\s|$)");
 var j=0;
 for (var i = 0; i < elsLen; i++) {
 if ( pattern.test(els[i].className) ) {
 classElements[j] = els[i];
 j++;
 }
 }
 return classElements;
}

// 'keys' code adapted from S5 which in turn was adapted from MozPoint (http://mozpoint.mozdev.org/)
function keys(key) {
 if (document.getElementById('contentWrapper').className == "slideShowMode"){
 if (!key) {
 key = event;
 key.which = key.keyCode;
 }
 switch (key.which) {
 case 32: // spacebar
 if(time>0){
 if(autoAdvance){
 clearInterval(autoAdvance);
 autoAdvance = null;
 } else {
 autoAdvance=setInterval("GoToSlide(1)", time);
 }
 }
 break;
 case 34: // page down
 case 39: // rightkey
 GoToSlide("n");
 break;
 // case 40: // downkey
 GoToSlide(-1);
 break;
 case 33: // page up
 case 37: // leftkey
 GoToSlide("p");
 break;
 // case 38: // upkey
 GoToSlide(1);
 break;
 case 36: // home
 GoToSlide("f");
 break;
 case 35: // end
 GoToSlide("l");
 break;
 case 27: // escape
 endSlideShow();
 break;
 }

 }
 return false;
}

function clicker(e) {
 if (!e) var e = window.event;
 var target = resolveTarget(e);
 //Whenever something is clicked that won't advance the slide make sure that the table of contents gets hidden
 if (target.getAttribute('href') != null || isParentOrSelf(target, 'toc') || isParentOrSelf(target,'embed') || isParentOrSelf(target,'object') || isParentOrSelf(target, 'pageFooter') || isParentOrSelf(target, 'navigator')){
 //Don't hide the TOC if the indexNumbers (which trigger the index) is clicked
 if(isParentOrSelf(target,'indexNumbers') || isParentOrSelf(target,'jumpInput')){
 return true;
 }
 showHideTOC('none');
 return true;
 }
 
 //Advance a slide if the TOC is visible otherwise make sure that the TOC gets hidden
 if ((!e.which && e.button == 1) || e.which == 1) {
 if (document.getElementById('toc').style.display != 'block'){
 GoToSlide("n");
 } else {
 showHideTOC('none');
 }
 }
 
 if ((!e.which && e.button == 2) || e.which == 3) {
 if (document.getElementById('toc').style.display != 'block'){
 GoToSlide("p");
 } else {
 showHideTOC('none');
 }
 return false;
 }
}

function isParentOrSelf(element, id) {
 if (element == null || element.nodeName=='BODY') return false;
 else if (element.id == id) return true;
 else return isParentOrSelf(element.parentNode, id);
}

GoToSlide=function(step) {
 var new_pos;
 var slideHolder = document.getElementById('slideContainer');
 //The parse float ensures that the attribute is returned as a number and not a string.
 var cur_pos = parseFloat(slideHolder.getAttribute('currentslide'));
 var numberSlides = parseFloat(slideHolder.getAttribute('numberSlides'));
 switch (step) {
 case "f":
 new_pos=0;
 break;
 case "l":
 new_pos=numberSlides-1;
 break;
 case "n":
 var numberOverlays = parseFloat(slideHolder.childNodes[cur_pos].getAttribute('numberOverlays'));
 var currentOverlay = parseFloat(slideHolder.getAttribute('currentOverlay'));
 if(numberOverlays==0 || currentOverlay==numberOverlays){
 new_pos=cur_pos+1;
 } else {
 var className="Overlay"+currentOverlay;
 var overlay=getElementsByClass(className,slideHolder.childNodes[cur_pos]);
 for(var i=0; i<overlay.length; i++) {overlay[i].className=className+' previousOverlay';}
 currentOverlay++;
 slideHolder.setAttribute('currentOverlay',currentOverlay);
 className="Overlay"+currentOverlay;
 overlay=getElementsByClass(className,slideHolder.childNodes[cur_pos]);
 for(i=0; i<overlay.length; i++) {overlay[i].className=className+' currentOverlay';}
 return false;
 }
 break;
 case "p":
 var numberOverlays = parseFloat(slideHolder.childNodes[cur_pos].getAttribute('numberOverlays'));
 var currentOverlay = parseFloat(slideHolder.getAttribute('currentOverlay'));
 if(numberOverlays==0 || currentOverlay==0){
 new_pos=cur_pos-1;
 } else {
 var className="Overlay"+currentOverlay;
 var overlays=getElementsByClass(className,slideHolder.childNodes[cur_pos]);
 for(var i=0; i<overlays.length; i++) {overlays[i].className=className+' nextOverlay';}
 currentOverlay--;
 className="Overlay"+currentOverlay;
 overlays=getElementsByClass(className,slideHolder.childNodes[cur_pos]);
 for(i=0; i<overlays.length; i++) {overlays[i].className=className+' currentOverlay';}
 slideHolder.setAttribute('currentOverlay',currentOverlay);
 return false;
 }
 break;
 default:
 new_pos=cur_pos+step;
 }

 if(slideShowCircularMode && new_pos == numberSlides) new_pos=0;
 if(slideShowCircularMode && new_pos<0) new_pos=(numberSlides - 1);
 if(step!=0 && new_pos>=0 && new_pos<numberSlides) {
 slideHolder.childNodes[cur_pos].style.display='none';
 slideHolder.childNodes[new_pos].style.display='block';
 slideHolder.setAttribute('currentslide',new_pos);
 var numberOverlays = parseFloat(slideHolder.childNodes[new_pos].getAttribute('numberOverlays'));
 if(step=="p"){
 var currentOverlay=numberOverlays;
 var state=' previousOverlay';
 } else {
 var currentOverlay=0;
 var state=' nextOverlay';
 }
 slideHolder.setAttribute('currentOverlay',currentOverlay);
 if(numberOverlays>0) {
 for(var i=1; i<=numberOverlays; i++){
 var className="Overlay"+i;
 var overlays=getElementsByClass(className,slideHolder.childNodes[new_pos]);
 for(var j=0; j<overlays.length; j++) {overlays[j].className=className+state;}
 }
 if(step=="p"){
 var className="Overlay"+numberOverlays;
 var overlays=getElementsByClass(className,slideHolder.childNodes[new_pos]);
 for(var j=0; j<overlays.length; j++) {overlays[j].className=className+' currentOverlay';}
 }
 }
 new_pos++;
 var indexNumbers = document.getElementById('indexNumbers');
 indexNumbers.firstChild.data = new_pos+'/'+numberSlides;
 if((new_pos==numberSlides) && !slideShowCircularMode && autoAdvance) clearInterval(autoAdvance);
 return true;
 }
 return false;
}

function tocShowSlide(e) {
 if (!e) var e = window.event;
 var target = resolveTarget(e);
 var slide = target.getAttribute('slideNumber');
 var cur_pos = document.getElementById('slideContainer').getAttribute('currentslide');
 var step = slide-cur_pos;
 if(step!=0) GoToSlide(step);
 showHideTOC('none');
 return;
}

//Toggle the display of the table of contents
function showHideTOC(display){
 var toc = document.getElementById('toc');
 //Reset the input box
 document.getElementById('jumpInput').value = "";

 if (display == null || display.length == null){
 if (toc.style.display == 'none' || toc.style.display == ''){
 toc.style.display = 'block';
 document.getElementById('jumpInput').focus();
 } else {
 toc.style.display = 'none';
 }
 } else {
 toc.style.display = display;
 if (display == 'block')
 document.getElementById('jumpInput').focus();
 }
}

function makeSignature(title,params){
 var signature = title+store.getTiddler(title).modified;
 if(params['style']) signature += params['style'];
 if(params['repeat']) signature += "repeat";
 if(params['slidePause'] > 0) signature += params['slidePause'];
 if(params['autostart']) signature += "autostart";
 if(params['clock']) signature += params['clock'];
 if(params['noOverlays']) signature += "noOverlays";
 return signature;
}

function padZero(x){
 return (x>=10 || x<0 ? "" : "0")+x;
}

setClock=function(){
 var actualTime = new Date();
 var newTime = actualTime.getTime() - clockStartTime;
 newTime = clockMultiplier*newTime+clockInterval+clockCorrection;
 actualTime.setTime(newTime);
 newTime = padZero(actualTime.getHours()) + ":" + padZero(actualTime.getMinutes())+ ":" + padZero(actualTime.getSeconds());
 var clock = document.getElementById('slideClock');
 clock.firstChild.nodeValue = newTime;
}

resetClock=function(){
 var time = new Date(0);
 if(clockStartTime>time){
 var startTime = new Date();
 clockStartTime=startTime.getTime();
 }
}

var title;
var place;
var autoAdvance=null;
var autoStart=null;
var slideClock=null;
var noOverlays=false;
var time = 0;
var slideShowCircularMode;
var slideShowStyleSheet;
var slideShowParams;
var clockMultiplier;
var clockInterval;
var clockCorrection=0;
var clockStartTime;
var openTiddlers;

config.macros.slideShow.handler = function(aPlace,macroName,params,wikifier,paramString,tiddler){
 if(tiddler instanceof Tiddler){
 var lingo = config.views.wikified.slideShow;
 var autostart = false;
 if (!e) var e = window.event;
 
 place = aPlace;
 title = tiddler.title;
 params = reparse(paramString);
 var onclick = function(){config.macros.slideShow.onClickSlideShow(params);};
 createTiddlyButton(aPlace,lingo.text,lingo.tooltip,onclick);
 
 var slideShowHolder = document.getElementById('slideShowWrapper');
 //If no show exist previously, create it
 if(params['autostart']){
 if(slideShowHolder != null){
 var signature = slideShowHolder.getAttribute('showSignature');
 if(signature.indexOf("autostart")==-1) autostart = true;
 } else {autostart = true;}
 if(autostart){
 slideShowParams = params;
 setTimeout(config.macros.slideShow.onClickSlideShow,100);
 }
 }
 }
}

var disableFunction = function(e){return false;}
var enableFunction = function(e){}

config.macros.slideShow.onClickSlideShow = function(newParams) {
 if(typeof(newParams)=="number") newParams=slideShowParams;
 openTiddlers = new Array;
 var viewer=document.getElementById('tiddlerDisplay');
 for(var i=0; i<viewer.childNodes.length; i++){
 var name = viewer.childNodes[i].getAttribute('tiddler');
 openTiddlers.push(name);
 }
 document.oncontextmenu = disableFunction;
 clockMultiplier = 1;
 clockInterval = 0;
 var startTime = new Date(0);
 slideShowCircularMode = false;
 time = 0;
 slideShowStyleSheet = null;
 if(newParams['style']){
 slideShowStyleSheet = eval(newParams['style']);
 } 
 if(newParams['repeat']){
 slideShowCircularMode = true;
 }
 if(newParams['slidePause'] > 0){
 time = newParams['slidePause'];
 }
 if(newParams['clock']){
 clockCorrection=startTime.getTimezoneOffset()*60000;
 startTime = new Date();
 var clockType= eval(newParams['clock']);
 if(clockType != '+') {
 clockMultiplier = -1;
 clockInterval = -clockType*60000;
 }
 }
 clockStartTime=startTime.getTime();
 if(newParams['noOverlays']){
 noOverlays = true;
 }
 var contentWrapper = document.getElementById('contentWrapper');
 if (contentWrapper.className != "slideShowMode"){
 clearMessage();
 //Attach the key and mouse listeners
 document.onkeyup = keys;
 document.onmouseup = clicker;
 
 var slideShowHolder = document.getElementById('slideShowWrapper');
 story.refreshTiddler(title,"SlideShowViewTemplate",true);
 //If no show exist previously, create it
 if(slideShowHolder == null){
 createSlides(newParams);
 //If there was once waiting in the background and it matches the one we just started, resume it
 } else if (slideShowHolder.getAttribute('showSignature') == makeSignature(title,newParams)){
 
 //Remove dblClick on edit function
 var theTiddler = document.getElementById("tiddler"+title);
 theTiddler.ondblclick = function() {};

 // Grab the 'viewer' element and give it a signature so the show can be resumed if stopped
 var tiddlerElements = theTiddler.childNodes;
 var viewer;
 for (var i = 0; i < tiddlerElements.length; i++){
 if (tiddlerElements[i].className == "viewer") viewer = tiddlerElements[i];
 }
 theTiddler.insertBefore(slideShowHolder,viewer);
 theTiddler.removeChild(viewer);
 slideShowHolder.style.display = 'block';
 document.getElementById("pageFooter").className = "pageFooterOff";
 
 //If the show we started it totally new than the resumable one, create the new one and kill the resumable one
 } else {
 slideShowHolder.parentNode.removeChild(slideShowHolder);
 createSlides(newParams);
 }
 slideClock=setInterval("setClock()", 1000); 
 if(time>0) autoAdvance=setInterval("GoToSlide(1)", time); 
 story.closeAllTiddlers(title);
 toggleSlideStyles();
 } else {
 endSlideShow();
 }
 return ;
 
}

function endSlideShow(){
 //Set aside show so it can be resumed later
 var showHolder = document.getElementById('slideShowWrapper');
 showHolder.style.display = 'none';
 document.getElementById('contentWrapper').parentNode.appendChild(showHolder);
 document.oncontextmenu = enableFunction;
 if(autoAdvance) clearInterval(autoAdvance);
 if(slideClock) clearInterval(slideClock);
 story.refreshTiddler(title,null,true);
 story.closeAllTiddlers();
 toggleSlideStyles();
 story.displayTiddlers(null,openTiddlers,DEFAULT_VIEW_TEMPLATE);
 document.onmouseup = function(){};
}

function isInteger(s){
 var i;
 for (i = 0; i < s.length; i++){
 // Check that current character is number.
 var c = s.charAt(i);
 if (((c < "0") || (c > "9"))) return false;
 }
 // All characters are numbers.
 return true;
}

function jumpInputToSlide(e){
 if (!e) {
 e = window.event;
 e.which = e.keyCode;
 }
 if(e.which==13){
 var jumpInput= document.getElementById("jumpInput").value;
 if(isInteger(jumpInput)){
 var step=jumpInput-document.getElementById('slideContainer').getAttribute('currentslide')-1;
 if (GoToSlide(step)){
 showHideTOC('none'); 
 }
 }
 }
 return;
}

//Used to shorten the TOC fields
function abbreviateLabel(label){
 var maxTOCLength = config.macros.slideShow.maxTOCLength;
 if(label.length>maxTOCLength) {
 var temp = new Array();
 temp = label.split(' ');
 label = temp[0];
 for(var j=1; j<temp.length; j++){
 if((label.length+temp[j].length)<=maxTOCLength){
 label += " " + temp[j];
 } else {
 label += " ...";
 break;
 }
 }
 }
 return label;
}

createSlides = function(newParams){
 var lingo = config.views.wikified.slideShow;

 //Remove dblClick on edit function
 var theTiddler = document.getElementById("tiddler"+title);
 theTiddler.ondblclick = function() {};

 // Grab the 'viewer' element and give it a signature so the show can be resumed if stopped
 var tiddlerElements = theTiddler.childNodes;
 var viewer;
 for (var i = 0; i < tiddlerElements.length; i++){
 if (tiddlerElements[i].className == "viewer") viewer = tiddlerElements[i];
 }
 viewer.id = 'slideShowWrapper';
 viewer.setAttribute("showSignature",makeSignature(title,newParams));

 //Hide the text that comes before the first H1 element (I think I may put this into a cover page type thing)
 while(viewer.childNodes.length > 0 && viewer.firstChild.nodeName.toUpperCase() != "HR" && viewer.firstChild.className!="slideSeparator") {
 viewer.removeChild(viewer.firstChild);
 }
 
 //Cycle through the content and each time you hit an H1 begin a new slide div
 var slideNumber = 0;
 var slideHolder = document.createElement('DIV');
 slideHolder.id = "slideContainer";
 
 while(viewer.childNodes.length > 0){
 //Create a new slide a append it to the slide holder
 if (viewer.firstChild.nodeName.toUpperCase() == "HR" && viewer.firstChild.className=="slideSeparator"){
 slideNumber++;
 var slide = document.createElement('DIV');
 slide.id = "slideNumber"+slideNumber;
 slide.className = "slide";
 if (slideNumber > 1) {
 slideHolder.setAttribute('currentslide',0);
 slide.style.display='none';
 } else {
 slide.style.display='block';
 }
 slideHolder.appendChild(slide); 
 viewer.removeChild(viewer.firstChild);
 } else {
 if(viewer.firstChild.nodeName=="SPAN" && viewer.firstChild.className=="" && viewer.firstChild.hasChildNodes()) {
 var anchor=viewer.firstChild.nextSibling;
 for (var ii=0;ii<viewer.firstChild.childNodes.length;ii++) {
 var clone=viewer.firstChild.childNodes[ii].cloneNode(true);
 viewer.insertBefore(clone,anchor);
 }
 viewer.removeChild(viewer.firstChild);
 } else {
 slide.appendChild(viewer.firstChild);
 }
 }
 }
 
 //Stick the slides back into the viewer
 viewer.appendChild(slideHolder);
 slideHolder.setAttribute('numberSlides',slideNumber);
 
 //Create the navigation bar
 var pagefooter = createTiddlyElement(viewer,"DIV","pageFooter","pageFooterOff");
 var navigator = createTiddlyElement(pagefooter,"SPAN","navigator");

 //Make it so that when the footer is hovered over the class will change to make it visible
 pagefooter.onmouseover = function () {pagefooter.className = "pageFooterOn"};
 pagefooter.onmouseout = function () {pagefooter.className = "pageFooterOff"};

 //Create the control button for the navigation 
 var onClickQuit = function(){endSlideShow();};
 createTiddlyButton(navigator,lingo.quit.text,lingo.quit.tooltip,onClickQuit);
 createTiddlyButton(navigator,lingo.firstSlide.text,lingo.firstSlide.tooltip,first_slide);
 createTiddlyButton(navigator,lingo.previousSlide.text,lingo.previousSlide.tooltip,previous_slide);
 createTiddlyButton(navigator,lingo.nextSlide.text,lingo.nextSlide.tooltip,next_slide);
 createTiddlyButton(navigator,lingo.lastSlide.text,lingo.lastSlide.tooltip,last_slide); 
 createTiddlyButton(navigator,lingo.resetClock.text,lingo.resetClock.tooltip,resetClock,"button","slideClock"); 

 var indexNumbers = createTiddlyElement(pagefooter,"SPAN","indexNumbers","indexNumbers","1/"+slideNumber)
 indexNumbers.onclick = showHideTOC;
 var toc = createTiddlyElement(pagefooter,"UL","toc");
 var ovl=1;
 for (var i=0;i<slideHolder.childNodes.length;i++) {
 if(!noOverlays) {
 var ovl=1;
 while(1){
 var className="Overlay"+ovl;
 var overlays=getElementsByClass(className,slideHolder.childNodes[i]);
 if(overlays.length>0){
 for(var j=0; j<overlays.length; j++) {overlays[j].className+=' nextOverlay';}
 ovl++;
 } else {break;}
 }
 }
 slideHolder.childNodes[i].setAttribute("numberOverlays",ovl-1);
 slideHolder.setAttribute("currentOverlay",0);

 //Loop through each slide and check the header's content
 var tocLabel = null; 
 for (var j=0;j<slideHolder.childNodes[i].childNodes.length;j++) {
 var node = slideHolder.childNodes[i].childNodes[j];
 if(node.nodeName=="H1" || node.nodeName=="H2" || node.nodeName=="H3" || node.nodeName=="H4") {
 var htstring = node.innerHTML;
 var stripped = htstring.replace(/(<([^>]+)>)/ig,"");
 tocLabel = abbreviateLabel(stripped);
 var tocLevel="tocLevel"+node.nodeName.charAt(1);
 var tocItem = createTiddlyElement(toc,"LI",null,tocLevel);
 var tocLink = createTiddlyElement(tocItem,"A",null,"tocItem",tocLabel);
 tocLink.setAttribute("slideNumber",i);
 tocLink.onclick=tocShowSlide;
 }
 }
 }
 

 //Input box to jump to s specific slide
 var tocItem = createTiddlyElement(toc,"LI",null,"tocJumpItem",config.macros.slideShow.messages.gotoLabel);
 var tocJumpInput = createTiddlyElement(tocItem,"INPUT","jumpInput");
 tocJumpInput.type="text";
 tocJumpInput.onkeyup=jumpInputToSlide;
}

var next_slide= function(e){GoToSlide(1);}
var first_slide= function(e){GoToSlide("f");}
var previous_slide= function(e){GoToSlide(-1);}
var last_slide= function(e){GoToSlide("l");}

function toggleSlideStyles(){
 var contentWrapper = document.getElementById('contentWrapper');
 if (contentWrapper.className == "slideShowMode"){
 contentWrapper.className = "";
 window.applyPageTemplate();
 if(slideShowStyleSheet) changeStyleSheet();
 } else{
 contentWrapper.className = "slideShowMode";
 window.applyPageTemplate("SlideShowPageTemplate");
 if(slideShowStyleSheet) changeStyleSheet(slideShowStyleSheet);
 }
}

setStylesheet("/***\n!Slide Mode Styles\n***/\n/*{{{*/\n#contentWrapper.slideShowMode #slideContainer{\n display: block;\n}\n\n#contentWrapper.slideShowMode .Comment{\n display: none;\n}\n\n#contentWrapper.slideShowMode .nextOverlay{\n visibility: hidden;\n}\n\n#contentWrapper.slideShowMode .currentOverlay{\n visibility: visible;\n}\n\n#contentWrapper.slideShowMode .previousOverlay{\n visibility: visible;\n}\n\n#jump{\n text-align: right;\n}\n\n.pageFooterOff #navigator{\n visibility: hidden;\n}\n\n.pageFooterOn #navigator{\n visibility: visible;\n}\n\n#contentWrapper.slideShowMode #slideClock{\n cursor: pointer; margin: 0 5px 0 5px; border: 1px solid #db4\n}\n\n#contentWrapper.slideShowMode,\n #contentWrapper.slideShowMode #displayArea{\n width: 100%;\n font-size: 1.5em;\n margin: 0 !important;\n padding: 0;\n}\n\n#slideContainer{\n display: none;\n}\n\n.indexNumbers{\n cursor: pointer;\n}\n\n#navigator{\n visibility: hidden;\n bottom: 0;\n}\n\n#toc{\n display: none;\n position: absolute;\n font-size: .75em;\n bottom: 2em;\n right: 0;\n background: #fff;\n border: 1px solid #000;\n text-align: left;\n}\n\nul#toc, #toc li{\n margin: 0;\n padding: 0;\n list-style: none;\n line-height: 1em;\n}\n\n.tocJumpItem{\n margin-right: 2em;\n}\n\n.tocJumpItem input{\nmargin-right: 1em;\n border: 0;\n}\n\n#toc a,\n#toc a.button{\n display: block;\n padding: .1em;\n}\n\n#toc .tocLevel1{\nfont-size: .8em;\n}\n\n#toc .tocLevel2{\n margin-left: 1em;\n font-size: .75em;\n}\n\n#toc .tocLevel3{\n margin-left: 2em;\nfont-size: .75em;\n}\n\n#toc .tocLevel4{\n margin-left: 3em;\nfont-size: .65em;\n}\n\n#toc a{\n cursor: pointer;\n}\n\nh1{\n min-height: 1em;\n}\n\n.slide h1{\n min-height: 0;\n}\n\n/* The '&gt;' selector is ignored by IE6 and earlier so the proper rules are given */\n#pageFooter{\n position: fixed;\n bottom: 2px;\n right: 2px;\n width: 100%;\n text-align: right;\n}\n\n/* This is a hack to trick IE6 and earlier to put the navbar on the bottom of the page */\n* html #pageFooter {\n position: absolute;\n width: 100%;\n text-align: right;\n right: auto; bottom: auto;\n left: expression( ( -20 - pageFooter.offsetWidth + ( document.documentElement.clientWidth ? document.documentElement.clientWidth : document.body.clientWidth ) + ( ignoreMe2 = document.documentElement.scrollLeft ? document.documentElement.scrollLeft : document.body.scrollLeft ) ) + 'px' );\n top: expression( ( -10 - pageFooter.offsetHeight + ( document.documentElement.clientHeight ? document.documentElement.clientHeight : document.body.clientHeight ) + ( ignoreMe = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop ) ) + 'px' );\n}\n\n\n\n/*}}}*/","slideShowStyles");
//}}}
!Description
This plugin turns a TiddlyWiki tiddler into a simple slide show type display. Most features that are usually found in presentation software are available. It should work in a way that does not interfere with TiddlyWiki. When you close the slide show you get back to your good old TW. 

This plugin has been tested in Firefox and Internet Explorer. Let me know if something seems broken.
!Usage
To use this plugin you //must// be using TiddlyWiki 2.0. Some optional features (as the incremental display) require version 2.0.8 or higher. To install the plugin copy the tiddlers SlideShowPlugin, SlideShowPageTemplate and SlideShowViewTemplate to your TW, label the first one with the //systemConfig// tag, save the TW and refresh the browser.

To make a slide show simply drop {{{<<slideShow>>}}} at the beginning of a tiddler and use {{{--s--}}} to start each slide. 

If you move your mouse over the bottom of the browser window you will see a few navigation buttons, a clock and a table of contents that shows up when you click the slide number.

Any block of text marked as {{{{{Comment{For my eyes only!}}}}}} will not be displayed in the slide show.

See these and other features in this [[SlideShowExample]].
!Incremental display
A succession of overlays (or layers) can be defined in each slide by marking blocks of text with {{{{{Overlay1{...some text...}}}}}}, {{{{{Overlay2{...some text...}}}}}}, {{{{{Overlay3{...some text...}}}}}}, ...

To costumize the way overlays are shown you can redefine the following CSS classes
*contentWrapper.slideShowMode .previousOverlay 
*contentWrapper.slideShowMode .currentOverlay 
*contentWrapper.slideShowMode .nextOverlay 
in a ~StyleSheet. The default style simply hides the next overlays and shows the current and the previous ones as normal text.
!Slide show parameters
*The slide show can be themed by providing a ~StyleSheet ({{{<<slideShow style:'MyStyleSheet'>>}}})
*By default, there is a clock at bottom of the browser window that displays the current time. This clock can also show the presentation elapsed time with {{{<<slideShow clock:'+'>>}}} or a countdown clock with {{{<<slideShow clock:'-20'>>}}} (for 20 minutes). In these two cases, if you click on the clock display it will be restarted
*The slide show can be set to loop ({{{<<slideShow repeat>>}}})
*You can set it so each slide changes after X milliseconds ({{{<<slideShow slidePause:X>>}}}) (auto advance mode)
*Use auto start mode to begin the slideshow the moment the tiddler is opened ({{{<<slideShow autostart>>>}}})
*You can disable overlays with {{{<<slideShow noOverlays>>}}}
*These parameters can be mixed and matched in any order: {{{<<slideShow slidePause:1000 repeat>>}}} is the same as {{{<<slideShow repeat slidePause:1000>>}}}
!Slide show navigation
You can navigate through a slide show using the keyboard or the mouse. To quickly move to titled sections you can use the table of contents. 
!!Mouse navigation
Left (right) clicking on a slide jumps to the next (previous) overlay. To move to the beginning of the next or previous slide you must use the navigation bar at the bottom of the browser's window. If there are no overlays defined both operations are equivalent.
!!Keyboard navigation
The following keys are defined:
*Left arrow - previous overlay
*Down arrow - previous slide
*Right arrow - next overlay
*Up arrow - next slide
*Home - first slide
*End - last slide
*Escape - exit slide show
*Spacebar - pause/resume slide show in auto advance mode
!Revision history
*1.5.1 10/11/2006
**added SlideShowPageTemplate and SlideShowViewTemplate. This way, the plugin no longer requires a standard TW layout. Thanks to Andrew Lister for the idea.
*1.5.0 18/09/2006
**fixed restoring stylesheet on exit
**changed (again!) the way how slides are separated (slide shows prepared for previous versions must be fixed)
*1.4.0 20/04/2006
**changed the way how slides are separated (slide shows prepared for previous versions must be fixed)
**now works with content included with the {{{<<tiddler>>}}} macro
**added incremental display (overlays)
**improved documentation
**assorted small fixes
*1.3.1 10/03/2006
**removed empty slide titles
**fixed wrong numberSlides when slides have div's
**fixed wrong time in Windows
*1.3.0 26/02/2006
**restore open tiddlers on exit
**fixed problem with markup in headers (should work with NestedSlidersPlugin)
**added slide comments (blocks of text in the tiddler that don't show up in the presentation)
*1.2.1 28/01/2006
**pause timed slideshow with spacebar
**added clock with 3 different modes
**fixed bugs with style and abbreviation options
**general cleanup
*1.2.0 07/01/2006
**added a resume feature
**added themes support
*1.1.5 14/12/2005
**added mouse support
**cleaned up navbar generation
*1.1.0 12/12/2005
**added support for IE
**added key listeners
*1.0.0 11/12/2005
**initial release
!Todo
*Time code is still very hackerish and unreliable.
<!--{{{-->
<div class='title' macro='view title' style='font-size: 1em;'></div>
<div class='viewer' macro='view text wikified'></div>
<!--}}}-->
/*{{{*/
@media print {
#mainMenu, #sidebar, #messageArea, .toolbar, #backstageButton, .siteTitle, .siteSubtitle {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;}
}
/*}}}*/
[img[cayley-tables/s3.png]]
!Spring 2009
**[[Test 2 Review Guide|tests/mat336spring09Test2ReviewGuide.pdf]]
**[[Test 2 Sample|tests/mat336spring09SampleTest2.pdf]]
**[[Final Exam Review Guide|tests/mat336spring09FinalReviewGuide.pdf]]
**[[Final Example Sample|tests/mat336spring09-SampleFinalExam-2009Apr21-b.pdf]]
!Fall 2008
**[[Test 1 Review Guide|tests/mat336fall08Test1ReviewGuide.pdf]]
**[[Test 1 Sample|tests/mat336fall08SampleTest1--2008Sep22-2009Feb10.pdf]]
**[[Test 2 Review Guide|tests/mat336fall08Test2ReviewGuide.pdf]]
**[[Test 2 Sample|tests/mat336fall08SampleTest2.pdf]]
**[[Test 2 Supplement|tests/mat336fall08Test2Supplement.pdf]]
**[[Final Exam Sample|tests/mat336fall08-SampleFinalExam-2008Nov25.pdf]]
!Fall 2006
**[[Test 1 (pdf)|tests/mat336fall06SampleExam1ver1.pdf]]
**[[Test 2 (pdf)|tests/mat336fall06SampleExam2ver1.pdf]]
**[[Final Exam (pdf)|tests/mat336fall06FinalExamReviewVer1.pdf]]

/***

|Name|ToggleSideBarMacro|
|Created by|SaqImtiaz|
|Location|http://tw.lewcid.org/#ToggleSideBarMacro|
|Version|1.0|
|Requires|~TW2.x|
!Description:
Provides a button for toggling visibility of the SideBar. You can choose whether the SideBar should initially be hidden or displayed.

!Demo
<<toggleSideBar "Toggle Sidebar">>

!Usage:
{{{<<toggleSideBar>>}}} <<toggleSideBar>>
additional options:
{{{<<toggleSideBar label tooltip show/hide>>}}} where:
label = custom label for the button,
tooltip = custom tooltip for the button,
show/hide = use one or the other, determines whether the sidebar is shown at first or not.
(default is to show the sidebar)

You can add it to your tiddler toolbar, your MainMenu, or where you like really.
If you are using a horizontal MainMenu and want the button to be right aligned, put the following in your StyleSheet:
{{{ .HideSideBarButton {float:right;} }}}

!History
*23-07-06: version 1.0: completely rewritten, now works with custom stylesheets too, and easier to customize start behaviour. 
*20-07-06: version 0.11
*27-04-06: version 0.1: working.

!Code
***/
//{{{
config.macros.toggleSideBar={};

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

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

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

     return false;
}

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

//}}}