sitestats "; // Create the iframe var iframe = document.createElement("iframe"); iframe.style.display = "none"; importer.insertBefore(iframe,importer.firstChild); var doc = iframe.document; if(iframe.contentDocument) doc = iframe.contentDocument; // For NS6 else if(iframe.contentWindow) doc = iframe.contentWindow.document; // For IE5.5 and IE6 // Put the content in the iframe doc.open(); doc.writeln(content); doc.close(); // Load the content into a TiddlyWiki() object var storeArea = doc.getElementById("storeArea"); var importStore = new TiddlyWiki(); importStore.loadFromDiv(storeArea,"store"); // Get rid of the iframe iframe.parentNode.removeChild(iframe); // Extract data for the listview var tiddlers = []; importStore.forEachTiddler(function(title,tiddler) { var t = {}; t.title = title; t.modified = tiddler.modified; t.modifier = tiddler.modifier; t.text = tiddler.text.substr(0,50); t.tags = tiddler.tags; tiddlers.push(t); }); // Display the listview createTiddlyElement(importer,"h2",null,"step3",config.macros.importTiddlers.step3); var step = createTiddlyElement(importer,"div",null,"wizardStep"); ListView.create(step,tiddlers,config.macros.importTiddlers.listViewTemplate,config.macros.importTiddlers.onSelectCommand); // Save the importer importer.store = importStore; } config.macros.importTiddlers.onSelectCommand = function(listView,command,rowNames) { var importer = findRelated(listView,"importTiddler","className","parentNode"); switch(command) { case "import": config.macros.importTiddlers.doImport(importer,rowNames); break; } if(config.options.chkAutoSave) saveChanges(true); } config.macros.importTiddlers.doImport = function(importer,rowNames) { var theStore = importer.store; var overwrite = new Array(); var t; for(t=0; t 0) if(!confirm(this.confirmOverwriteText.format([overwrite.join(", ")]))) return; for(t=0; t"); s.push("" + this.title.htmlEncode() + ""); s.push("" + wikifyStatic(this.text,null,this).htmlEncode() + ""); for(var t=0; t" + this.tags[t] + ""); s.push("" + url + "#" + encodeURIComponent(String.encodeTiddlyLink(this.title)) + ""); s.push("" + this.modified.toGMTString() + ""); s.push(""); return(s.join("\n")); } // Change the text and other attributes of a tiddler Tiddler.prototype.set = function(title,text,modifier,modified,tags,created,fields) { this.assign(title,text,modifier,modified,tags,created,fields); this.changed(); return this; } // Change the text and other attributes of a tiddler without triggered a tiddler.changed() call Tiddler.prototype.assign = function(title,text,modifier,modified,tags,created,fields) { if(title != undefined) this.title = title; if(text != undefined) this.text = text; if(modifier != undefined) this.modifier = modifier; if(modified != undefined) this.modified = modified; if(created != undefined) this.created = created; if(fields != undefined) this.fields = fields; if(tags != undefined) this.tags = (typeof tags == "string") ? tags.readBracketedList() : tags; else if(this.tags == undefined) this.tags = []; return this; } // Get the tags for a tiddler as a string (space delimited, using [[brackets]] for tags containing spaces) Tiddler.prototype.getTags = function() { return String.encodeTiddlyLinkList(this.tags); } // Test if a tiddler carries a tag Tiddler.prototype.isTagged = function(tag) { return this.tags.find(tag) != null; } // Static method to convert "\n" to newlines, "\s" to "\" Tiddler.unescapeLineBreaks = function(text) { return text ? text.unescapeLineBreaks() : ""; } // Convert newlines to "\n", "\" to "\s" Tiddler.prototype.escapeLineBreaks = function() { return this.text.escapeLineBreaks(); } // Updates the secondary information (like links[] array) after a change to a tiddler Tiddler.prototype.changed = function() { this.links = []; var t = this.autoLinkWikiWords() ? 0 : 1; var tiddlerLinkRegExp = t==0 ? config.textPrimitives.tiddlerAnyLinkRegExp : config.textPrimitives.tiddlerForcedLinkRegExp; tiddlerLinkRegExp.lastIndex = 0; var formatMatch = tiddlerLinkRegExp.exec(this.text); while(formatMatch) { if(t==0 && formatMatch[1] && formatMatch[1] != this.title) // wikiWordLink { if(formatMatch.index > 0) { var preRegExp = new RegExp(config.textPrimitives.unWikiLink+"|"+config.textPrimitives.anyLetter,"mg"); preRegExp.lastIndex = formatMatch.index-1; var preMatch = preRegExp.exec(this.text); if(preMatch.index != formatMatch.index-1) this.links.pushUnique(formatMatch[1]); } else this.links.pushUnique(formatMatch[1]); } else if(formatMatch[2-t] && (store.tiddlerExists(formatMatch[3-t]) || store.isShadowTiddler(formatMatch[3-t]))) // titledBrackettedLink this.links.pushUnique(formatMatch[3-t]); else if(formatMatch[4-t] && formatMatch[4-t] != this.title) // brackettedLink this.links.pushUnique(formatMatch[4-t]); // Do not add link if match urlPattern (formatMatch[5-t]) formatMatch = tiddlerLinkRegExp.exec(this.text); } this.linksUpdated = true; return; } Tiddler.prototype.getSubtitle = function() { var theModifier = this.modifier; if(!theModifier) theModifier = config.messages.subtitleUnknown; var theModified = this.modified; if(theModified) theModified = theModified.toLocaleString(); else theModified = config.messages.subtitleUnknown; return(config.messages.tiddlerLinkTooltip.format([this.title,theModifier,theModified])); } Tiddler.prototype.isReadOnly = function() { return readOnly; } Tiddler.prototype.autoLinkWikiWords = function() { return !(this.isTagged("systemConfig") || this.isTagged("excludeMissing")); } Tiddler.prototype.generateFingerprint = function() { return "0x" + Crypto.hexSha1Str(this.text); } // --------------------------------------------------------------------------------- // TiddlyWiki() object contains Tiddler()s // --------------------------------------------------------------------------------- function TiddlyWiki() { var tiddlers = {}; // Hashmap by name of tiddlers this.tiddlersUpdated = false; this.namedNotifications = []; // Array of {name:,notify:} of notification functions this.notificationLevel = 0; this.slices = {}; // map tiddlerName->(map sliceName->sliceValue). Lazy. this.clear = function() { tiddlers = {}; this.setDirty(false); }; this.fetchTiddler = function(title) { return tiddlers[title]; }; this.deleteTiddler = function(title) { delete this.slices[title]; delete tiddlers[title]; }; this.addTiddler = function(tiddler) { delete this.slices[tiddler.title]; tiddlers[tiddler.title] = tiddler; }; this.forEachTiddler = function(callback) { for(var t in tiddlers) { var tiddler = tiddlers[t]; if(tiddler instanceof Tiddler) callback.call(this,t,tiddler); } }; } // Set the dirty flag TiddlyWiki.prototype.setDirty = function(dirty) { this.dirty = dirty; } TiddlyWiki.prototype.isDirty = function() { return this.dirty; } TiddlyWiki.prototype.suspendNotifications = function() { this.notificationLevel--; } TiddlyWiki.prototype.resumeNotifications = function() { this.notificationLevel++; } // Invoke the notification handlers for a particular tiddler TiddlyWiki.prototype.notify = function(title,doBlanket) { if(!this.notificationLevel) for(var t=0; tString value = value instanceof Date ? value.convertToYYYYMMDDHHMMSSMMM() : String(value); if (oldValue == value) return; t.fields[fieldName] = value; } } // When we are here the tiddler/store really was changed. this.notify(t.title,true); if (!fieldName.match(/^temp\./)) this.setDirty(true); } // Returns the value of the given field of the tiddler. // The fieldName is case-insensitive. // Will only return String values (or undefined). TiddlyWiki.prototype.getValue = function(tiddler, fieldName) { var t = this.resolveTiddler(tiddler); if (!t) return undefined; fieldName = fieldName.toLowerCase(); var accessor = TiddlyWiki.standardFieldAccess[fieldName]; if (accessor) { return accessor.get(t); } return t.fields ? t.fields[fieldName] : undefined; } // Calls the callback function for every field in the tiddler. // // When callback function returns a non-false value the iteration stops // and that value is returned. // // The order of the fields is not defined. // // @param callback a function(tiddler, fieldName, value). // TiddlyWiki.prototype.forEachField = function(tiddler, callback, onlyExtendedFields) { var t = this.resolveTiddler(tiddler); if (!t) return undefined; if (t.fields) { for (var n in t.fields) { var result = callback(t, n, t.fields[n]); if (result) return result; } } if (onlyExtendedFields) return undefined; for (var n in TiddlyWiki.standardFieldAccess) { if (n == "tiddler") // even though the "title" field can also be referenced through the name "tiddler" // we only visit this field once. continue; var result = callback(t, n, TiddlyWiki.standardFieldAccess[n].get(t)); if (result) return result; } return undefined; }; // --------------------------------------------------------------------------------- // Story functions // --------------------------------------------------------------------------------- // A story is a HTML div containing a sequence of tiddlers that can be manipulated // container - id of containing element // idPrefix - string prefix prepended to title to make ids for tiddlers in this story function Story(container,idPrefix) { this.container = container; this.idPrefix = idPrefix; this.highlightRegExp = null; } // Iterate through all the tiddlers in a story // fn - callback function to be called for each tiddler. Arguments are: // tiddler - reference to Tiddler object // element - reference to tiddler display element Story.prototype.forEachTiddler = function(fn) { var place = document.getElementById(this.container); if(!place) return; var e = place.firstChild; while(e) { var n = e.nextSibling; var title = e.getAttribute("tiddler"); fn.call(this,title,e); e = n; } } // Display several tiddlers given their titles in an array. Parameters same as displayTiddler(), except: // titles - array of string titles Story.prototype.displayTiddlers = function(srcElement,titles,template,animate,slowly) { for(var t = titles.length-1;t>=0;t--) this.displayTiddler(srcElement,titles[t],template,animate,slowly); } // Display a given tiddler with a given template. If the tiddler is already displayed but with a different // template, it is switched to the specified template // srcElement - reference to element from which this one is being opened -or- // special positions "top", "bottom" // title - title of tiddler to display // template - the name of the tiddler containing the template -or- // one of the constants DEFAULT_VIEW_TEMPLATE and DEFAULT_EDIT_TEMPLATE -or- // null or undefined to indicate the current template if there is one, DEFAULT_VIEW_TEMPLATE if not // animate - whether to perform animations // slowly - whether to perform animations in slomo Story.prototype.displayTiddler = function(srcElement,title,template,animate,slowly) { var place = document.getElementById(this.container); var theTiddler = document.getElementById(this.idPrefix + title); if(theTiddler) this.refreshTiddler(title,template); else { var before = this.positionTiddler(srcElement); theTiddler = this.createTiddler(place,before,title,template); } if(srcElement && typeof srcElement !== "string") { if(anim && config.options.chkAnimate && (animate == undefined || animate == true)) anim.startAnimating(new Cascade(title,srcElement,theTiddler,slowly),new Scroller(theTiddler,slowly)); else window.scrollTo(0,ensureVisible(theTiddler)); } } // Figure out the appropriate position for a newly opened tiddler // srcElement - reference to the element containing the link to the tiddler -or- // special positions "top", "bottom" // returns - reference to the tiddler that the new one should appear before (null for the bottom of the story) Story.prototype.positionTiddler = function(srcElement) { var place = document.getElementById(this.container); var before; if(typeof srcElement == "string") { switch(srcElement) { case "top": before = place.firstChild; break; case "bottom": before = null; break; } } else { var after = this.findContainingTiddler(srcElement); if(after == null) before = place.firstChild; else if(after.nextSibling) before = after.nextSibling; else before = null; } return before; } // Create a tiddler frame at the appropriate place in a story column // place - reference to parent element // before - null, or reference to element before which to insert new tiddler // title - title of new tiddler // template - the name of the tiddler containing the template or one of the constants DEFAULT_VIEW_TEMPLATE and DEFAULT_EDIT_TEMPLATE Story.prototype.createTiddler = function(place,before,title,template) { var theTiddler = createTiddlyElement(null,"div",this.idPrefix + title,"tiddler"); theTiddler.setAttribute("refresh","tiddler"); place.insertBefore(theTiddler,before); this.refreshTiddler(title,template); return theTiddler; } // Overridable for choosing the name of the template to apply for a tiddler Story.prototype.chooseTemplateForTiddler = function(title,template) { if(!template) template = DEFAULT_VIEW_TEMPLATE; if(template == DEFAULT_VIEW_TEMPLATE || template == DEFAULT_EDIT_TEMPLATE) template = config.tiddlerTemplates[template]; return template; } // Overridable for extracting the text of a template from a tiddler Story.prototype.getTemplateForTiddler = function(title,template,tiddler) { return store.getRecursiveTiddlerText(template,null,10); } // Apply a template to an existing tiddler if it is not already displayed using that template // title - title of tiddler to update // template - the name of the tiddler containing the template or one of the constants DEFAULT_VIEW_TEMPLATE and DEFAULT_EDIT_TEMPLATE // force - if true, forces the refresh even if the template hasn't changedd Story.prototype.refreshTiddler = function(title,template,force) { var theTiddler = document.getElementById(this.idPrefix + title); if(theTiddler) { if(theTiddler.getAttribute("dirty") == "true" && !force) return theTiddler; template = this.chooseTemplateForTiddler(title,template); var currTemplate = theTiddler.getAttribute("template"); if((template != currTemplate) || force) { var tiddler = store.getTiddler(title); if(!tiddler) { tiddler = new Tiddler(); if(store.isShadowTiddler(title)) tiddler.set(title,store.getTiddlerText(title),config.views.wikified.shadowModifier,version.date,[],version.date); else { var text = template=="EditTemplate" ? config.views.editor.defaultText.format([title]) : config.views.wikified.defaultText.format([title]); tiddler.set(title,text,config.views.wikified.defaultModifier,version.date,[],version.date); } } theTiddler.setAttribute("tags",tiddler.tags.join(" ")); theTiddler.setAttribute("tiddler",title); theTiddler.setAttribute("template",template); var me = this; theTiddler.onmouseover = this.onTiddlerMouseOver; theTiddler.onmouseout = this.onTiddlerMouseOut; theTiddler.ondblclick = this.onTiddlerDblClick; theTiddler[window.event?"onkeydown":"onkeypress"] = this.onTiddlerKeyPress; var html = this.getTemplateForTiddler(title,template,tiddler); theTiddler.innerHTML = html; applyHtmlMacros(theTiddler,tiddler); if(store.getTaggedTiddlers(title).length > 0) addClass(theTiddler,"isTag"); else removeClass(theTiddler,"isTag"); if(!store.tiddlerExists(title)) { if(store.isShadowTiddler(title)) addClass(theTiddler,"shadow"); else addClass(theTiddler,"missing"); } else { removeClass(theTiddler,"shadow"); removeClass(theTiddler,"missing"); } } } return theTiddler; } // Refresh all tiddlers in the Story Story.prototype.refreshAllTiddlers = function() { var place = document.getElementById(this.container); var e = place.firstChild; this.refreshTiddler(e.getAttribute("tiddler"),e.getAttribute("template"),true); while((e = e.nextSibling) != null) this.refreshTiddler(e.getAttribute("tiddler"),e.getAttribute("template"),true); } // Default tiddler onmouseover/out event handlers Story.prototype.onTiddlerMouseOver = function(e) { if(window.addClass instanceof Function) addClass(this,"selected"); } Story.prototype.onTiddlerMouseOut = function(e) { if(window.removeClass instanceof Function) removeClass(this,"selected"); } // Default tiddler ondblclick event handler Story.prototype.onTiddlerDblClick = function(e) { if (!e) var e = window.event; var theTarget = resolveTarget(e); if(theTarget && theTarget.nodeName.toLowerCase() != "input" && theTarget.nodeName.toLowerCase() != "textarea") { if(document.selection && document.selection.empty) document.selection.empty(); config.macros.toolbar.invokeCommand(this,"defaultCommand",e); e.cancelBubble = true; if (e.stopPropagation) e.stopPropagation(); return true; } else return false; } Story.prototype.onTiddlerKeyPress = function(e) { if (!e) var e = window.event; clearMessage(); var consume = false; var title = this.getAttribute("tiddler"); var target = resolveTarget(e); switch(e.keyCode) { case 9: // Tab if(config.options.chkInsertTabs && target.tagName.toLowerCase() == "textarea") { replaceSelection(target,String.fromCharCode(9)); consume = true; } if(config.isOpera) { target.onblur = function() { this.focus(); this.onblur = null; } } break; case 13: // Ctrl-Enter case 10: // Ctrl-Enter on IE PC case 77: // Ctrl-Enter is "M" on some platforms if(e.ctrlKey) { blurElement(this); config.macros.toolbar.invokeCommand(this,"defaultCommand",e); consume = true; } break; case 27: // Escape blurElement(this); config.macros.toolbar.invokeCommand(this,"cancelCommand",e); consume = true; break; } e.cancelBubble = consume; if(consume) { if (e.stopPropagation) e.stopPropagation(); // Stop Propagation e.returnValue = true; // Cancel The Event in IE if (e.preventDefault ) e.preventDefault(); // Cancel The Event in Moz } return(!consume); }; // Returns the specified field (input or textarea element) in a tiddler, otherwise the first edit field it finds // or null if it found no edit field at all Story.prototype.getTiddlerField = function(title,field) { var tiddler = document.getElementById(this.idPrefix + title); var e = null; if(tiddler != null) { var children = tiddler.getElementsByTagName("*"); for (var t=0; t=0; t--) titles.push(matches[t].title); this.displayTiddlers(null,titles); highlightHack = null; var q = useRegExp ? "/" : "'"; if(matches.length > 0) displayMessage(config.macros.search.successMsg.format([titles.length.toString(),q + text + q])); else displayMessage(config.macros.search.failureMsg.format([q + text + q])); } // Determine if the specified element is within a tiddler in this story // e - reference to an element // returns: reference to a tiddler element or null if none Story.prototype.findContainingTiddler = function(e) { while(e && !hasClass(e,"tiddler")) e = e.parentNode; return(e); } // Gather any saveable fields from a tiddler element // e - reference to an element to scan recursively // fields - object to contain gathered field values Story.prototype.gatherSaveFields = function(e,fields) { if(e && e.getAttribute) { var f = e.getAttribute("edit"); if(f) fields[f] = e.value.replace(/\r/mg,"");; if(e.hasChildNodes()) { var c = e.childNodes; for(var t=0; t=0; t--) stash.appendChild(nodes[t]); } var wrapper = document.getElementById("contentWrapper"); if(!title) title = "PageTemplate"; var html = store.getRecursiveTiddlerText(title,null,10); wrapper.innerHTML = html; applyHtmlMacros(wrapper); refreshElements(wrapper); display = document.getElementById("tiddlerDisplay"); removeChildren(display); if(!display) display = createTiddlyElement(wrapper,"div","tiddlerDisplay"); nodes = stash.childNodes; for(t=nodes.length-1; t>=0; t--) display.appendChild(nodes[t]); stash.parentNode.removeChild(stash); } function refreshDisplay(hint) { var e = document.getElementById("contentWrapper"); if(typeof hint == "string") hint = [hint]; refreshElements(e,hint); } function refreshPageTitle() { document.title = wikifyPlain("SiteTitle") + " - " + wikifyPlain("SiteSubtitle"); } function refreshStyles(title) { setStylesheet(title == null ? "" : store.getRecursiveTiddlerText(title,"",10),title); } function refreshColorPalette(title) { if(!startingUp) refreshAll(); } function refreshAll() { refreshPageTemplate(); refreshDisplay(); refreshStyles("StyleSheetLayout"); refreshStyles("StyleSheetColors"); refreshStyles("StyleSheet"); refreshStyles("StyleSheetPrint"); } // --------------------------------------------------------------------------------- // Options cookie stuff // --------------------------------------------------------------------------------- function loadOptionsCookie() { if(safeMode) return; var cookies = document.cookie.split(";"); for(var c=0; c'; // Split up into two so that indexOf() of this source doesn't find it var endSaveArea = ''; // If there are unsaved changes, force the user to confirm before exitting function confirmExit() { hadConfirmExit = true; if(store && store.isDirty && store.isDirty()) return config.messages.confirmExit; } // Give the user a chance to save changes before exitting function checkUnsavedChanges() { if(store && store.isDirty && store.isDirty() && window.hadConfirmExit === false) { if(confirm(config.messages.unsavedChangesWarning)) saveChanges(); } } function updateMarkupBlock(s,blockName,tiddlerName) { return s.replaceChunk( "".format([blockName]), "".format([blockName]), "\n" + store.getRecursiveTiddlerText(tiddlerName,"") + "\n"); } // Save this tiddlywiki with the pending changes function saveChanges(onlyIfDirty) { if(onlyIfDirty && !store.isDirty()) return; clearMessage(); // Get the URL of the document var originalPath = document.location.toString(); // Check we were loaded from a file URL if(originalPath.substr(0,5) != "file:") { alert(config.messages.notFileUrlError); if(store.tiddlerExists(config.messages.saveInstructions)) displayTiddler(null,config.messages.saveInstructions); return; } var localPath = getLocalPath(originalPath); // Load the original file var original = loadFile(localPath); if(original == null) { alert(config.messages.cantSaveError); if(store.tiddlerExists(config.messages.saveInstructions)) displayTiddler(null,config.messages.saveInstructions); return; } // Locate the storeArea div's var posOpeningDiv = original.indexOf(startSaveArea); var limitClosingDiv = original.indexOf(" "x:\path\path\path..." // "file://///server/share/path/path/path..." - FireFox pc network file --> "\\server\share\path\path\path..." // "file:///path/path/path..." - mac/unix local file --> "/path/path/path..." // "file://server/share/path/path/path..." - pc network file --> "\\server\share\path\path\path..." var localPath; if(originalPath.charAt(9) == ":") // pc local file localPath = unescape(originalPath.substr(8)).replace(new RegExp("/","g"),"\\"); else if(originalPath.indexOf("file://///") == 0) // FireFox pc network file localPath = "\\\\" + unescape(originalPath.substr(10)).replace(new RegExp("/","g"),"\\"); else if(originalPath.indexOf("file:///") == 0) // mac/unix local file localPath = unescape(originalPath.substr(7)); else if(originalPath.indexOf("file:/") == 0) // mac/unix local file localPath = unescape(originalPath.substr(5)); else // pc network file localPath = "\\\\" + unescape(originalPath.substr(7)).replace(new RegExp("/","g"),"\\"); return localPath; } function getBackupPath(localPath) { var backSlash = true; var dirPathPos = localPath.lastIndexOf("\\"); if(dirPathPos == -1) { dirPathPos = localPath.lastIndexOf("/"); backSlash = false; } var backupFolder = config.options.txtBackupFolder; if(!backupFolder || backupFolder == "") backupFolder = "."; var backupPath = localPath.substr(0,dirPathPos) + (backSlash ? "\\" : "/") + backupFolder + localPath.substr(dirPathPos); backupPath = backupPath.substr(0,backupPath.lastIndexOf(".")) + "." + (new Date()).convertToYYYYMMDDHHMMSSMMM() + ".html"; return backupPath; } function generateRss() { var s = []; var d = new Date(); var u = store.getTiddlerText("SiteUrl"); // Assemble the header s.push("<" + "?xml version=\"1.0\"?" + ">"); s.push(""); s.push(""); s.push("" + wikifyPlain("SiteTitle").htmlEncode() + ""); if(u) s.push("" + u.htmlEncode() + ""); s.push("" + wikifyPlain("SiteSubtitle").htmlEncode() + ""); s.push("en-us"); s.push("Copyright " + d.getFullYear() + " " + config.options.txtUserName.htmlEncode() + ""); s.push("" + d.toGMTString() + ""); s.push("" + d.toGMTString() + ""); s.push("http://blogs.law.harvard.edu/tech/rss"); s.push("TiddlyWiki " + version.major + "." + version.minor + "." + version.revision + ""); // The body var tiddlers = store.getTiddlers("modified","excludeLists"); var n = config.numRssItems > tiddlers.length ? 0 : tiddlers.length-config.numRssItems; for (var t=tiddlers.length-1; t>=n; t--) s.push(tiddlers[t].saveToRss(u)); // And footer s.push(""); s.push(""); // Save it all return s.join("\n"); } // UTF-8 encoding rules: // 0x0000 - 0x007F: 0xxxxxxx // 0x0080 - 0x07FF: 110xxxxx 10xxxxxx // 0x0800 - 0xFFFF: 1110xxxx 10xxxxxx 10xxxxxx function convertUTF8ToUnicode(u) { if(window.netscape == undefined) return manualConvertUTF8ToUnicode(u); else return mozConvertUTF8ToUnicode(u); } function manualConvertUTF8ToUnicode(utf) { var uni = utf; var src = 0; var dst = 0; var b1, b2, b3; var c; while(src < utf.length) { b1 = utf.charCodeAt(src++); if(b1 < 0x80) dst++; else if(b1 < 0xE0) { b2 = utf.charCodeAt(src++); c = String.fromCharCode(((b1 & 0x1F) << 6) | (b2 & 0x3F)); uni = uni.substring(0,dst++).concat(c,utf.substr(src)); } else { b2 = utf.charCodeAt(src++); b3 = utf.charCodeAt(src++); c = String.fromCharCode(((b1 & 0xF) << 12) | ((b2 & 0x3F) << 6) | (b3 & 0x3F)); uni = uni.substring(0,dst++).concat(c,utf.substr(src)); } } return(uni); } function mozConvertUTF8ToUnicode(u) { try { netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); var converter = Components.classes["@mozilla.org/intl/scriptableunicodeconverter"].createInstance(Components.interfaces.nsIScriptableUnicodeConverter); converter.charset = "UTF-8"; } catch(e) { return manualConvertUTF8ToUnicode(u); } // fallback var s = converter.ConvertToUnicode(u); var fin = converter.Finish(); return (fin.length > 0) ? s+fin : s; } function convertUnicodeToUTF8(s) { if(window.netscape == undefined) return manualConvertUnicodeToUTF8(s); else return mozConvertUnicodeToUTF8(s); } function manualConvertUnicodeToUTF8(s) { var re = /[^\u0000-\u007F]/g ; return s.replace(re, function($0) {return("&#" + $0.charCodeAt(0).toString() + ";");}) } function mozConvertUnicodeToUTF8(s) { try { netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); var converter = Components.classes["@mozilla.org/intl/scriptableunicodeconverter"].createInstance(Components.interfaces.nsIScriptableUnicodeConverter); converter.charset = "UTF-8"; } catch(e) { return manualConvertUnicodeToUTF8(u); } // fallback var u = converter.ConvertFromUnicode(s); var fin = converter.Finish(); if(fin.length > 0) return u + fin; else return u; } function saveFile(fileUrl, content) { var r = null; if((r == null) || (r == false)) r = mozillaSaveFile(fileUrl, content); if((r == null) || (r == false)) r = ieSaveFile(fileUrl, content); if((r == null) || (r == false)) r = javaSaveFile(fileUrl, content); return(r); } function loadFile(fileUrl) { var r = null; if((r == null) || (r == false)) r = mozillaLoadFile(fileUrl); if((r == null) || (r == false)) r = ieLoadFile(fileUrl); if((r == null) || (r == false)) r = javaLoadFile(fileUrl); return(r); } // Returns null if it can't do it, false if there's an error, true if it saved OK function ieSaveFile(filePath, content) { try { var fso = new ActiveXObject("Scripting.FileSystemObject"); } catch(e) { //alert("Exception while attempting to save\n\n" + e.toString()); return(null); } var file = fso.OpenTextFile(filePath,2,-1,0); file.Write(content); file.Close(); return(true); } // Returns null if it can't do it, false if there's an error, or a string of the content if successful function ieLoadFile(filePath) { try { var fso = new ActiveXObject("Scripting.FileSystemObject"); var file = fso.OpenTextFile(filePath,1); var content = file.ReadAll(); file.Close(); } catch(e) { //alert("Exception while attempting to load\n\n" + e.toString()); return(null); } return(content); } // Returns null if it can't do it, false if there's an error, true if it saved OK function mozillaSaveFile(filePath, content) { if(window.Components) try { netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); var file = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile); file.initWithPath(filePath); if (!file.exists()) file.create(0, 0664); var out = Components.classes["@mozilla.org/network/file-output-stream;1"].createInstance(Components.interfaces.nsIFileOutputStream); out.init(file, 0x20 | 0x02, 00004,null); out.write(content, content.length); out.flush(); out.close(); return(true); } catch(e) { //alert("Exception while attempting to save\n\n" + e); return(false); } return(null); } // Returns null if it can't do it, false if there's an error, or a string of the content if successful function mozillaLoadFile(filePath) { if(window.Components) try { netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); var file = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile); file.initWithPath(filePath); if (!file.exists()) return(null); var inputStream = Components.classes["@mozilla.org/network/file-input-stream;1"].createInstance(Components.interfaces.nsIFileInputStream); inputStream.init(file, 0x01, 00004, null); var sInputStream = Components.classes["@mozilla.org/scriptableinputstream;1"].createInstance(Components.interfaces.nsIScriptableInputStream); sInputStream.init(inputStream); return(sInputStream.read(sInputStream.available())); } catch(e) { //alert("Exception while attempting to load\n\n" + e); return(false); } return(null); } function javaUrlToFilename(url) { var f = "//localhost"; if(url.indexOf(f) == 0) return url.substring(f.length); var i = url.indexOf(":"); if(i > 0) return url.substring(i-1); return url; } function javaSaveFile(filePath, content) { try { if(document.applets["TiddlySaver"]) return document.applets["TiddlySaver"].saveFile(javaUrlToFilename(filePath),"UTF-8",content); } catch(e) { } try { var s = new java.io.PrintStream(new java.io.FileOutputStream(javaUrlToFilename(filePath))); s.print(content); s.close(); } catch(e) { return null; } return true; } function javaLoadFile(filePath) { try { if(document.applets["TiddlySaver"]) return String(document.applets["TiddlySaver"].loadFile(javaUrlToFilename(filePath),"UTF-8")); } catch(e) { } var content = []; try { var r = new java.io.BufferedReader(new java.io.FileReader(javaUrlToFilename(filePath))); var line; while ((line = r.readLine()) != null) content.push(new String(line)); r.close(); } catch(e) { return null; } return content.join("\n"); } // --------------------------------------------------------------------------------- // Remote HTTP requests // --------------------------------------------------------------------------------- // Load a file over http // url - the source url // callback - function to call when there's a response // params - parameter object that gets passed to the callback for storing it's state // Return value is the underlying XMLHttpRequest object, or 'null' if there was an error // Callback function is called like this: // callback(status,params,responseText,xhr) // status - true if OK, false if error // params - the parameter object provided to loadRemoteFile() // responseText - the text of the file // xhr - the underlying XMLHttpRequest object function loadRemoteFile(url,callback,params) { // Get an xhr object var x; try { x = new XMLHttpRequest(); // Modern } catch(e) { try { x = new ActiveXObject("Msxml2.XMLHTTP"); // IE 6 } catch (e) { return null; } } // Install callback x.onreadystatechange = function() { if (x.readyState == 4) { if ((x.status == 0 || x.status == 200) && callback) { callback(true,params,x.responseText,url,x); } else callback(false,params,null,url,x); } } // Send request if(window.netscape && window.netscape.security && document.location.protocol.indexOf("http") == -1) window.netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead"); try { url = url + (url.indexOf("?") < 0 ? "?" : "&") + "nocache=" + Math.random(); x.open("GET",url,true); if (x.overrideMimeType) x.overrideMimeType("text/html"); x.send(null); } catch (e) { alert("Error in send " + e); return null; } return x; } // --------------------------------------------------------------------------------- // TiddlyWiki-specific utility functions // --------------------------------------------------------------------------------- function createTiddlyButton(theParent,theText,theTooltip,theAction,theClass,theId,theAccessKey) { var theButton = document.createElement("a"); if(theAction) { theButton.onclick = theAction; theButton.setAttribute("href","javascript:;"); } if(theTooltip) theButton.setAttribute("title",theTooltip); if(theText) theButton.appendChild(document.createTextNode(theText)); if(theClass) theButton.className = theClass; else theButton.className = "button"; if(theId) theButton.id = theId; if(theParent) theParent.appendChild(theButton); if(theAccessKey) theButton.setAttribute("accessKey",theAccessKey); return(theButton); } function createTiddlyLink(place,title,includeText,theClass,isStatic) { var text = includeText ? title : null; var i = getTiddlyLinkInfo(title,theClass) var btn; if(isStatic) btn = createExternalLink(place,"#" + title); else btn = createTiddlyButton(place,text,i.subTitle,onClickTiddlerLink,i.classes); btn.setAttribute("refresh","link"); btn.setAttribute("tiddlyLink",title); return(btn); } function refreshTiddlyLink(e,title) { var i = getTiddlyLinkInfo(title,e.className); e.className = i.classes; e.title = i.subTitle; } function getTiddlyLinkInfo(title,currClasses) { var classes = currClasses ? currClasses.split(" ") : []; classes.pushUnique("tiddlyLink"); var tiddler = store.fetchTiddler(title); var subTitle; if(tiddler) { subTitle = tiddler.getSubtitle(); classes.pushUnique("tiddlyLinkExisting"); classes.remove("tiddlyLinkNonExisting"); classes.remove("shadow"); } else { classes.remove("tiddlyLinkExisting"); classes.pushUnique("tiddlyLinkNonExisting"); if(store.isShadowTiddler(title)) { subTitle = config.messages.shadowedTiddlerToolTip.format([title]); classes.pushUnique("shadow"); } else { subTitle = config.messages.undefinedTiddlerToolTip.format([title]); classes.remove("shadow"); } } return {classes: classes.join(" "), subTitle: subTitle}; } function createExternalLink(place,url) { var theLink = document.createElement("a"); theLink.className = "externalLink"; theLink.href = url; theLink.title = config.messages.externalLinkTooltip.format([url]); if(config.options.chkOpenInNewWindow) theLink.target = "_blank"; place.appendChild(theLink); return(theLink); } // Event handler for clicking on a tiddly link function onClickTiddlerLink(e) { if (!e) var e = window.event; var theTarget = resolveTarget(e); var theLink = theTarget; var title = null; do { title = theLink.getAttribute("tiddlyLink"); theLink = theLink.parentNode; } while(title == null && theLink != null); if(title) { var toggling = e.metaKey || e.ctrlKey; if(config.options.chkToggleLinks) toggling = !toggling; var opening; if(toggling && document.getElementById("tiddler" + title)) story.closeTiddler(title,true,e.shiftKey || e.altKey); else story.displayTiddler(theTarget,title,null,true,e.shiftKey || e.altKey); } clearMessage(); return(false); } // Create a button for a tag with a popup listing all the tiddlers that it tags function createTagButton(place,tag,excludeTiddler) { var theTag = createTiddlyButton(place,tag,config.views.wikified.tag.tooltip.format([tag]),onClickTag); theTag.setAttribute("tag",tag); if(excludeTiddler) theTag.setAttribute("tiddler",excludeTiddler); return(theTag); } // Event handler for clicking on a tiddler tag function onClickTag(e) { if (!e) var e = window.event; var theTarget = resolveTarget(e); var popup = Popup.create(this); var tag = this.getAttribute("tag"); var title = this.getAttribute("tiddler"); if(popup && tag) { var tagged = store.getTaggedTiddlers(tag); var titles = []; var li,r; for(r=0;r 0) { var openAll = createTiddlyButton(createTiddlyElement(popup,"li"),lingo.openAllText.format([tag]),lingo.openAllTooltip,onClickTagOpenAll); openAll.setAttribute("tag",tag); createTiddlyElement(createTiddlyElement(popup,"li"),"hr"); for(r=0; r=0; t--) titles.push(tagged[t].title); displayTiddlers(this,titles); return(false); } function onClickError(e) { if (!e) var e = window.event; var popup = Popup.create(this); var lines = this.getAttribute("errorText").split("\n"); for(var t=0; t= this.steps) { while(this.elements.length > 0) this.removeTail(); this.targetElement.style.position = "static"; this.targetElement.style.zIndex = ""; return false; } else { if(this.elements.length > 0 && this.progress > config.cascadeDepth) this.removeTail(); if(this.progress < (this.steps - config.cascadeDepth)) { var f = Animator.slowInSlowOut(this.progress/(this.steps - config.cascadeDepth - 1)); var e = createTiddlyElement(document.body,"div",null,"cascade",this.text); e.style.zIndex = 1; e.style.left = this.startLeft + (this.targetLeft-this.startLeft) * f + "px"; e.style.top = this.startTop + (this.targetTop-this.startTop) * f + "px"; e.style.width = this.startWidth + (this.targetWidth-this.startWidth) * f + "px"; e.style.height = this.startHeight + (this.targetHeight-this.startHeight) * f + "px"; e.style.display = "block"; this.elements.push(e); } return true; } } Cascade.prototype.removeTail = function() { var e = this.elements[0]; e.parentNode.removeChild(e); this.elements.shift(); } // --------------------------------------------------------------------------------- // Scroller animation // --------------------------------------------------------------------------------- function Scroller(targetElement,slowly) { this.targetElement = targetElement; this.startScroll = findScrollY(); this.targetScroll = ensureVisible(targetElement); this.progress = 0; this.step = slowly ? config.animSlow : config.animFast; return this; } Scroller.prototype.tick = function() { this.progress += this.step; if(this.progress > 1) { window.scrollTo(0,this.targetScroll); return false; } else { var f = Animator.slowInSlowOut(this.progress); window.scrollTo(0,this.startScroll + (this.targetScroll-this.startScroll) * f); return true; } } // --------------------------------------------------------------------------------- // Slider animation // --------------------------------------------------------------------------------- // deleteMode - "none", "all" [delete target element and it's children], [only] "children" [but not the target element] function Slider(element,opening,slowly,deleteMode) { this.element = element; element.style.display = "block"; this.deleteMode = deleteMode; this.element.style.height = "auto"; this.realHeight = element.offsetHeight; this.opening = opening; this.step = slowly ? config.animSlow : config.animFast; if(opening) { this.progress = 0; element.style.height = "0px"; element.style.display = "block"; } else { this.progress = 1; this.step = -this.step; } element.style.overflow = "hidden"; return this; } Slider.prototype.stop = function() { if(this.opening) { this.element.style.height = "auto"; this.element.style.opacity = 1; this.element.style.filter = "alpha(opacity:100)"; } else { switch(this.deleteMode) { case "none": this.element.style.display = "none"; break; case "all": this.element.parentNode.removeChild(this.element); break; case "children": removeChildren(this.element); break; } } } Slider.prototype.tick = function() { this.progress += this.step; if(this.progress < 0 || this.progress > 1) { this.stop(); return false; } else { var f = Animator.slowInSlowOut(this.progress); var h = this.realHeight * f; this.element.style.height = h + "px"; this.element.style.opacity = f; this.element.style.filter = "alpha(opacity:" + f * 100 +")"; return true; } } // --------------------------------------------------------------------------------- // Popup menu // --------------------------------------------------------------------------------- var Popup = { stack: [] // Array of objects with members root: and popup: }; Popup.create = function(root) { Popup.remove(); var popup = createTiddlyElement(document.body,"ol","popup","popup"); Popup.stack.push({root: root, popup: popup}); return popup; } Popup.onDocumentClick = function(e) { if (!e) var e = window.event; var target = resolveTarget(e); if(e.eventPhase == undefined) Popup.remove(); else if(e.eventPhase == Event.BUBBLING_PHASE || e.eventPhase == Event.AT_TARGET) Popup.remove(); return true; } Popup.show = function(unused,slowly) { var curr = Popup.stack[Popup.stack.length-1]; var rootLeft = findPosX(curr.root); var rootTop = findPosY(curr.root); var rootHeight = curr.root.offsetHeight; var popupLeft = rootLeft; var popupTop = rootTop + rootHeight; var popupWidth = curr.popup.offsetWidth; var winWidth = findWindowWidth(); if(popupLeft + popupWidth > winWidth) popupLeft = winWidth - popupWidth; curr.popup.style.left = popupLeft + "px"; curr.popup.style.top = popupTop + "px"; curr.popup.style.display = "block"; addClass(curr.root,"highlight"); if(anim && config.options.chkAnimate) anim.startAnimating(new Scroller(curr.popup,slowly)); else window.scrollTo(0,ensureVisible(curr.popup)); } Popup.remove = function() { if(Popup.stack.length > 0) { Popup.removeFrom(0); } } Popup.removeFrom = function(from) { for(var t=Popup.stack.length-1; t>=from; t--) { var p = Popup.stack[t]; removeClass(p.root,"highlight"); p.popup.parentNode.removeChild(p.popup); } Popup.stack = Popup.stack.slice(0,from); } // --------------------------------------------------------------------------------- // ListView gadget // --------------------------------------------------------------------------------- var ListView = {}; // Create a listview // place - where in the DOM tree to insert the listview // listObject - array of objects to be included in the listview // listTemplate - template for the listview // callback - callback for a command being selected // className - optional classname for the element ListView.create = function(place,listObject,listTemplate,callback,className) { var table = createTiddlyElement(place,"table",null,className ? className : "listView"); var thead = createTiddlyElement(table,"thead"); var r = createTiddlyElement(thead,"tr"); for(var t=0; t element of listView // callback(checkboxElement,rowName) // where // checkboxElement - DOM element of checkbox // rowName - name of this row as assigned by the column template // result: true if at least one selector was checked ListView.forEachSelector = function(view,callback) { var checkboxes = view.getElementsByTagName("input"); var hadOne = false; for(var t=0; t max) c = max; return c; } // Add indexOf function if browser does not support it if(!Array.indexOf) { Array.prototype.indexOf = function(item,from) { if(!from) from = 0; for(var i=from; i "backgroundColor") String.prototype.unDash = function() { var s = this.split("-"); if(s.length > 1) for(var t=1; t currPos) r.push(this.substring(currPos,match.index)); r.push(substrings[parseInt(match[1])]); currPos = subRegExp.lastIndex; } } while(match); if(currPos < this.length) r.push(this.substring(currPos,this.length)); return r.join(""); } // Escape any special RegExp characters with that character preceded by a backslash String.prototype.escapeRegExp = function() { var s = "\\^$*+?()=!|,{}[]."; var c = this; for(var t=0; t to ">" and " to """ String.prototype.htmlEncode = function() { return(this.replace(/&/mg,"&").replace(//mg,">").replace(/\"/mg,""")); } // Convert "&" to &, "<" to <, ">" to > and """ to " String.prototype.htmlDecode = function() { return(this.replace(/&/mg,"&").replace(/</mg,"<").replace(/>/mg,">").replace(/"/mg,"\"")); } // Parse a space-separated string of name:value parameters where: // - the name or the value can be optional (in which case separate defaults are used instead) // - in case of ambiguity, a lone word is taken to be a value // - if 'cascadeDefaults' is set to true, then the defaults are modified by updated by each specified name or value // - name prefixes are not allowed if the 'noNames' parameter is true // - if both the name and value are present they must be separated by a colon // - the name and the value may both be quoted with single- or double-quotes, double-square brackets // - names or values quoted with {{double-curly braces}} are evaluated as a JavaScript expression // - as long as the 'allowEval' parameter is true // The result is an array of objects: // result[0] = object with a member for each parameter name, value of that member being an array of values // result[1..n] = one object for each parameter, with 'name' and 'value' members String.prototype.parseParams = function(defaultName,defaultValue,allowEval,noNames,cascadeDefaults) { var parseToken = function(match,p) { var n; if(match[p]) // Double quoted n = match[p]; else if(match[p+1]) // Single quoted n = match[p+1]; else if(match[p+2]) // Double-square-bracket quoted n = match[p+2]; else if(match[p+3]) // Double-brace quoted try { n = match[p+3]; if(allowEval) n = window.eval(n); } catch(e) { throw "Unable to evaluate {{" + match[p+3] + "}}: " + exceptionText(e); } else if(match[p+4]) // Unquoted n = match[p+4]; return n; }; var r = [{}]; var dblQuote = "(?:\"((?:(?:\\\\\")|[^\"])*)\")"; var sngQuote = "(?:'((?:(?:\\\\\')|[^'])*)')"; var dblSquare = "(?:\\[\\[((?:\\s|\\S)*?)\\]\\])"; var dblBrace = "(?:\\{\\{((?:\\s|\\S)*?)\\}\\})"; var unQuoted = noNames ? "([^\"'\\s]\\S*)" : "([^\"':\\s][^\\s:]*)"; var skipSpace = "(?:\\s*)"; var token = "(?:" + dblQuote + "|" + sngQuote + "|" + dblSquare + "|" + dblBrace + "|" + unQuoted + ")"; var re = noNames ? new RegExp(token,"mg") : new RegExp(skipSpace + token + skipSpace + "(?:(\\:)" + skipSpace + token + ")?","mg"); var params = []; do { var match = re.exec(this); if(match) { var n = parseToken(match,1); if(noNames) r.push({name: "", value: n}); else { var v = parseToken(match,7); if(v == null && defaultName) { v = n; n = defaultName; } else if(v == null && defaultValue) v = defaultValue; r.push({name: n, value: v}); if(cascadeDefaults) { defaultName = n; defaultValue = v; } } } } while(match); // Summarise parameters into first element for(var t=1; t 12 ? h-12 : ( h > 0 ? h : 12 ); } Date.prototype.getAmPm = function() { return this.getHours() >= 12 ? "pm" : "am"; } Date.prototype.daySuffix = function() { var num = this.getDate(); if (num >= 11 && num <= 13) return "th"; else if (num.toString().substr(-1)=="1") return "st"; else if (num.toString().substr(-1)=="2") return "nd"; else if (num.toString().substr(-1)=="3") return "rd"; return "th"; } // Convert a date to local YYYYMMDDHHMM string format Date.prototype.convertToLocalYYYYMMDDHHMM = function() { return(String.zeroPad(this.getFullYear(),4) + String.zeroPad(this.getMonth()+1,2) + String.zeroPad(this.getDate(),2) + String.zeroPad(this.getHours(),2) + String.zeroPad(this.getMinutes(),2)); } // Convert a date to UTC YYYYMMDDHHMM string format Date.prototype.convertToYYYYMMDDHHMM = function() { return(String.zeroPad(this.getUTCFullYear(),4) + String.zeroPad(this.getUTCMonth()+1,2) + String.zeroPad(this.getUTCDate(),2) + String.zeroPad(this.getUTCHours(),2) + String.zeroPad(this.getUTCMinutes(),2)); } // Convert a date to UTC YYYYMMDD.HHMMSSMMM string format Date.prototype.convertToYYYYMMDDHHMMSSMMM = function() { return(String.zeroPad(this.getUTCFullYear(),4) + String.zeroPad(this.getUTCMonth()+1,2) + String.zeroPad(this.getUTCDate(),2) + "." + String.zeroPad(this.getUTCHours(),2) + String.zeroPad(this.getUTCMinutes(),2) + String.zeroPad(this.getUTCSeconds(),2) + String.zeroPad(this.getUTCMilliseconds(),4)); } // Static method to create a date from a UTC YYYYMMDDHHMM format string Date.convertFromYYYYMMDDHHMM = function(d) { var theDate = new Date(Date.UTC(parseInt(d.substr(0,4),10), parseInt(d.substr(4,2),10)-1, parseInt(d.substr(6,2),10), parseInt(d.substr(8,2),10), parseInt(d.substr(10,2),10),0,0)); return(theDate); } // --------------------------------------------------------------------------------- // Crypto functions and associated conversion routines // --------------------------------------------------------------------------------- // Crypto "namespace" function Crypto() {} // Convert a string to an array of big-endian 32-bit words Crypto.strToBe32s = function(str) { var be = Array(); var len = Math.floor(str.length/4); var i, j; for(i=0, j=0; i>2] |= (str.charCodeAt(j)&0xff)<<(24-(j*8)%32); j++; } return be; } // Convert an array of big-endian 32-bit words to a string Crypto.be32sToStr = function(be) { var str = ""; for(var i=0;i>5]>>>(24-i%32)) & 0xff); return str; } // Convert an array of big-endian 32-bit words to a hex string Crypto.be32sToHex = function(be) { var hex = "0123456789ABCDEF"; var str = ""; for(var i=0;i>2]>>((3-i%4)*8+4))&0xF) + hex.charAt((be[i>>2]>>((3-i%4)*8))&0xF); return str; } // Return, in hex, the SHA-1 hash of a string Crypto.hexSha1Str = function(str) { return Crypto.be32sToHex(Crypto.sha1Str(str)); } // Return the SHA-1 hash of a string Crypto.sha1Str = function(str) { return Crypto.sha1(Crypto.strToBe32s(str),str.length); } // Calculate the SHA-1 hash of an array of blen bytes of big-endian 32-bit words Crypto.sha1 = function(x,blen) { // Add 32-bit integers, wrapping at 32 bits //# Uses 16-bit operations internally to work around bugs in some JavaScript interpreters. add32 = function(a,b) { var lsw = (a&0xFFFF)+(b&0xFFFF); var msw = (a>>16)+(b>>16)+(lsw>>16); return (msw<<16)|(lsw&0xFFFF); }; // Add five 32-bit integers, wrapping at 32 bits //# Uses 16-bit operations internally to work around bugs in some JavaScript interpreters. add32x5 = function(a,b,c,d,e) { var lsw = (a&0xFFFF)+(b&0xFFFF)+(c&0xFFFF)+(d&0xFFFF)+(e&0xFFFF); var msw = (a>>16)+(b>>16)+(c>>16)+(d>>16)+(e>>16)+(lsw>>16); return (msw<<16)|(lsw&0xFFFF); }; // Bitwise rotate left a 32-bit integer by 1 bit rol32 = function(n) { return (n>>>31)|(n<<1); }; var len = blen*8; // Append padding so length in bits is 448 mod 512 x[len>>5] |= 0x80 << (24-len%32); // Append length x[((len+64>>9)<<4)+15] = len; var w = Array(80); var k1 = 0x5A827999; var k2 = 0x6ED9EBA1; var k3 = 0x8F1BBCDC; var k4 = 0xCA62C1D6; var h0 = 0x67452301; var h1 = 0xEFCDAB89; var h2 = 0x98BADCFE; var h3 = 0x10325476; var h4 = 0xC3D2E1F0; for(var i=0;i>>27)|(a<<5),d^(b&(c^d)),w[j],k1); e=d; d=c; c=(b>>>2)|(b<<30); b=a; a = t; } for(j=16;j<20;j++) { w[j] = rol32(w[j-3]^w[j-8]^w[j-14]^w[j-16]); t = add32x5(e,(a>>>27)|(a<<5),d^(b&(c^d)),w[j],k1); e=d; d=c; c=(b>>>2)|(b<<30); b=a; a = t; } for(j=20;j<40;j++) { w[j] = rol32(w[j-3]^w[j-8]^w[j-14]^w[j-16]); t = add32x5(e,(a>>>27)|(a<<5),b^c^d,w[j],k2); e=d; d=c; c=(b>>>2)|(b<<30); b=a; a = t; } for(j=40;j<60;j++) { w[j] = rol32(w[j-3]^w[j-8]^w[j-14]^w[j-16]); t = add32x5(e,(a>>>27)|(a<<5),(b&c)|(d&(b|c)),w[j],k3); e=d; d=c; c=(b>>>2)|(b<<30); b=a; a = t; } for(j=60;j<80;j++) { w[j] = rol32(w[j-3]^w[j-8]^w[j-14]^w[j-16]); t = add32x5(e,(a>>>27)|(a<<5),b^c^d,w[j],k4); e=d; d=c; c=(b>>>2)|(b<<30); b=a; a = t; } h0 = add32(h0,a); h1 = add32(h1,b); h2 = add32(h2,c); h3 = add32(h3,d); h4 = add32(h4,e); } return Array(h0,h1,h2,h3,h4); } // --------------------------------------------------------------------------------- // RGB colour object // --------------------------------------------------------------------------------- // Construct an RGB colour object from a '#rrggbb', '#rgb' or 'rgb(n,n,n)' string or from separate r,g,b values function RGB(r,g,b) { this.r = 0; this.g = 0; this.b = 0; if(typeof r == "string") { if(r.substr(0,1) == "#") { if(r.length == 7) { this.r = parseInt(r.substr(1,2),16)/255; this.g = parseInt(r.substr(3,2),16)/255; this.b = parseInt(r.substr(5,2),16)/255; } else { this.r = parseInt(r.substr(1,1),16)/15; this.g = parseInt(r.substr(2,1),16)/15; this.b = parseInt(r.substr(3,1),16)/15; } } else { var rgbPattern = /rgb\s*\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*\)/ ; var c = r.match(rgbPattern); if (c) { this.r = parseInt(c[1],10)/255; this.g = parseInt(c[2],10)/255; this.b = parseInt(c[3],10)/255; } } } else { this.r = r; this.g = g; this.b = b; } return this; } // Mixes this colour with another in a specified proportion // c = other colour to mix // f = 0..1 where 0 is this colour and 1 is the new colour // Returns an RGB object RGB.prototype.mix = function(c,f) { return new RGB(this.r + (c.r-this.r) * f,this.g + (c.g-this.g) * f,this.b + (c.b-this.b) * f); } // Return an rgb colour as a #rrggbb format hex string RGB.prototype.toString = function() { var r = this.r.clamp(0,1); var g = this.g.clamp(0,1); var b = this.b.clamp(0,1); return("#" + ("0" + Math.floor(r * 255).toString(16)).right(2) + ("0" + Math.floor(g * 255).toString(16)).right(2) + ("0" + Math.floor(b * 255).toString(16)).right(2)); } // --------------------------------------------------------------------------------- // DOM utilities - many derived from www.quirksmode.org // --------------------------------------------------------------------------------- function drawGradient(place,horiz,colours) { for(var t=0; t<= 100; t+=2) { var bar = document.createElement("div"); place.appendChild(bar); bar.style.position = "absolute"; bar.style.left = horiz ? t + "%" : 0; bar.style.top = horiz ? 0 : t + "%"; bar.style.width = horiz ? (101-t) + "%" : "100%"; bar.style.height = horiz ? "100%" : (101-t) + "%"; bar.style.zIndex = -1; var f = t/100; var p = f*(colours.length-1); bar.style.backgroundColor = colours[Math.floor(p)].mix(colours[Math.ceil(p)],p-Math.floor(p)).toString(); } } function createTiddlyText(theParent,theText) { return theParent.appendChild(document.createTextNode(theText)); } function createTiddlyCheckbox(theParent,caption,checked,onChange) { var cb = document.createElement("input"); cb.setAttribute("type","checkbox"); cb.onclick = onChange; theParent.appendChild(cb); cb.checked = checked; if(caption) wikify(caption,theParent); return cb; } function createTiddlyElement(theParent,theElement,theID,theClass,theText) { var e = document.createElement(theElement); if(theClass != null) e.className = theClass; if(theID != null) e.setAttribute("id",theID); if(theText != null) e.appendChild(document.createTextNode(theText)); if(theParent != null) theParent.appendChild(e); return(e); } // Add an event handler // Thanks to John Resig, via QuirksMode function addEvent(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); } // Remove an event handler // Thanks to John Resig, via QuirksMode function removeEvent(obj,type,fn) { if(obj.detachEvent) { obj.detachEvent('on'+type,obj[type+fn]); obj[type+fn] = null; } else obj.removeEventListener(type,fn,false); } function addClass(e,theClass) { var currClass = e.className.split(" "); if(currClass.indexOf(theClass) == -1) e.className += " " + theClass; } function removeClass(e,theClass) { var currClass = e.className.split(" "); var i = currClass.indexOf(theClass); while(i != -1) { currClass.splice(i,1); i = currClass.indexOf(theClass); } e.className = currClass.join(" "); } function hasClass(e,theClass) { if(e.className) { if(e.className.split(" ").indexOf(theClass) != -1) return true; } return false; } // Find the closest relative with a given property value (property defaults to tagName, relative defaults to parentNode) function findRelated(e,value,name,relative) { name = name ? name : "tagName"; relative = relative ? relative : "parentNode"; if(name == "className") { while(e && !hasClass(e,value)) { e = e[relative]; } } else { while(e && e[name] != value) { e = e[relative]; } } return e; } // Resolve the target object of an event function resolveTarget(e) { var obj; if (e.target) obj = e.target; else if (e.srcElement) obj = e.srcElement; if (obj.nodeType == 3) // defeat Safari bug obj = obj.parentNode; return(obj); } // Return the content of an element as plain text with no formatting function getPlainText(e) { var text = ""; if(e.innerText) text = e.innerText; else if(e.textContent) text = e.textContent; return text; } // Get the scroll position for window.scrollTo necessary to scroll a given element into view function ensureVisible(e) { var posTop = findPosY(e); var posBot = posTop + e.offsetHeight; var winTop = findScrollY(); var winHeight = findWindowHeight(); var winBot = winTop + winHeight; if(posTop < winTop) return(posTop); else if(posBot > winBot) { if(e.offsetHeight < winHeight) return(posTop - (winHeight - e.offsetHeight)); else return(posTop); } else return(winTop); } // Get the current width of the display window function findWindowWidth() { return(window.innerWidth ? window.innerWidth : document.documentElement.clientWidth); } // Get the current height of the display window function findWindowHeight() { return(window.innerHeight ? window.innerHeight : document.documentElement.clientHeight); } // Get the current horizontal page scroll position function findScrollX() { return(window.scrollX ? window.scrollX : document.documentElement.scrollLeft); } // Get the current vertical page scroll position function findScrollY() { return(window.scrollY ? window.scrollY : document.documentElement.scrollTop); } function findPosX(obj) { var curleft = 0; while (obj.offsetParent) { curleft += obj.offsetLeft; obj = obj.offsetParent; } return curleft; } function findPosY(obj) { var curtop = 0; while (obj.offsetParent) { curtop += obj.offsetTop; obj = obj.offsetParent; } return curtop; } // Blur a particular element function blurElement(e) { if(e != null && e.focus && e.blur) { e.focus(); e.blur(); } } // Create a non-breaking space function insertSpacer(place) { var e = document.createTextNode(String.fromCharCode(160)); if(place) place.appendChild(e); return e; } // Remove all children of a node function removeChildren(e) { while(e.hasChildNodes()) e.removeChild(e.firstChild); } // Add a stylesheet, replacing any previous custom stylesheet function setStylesheet(s,id) { if(!id) id = "customStyleSheet"; var n = document.getElementById(id); if(document.createStyleSheet) // Test for IE's non-standard createStyleSheet method { if(n) n.parentNode.removeChild(n); // This failed without the   document.getElementsByTagName("head")[0].insertAdjacentHTML("beforeEnd"," "); } else { if(n) n.replaceChild(document.createTextNode(s),n.firstChild); else { var n = document.createElement("style"); n.type = "text/css"; n.id = id; n.appendChild(document.createTextNode(s)); document.getElementsByTagName("head")[0].appendChild(n); } } } // Replace the current selection of a textarea or text input and scroll it into view function replaceSelection(e,text) { if (e.setSelectionRange) { var oldpos = e.selectionStart + 1; e.value = e.value.substr(0,e.selectionStart) + text + e.value.substr(e.selectionStart); e.setSelectionRange( oldpos, oldpos); var linecount = e.value.split('\n').length; var thisline = e.value.substr(0,e.selectionStart).split('\n').length-1; e.scrollTop = Math.floor((thisline-e.rows/2)*e.scrollHeight/linecount); } else if (document.selection) { var range = document.selection.createRange(); if (range.parentElement() == e) { var isCollapsed = range.text == ""; range.text = text; if (!isCollapsed) { range.moveStart('character', -text.length); range.select(); } } } } // Returns the text of the given (text) node, possibly merging subsequent text nodes function getNodeText(e) { var t = ""; while (e && e.nodeName == "#text") { t += e.nodeValue; e = e.nextSibling; } return t; } //# ------------------------- //# LoaderBase: A (abstract) storage loader that loads the tiddlers from a list of HTML elements. //# The format of the elements is defined by subclasses of this loader through the internalizeTiddler implementation. //# Subclasses must implement: //# function getTitle(store, e) //# //# store must implement: //# function createTiddler(title). //# function LoaderBase() { } LoaderBase.prototype.loadTiddler = function(store,e,tiddlers) { var title = this.getTitle(store, e); if (title) { var tiddler = store.createTiddler(title); this.internalizeTiddler(store, tiddler, title, e); tiddlers.push(tiddler); } } LoaderBase.prototype.loadTiddlers = function(store,nodes) { var tiddlers = []; for (var t = 0; t < nodes.length; t++) { try { this.loadTiddler(store, nodes[t], tiddlers); } catch(e) { showException(e, config.messages.tiddlerLoadError.format([this.getTitle(store, nodes[t])])); } } return tiddlers; } //# ------------------------- //# SaverBase: a (abstract) storage saver that externalizes all tiddlers into a string, //# with every tiddler individually externalized (using this.externalizeTiddler) and joined with newlines //# Subclasses must implement: //# function externalizeTiddler(store, tiddler) //# //# store must implement: //# function getTiddlers(sortByFieldName) //# function SaverBase() { } SaverBase.prototype.externalize = function(store) { var results = []; var tiddlers = store.getTiddlers("title"); for (var t = 0; t < tiddlers.length; t++) results.push(this.externalizeTiddler(store, tiddlers[t])); return results.join("\n"); } //-------------------------------- // TW21Loader (inherits from LoaderBase) function TW21Loader() {}; TW21Loader.prototype = new LoaderBase(); TW21Loader.prototype.getTitle = function(store, e) { var title = null; if(e.getAttribute) title = e.getAttribute("tiddler"); if(!title && e.id) { var lenPrefix = store.idPrefix.length; if (e.id.substr(0,lenPrefix) == store.idPrefix) title = e.id.substr(lenPrefix); } return title; } TW21Loader.prototype.internalizeTiddler = function(store, tiddler, title, data) { var text = getNodeText(data.firstChild).unescapeLineBreaks(); var modifier = data.getAttribute("modifier"); var modified = Date.convertFromYYYYMMDDHHMM(data.getAttribute("modified")); var c = data.getAttribute("created"); var created = c ? Date.convertFromYYYYMMDDHHMM(c) : modified; var tags = data.getAttribute("tags"); var fields = {}; var attrs = data.attributes; for(var i = attrs.length-1; i >= 0; i--) { var name = attrs[i].name; if (attrs[i].specified && !TiddlyWiki.isStandardField(name)) { fields[name] = attrs[i].value.unescapeLineBreaks(); } } tiddler.assign(title,text,modifier,modified,tags,created, fields); return tiddler; }; //-------------------------------- // TW21Saver (inherits from SaverBase) function TW21Saver() {}; TW21Saver.prototype = new SaverBase(); TW21Saver.prototype.externalizeTiddler = function(store, tiddler) { try { var extendedFieldAttributes = ""; store.forEachField(tiddler, function(tiddler, fieldName, value) { // don't store stuff from the temp namespace if (!fieldName.match(/^temp\./)) extendedFieldAttributes += ' %0="%1"'.format([fieldName, value.escapeLineBreaks().htmlEncode()]); }, true); return '
%5
'.format([ tiddler.title.htmlEncode(), tiddler.modifier.htmlEncode(), tiddler.modified.convertToYYYYMMDDHHMM(), tiddler.created.convertToYYYYMMDDHHMM(), tiddler.getTags().htmlEncode(), tiddler.escapeLineBreaks().htmlEncode(), extendedFieldAttributes ]); } catch (e) { throw exceptionText(e, config.messages.tiddlerSaveError.format([tiddler.title])); } } // --------------------------------------------------------------------------------- // Deprecated code // --------------------------------------------------------------------------------- // @Deprecated: Use createElementAndWikify and this.termRegExp instead config.formatterHelpers.charFormatHelper = function(w) { w.subWikify(createTiddlyElement(w.output,this.element),this.terminator); } // @Deprecated: Use enclosedTextHelper and this.lookaheadRegExp instead config.formatterHelpers.monospacedByLineHelper = function(w) { var lookaheadRegExp = new RegExp(this.lookahead,"mg"); lookaheadRegExp.lastIndex = w.matchStart; var lookaheadMatch = lookaheadRegExp.exec(w.source); if(lookaheadMatch && lookaheadMatch.index == w.matchStart) { var text = lookaheadMatch[1]; if(config.browser.isIE) text = text.replace(/\n/g,"\r"); createTiddlyElement(w.output,"pre",null,null,text); w.nextMatch = lookaheadRegExp.lastIndex; } } // @Deprecated: Use
or
instead of <
> config.macros.br.handler = function(place) { createTiddlyElement(place,"br"); } // Find an entry in an array. Returns the array index or null // @Deprecated: Use indexOf instead Array.prototype.find = function(item) { var i = this.indexOf(item); return i == -1 ? null : i; } // Load a tiddler from an HTML DIV. The caller should make sure to later call Tiddler.changed() // @Deprecated: Use store.getLoader().internalizeTiddler instead Tiddler.prototype.loadFromDiv = function(divRef,title) { return store.getLoader().internalizeTiddler(store,this,title,divRef); } // Format the text for storage in an HTML DIV // @Deprecated Use store.getSaver().externalizeTiddler instead. Tiddler.prototype.saveToDiv = function() { return store.getSaver().externalizeTiddler(store,this); } // @Deprecated: Use store.allTiddlersAsHtml() instead function allTiddlersAsHtml() { return store.allTiddlersAsHtml(); } // @Deprecated: Use refreshPageTemplate instead function applyPageTemplate(title) { refreshPageTemplate(title); } // @Deprecated: Use story.displayTiddlers instead function displayTiddlers(srcElement,titles,template,unused1,unused2,animate,slowly) { story.displayTiddlers(srcElement,titles,template,animate,slowly); } // @Deprecated: Use story.displayTiddler instead function displayTiddler(srcElement,title,template,unused1,unused2,animate,slowly) { story.displayTiddler(srcElement,title,template,animate,slowly); } // @Deprecated: Use functions on right hand side directly instead var createTiddlerPopup = Popup.create; var scrollToTiddlerPopup = Popup.show; var hideTiddlerPopup = Popup.remove; // @Deprecated: Use right hand side directly instead var regexpBackSlashEn = new RegExp("\\\\n","mg"); var regexpBackSlash = new RegExp("\\\\","mg"); var regexpBackSlashEss = new RegExp("\\\\s","mg"); var regexpNewLine = new RegExp("\n","mg"); var regexpCarriageReturn = new RegExp("\r","mg"); // --------------------------------------------------------------------------------- // End of scripts // --------------------------------------------------------------------------------- //]]>
I went to 8 football games during the 2001 season:\n[[Syracuse]] vs [[Auburn]] in the Carrier Dome in Syracuse, NY, \n[[Jaguars]] vs [[Bills]] at [[Alltel Stadium]] in Jacksonville, FL, \n[[Redskins]] vs [[Panthers]] at [[FedEx Field]] in Landover, MD, \n[[Chargers]] vs [[Bills]] at [[Qualcomm Stadium]] in San Diego, CA,\n[[Auburn]] vs [[Alabama]] at [[Jordan-Hare Stadium]] in Auburn, AL\n[[Bengals]] vs [[Buccaneers]] at [[Paul Brown Stadium]] in Cincinnati, OH, and \n[[Buccaneers]] vs [[Saints]] at [[Raymond James Stadium]] in Tampa, FL. \n[[Dolphins]] vs [[Ravens]] at [[Pro Player Stadium]] in Miami, FL - An AFC Wild Card [[Playoff Game]].\n\nI scanned in these pictures and ticket stubs. I didn't have a digital camera until 2003, so this is a real historical archive! Enjoy. [[Click Here|http://www.bndsports.com/2001/index.html]]
There are 10 games in the 2002 football season gallery. Highlights include the [[USC vs Auburn]] game in Los Angeles, the [[Broncos vs Bills]] game in Denver, the [[Panthers vs Buccaneers]] game in Charlotte, the [[Texans vs Ravens]] game in Houston, and [[Super Bowl XXXVII]] in San Diego! http://www.bndsports.com/2002/2002_season_index.htm
There are 18 games in the 2003 football gallery. http://www.bndsports.com/2003/itinerary_2003.htm
There are 22 games in the 2004 football gallery. http://www.bndsports.com/2004/2004_itinerary.htm
There are 20 games in the 2005 football gallery. http://www.bndsports.com/2005/2005_itinerary.htm
The 2006 football gallery is under construction. Here is the itinerary: http://www.bndsports.com/2006/2006_itinerary.htm
Planning to attend the following games in the 2007 season:\nMaryland Terrapins vs [[Villanova Wildcats]], September 1, 2007\nCleveland Browns vs Pittsburgh Steelers, September 9, 2007\nVirginia Cavaliers vs Pittsburgh Panthers, September 28, 2007\nCarolina Panthers vs Tampa Bay [[Buccaneers]], September 29, 2007\nSan Francisco 49ers vs Baltimore Ravens, October 7, 2007\nPittsburgh Steelers vs Baltimore Ravens, November 5, 2007\n[[Auburn]] vs Alabama, November 24, 2007\nArmy vs Navy, December 1, 2007\nAll [[Baltimore Ravens]] home games.\nFor a total of 16 games, 3 new NFL stadiums, 2 new college teams.
Auburn University, in Auburn, AL, is home to my favorite college football team, the Auburn Tigers. Their home stadium is [[Jordan-Hare Stadium]], which has an official capacity of 87,451.\n\nHome Games attended:\nvs [[Georgia]] - [[November 16, 1996]]\nvs [[Ole Miss]] - [[September 13, 1997]]\nvs [[Alabama]] - [[November 17, 2001]] - [[Iron Bowl]]\nvs [[Vanderbilt]] - [[September 14, 2002]]\nvs [[Alabama]] - [[November 22, 2003]] - [[Iron Bowl]]\nvs [[Arkansas]] - [[October 16, 2004]]\nvs [[Georgia Tech]] - [[September 3, 2005]]\nvs [[Mississippi State]] - [[September 10, 2005]]\n\nRoad Games attended:\nat [[Ole Miss]] - [[September 14, 1996]]\nat [[Florida]] - [[October 19, 1996]]\nat [[LSU]] - [[September 20, 1997]]\nat [[Syracuse]] - [[September 22, 2001]]\nat [[Southern California]] - [[September 2, 2002]]\nat [[Georgia Tech]] - [[September 6, 2003]]\n\nSEC Championship Game:\nvs [[Tennessee]] - [[December 4, 2004]]\n\nBowl Games attended:\n[[Outback]] vs [[Penn State]] - [[January 1, 1996]]\n[[Peach]] vs [[Clemson]] - [[January 2, 1998]]\n[[Citrus]] vs [[Wisconsin]] - [[January 2, 2006]]
bnd TiddlyWiki
The Tampa Bay Buccaneers, my favorite NFL team, plays their home games in Raymond-James Stadium, which has an official capacity of 74,301. They played in Tampa Stadium through the conclusion of the 1997 season.\n\nHome Games attended:\nvs [[Chargers]] - January 2, 1994 (no gallery)\nvs [[Packers]] - September 1, 1996 (no gallery)\nvs [[Bears]] - [[December 21, 1997]]\nvs [[Lions]], an NFC Wild Card [[Playoff Game]] - [[December 28, 1997]]\nvs [[Saints]] - [[December 23, 2001]]\nvs [[Falcons]] - [[December 20, 2003]]\nvs [[Panthers]] - [[December 26, 2004]]\nvs [[Redskins]], an NFC Wild Card [[Playoff Game]] - [[January 8, 2006]]\nvs [[Ravens]] - [[September 10, 2006]]\n\nRoad Games attended:\nat [[Eagles]] - [[September 19, 1999]]\nat [[Bengals]] - [[December 2, 2001]]\nat [[Ravens]] - [[September 15, 2002]]\nat [[Panthers]] - [[October 27, 2002]]\nat [[Rams]] - [[October 18, 2004]]\nat [[Chargers]] - [[December 12, 2004]]\n\n[[Super Bowl XXXVII]]\nvs [[Raiders]] - [[January 26, 2003]]
FootballGalleries
Click on a year for more information.\n[[Pre2001]] \n[[2001]]\n[[2002]]\n[[2003]]\n[[2004]]\n[[2005]]\n[[2006]]\n[[2007]]
/***\n|''Name:''|LegacyStrikeThroughPlugin|\n|''Description:''|Support for legacy (pre 2.1) strike through formatting|\n|''Version:''|1.0.1|\n|''Date:''|Jul 21, 2006|\n|''Source:''|http://www.tiddlywiki.com/#LegacyStrikeThroughPlugin|\n|''Author:''|MartinBudden (mjbudden (at) gmail (dot) com)|\n|''License:''|[[BSD open source license]]|\n|''CoreVersion:''|2.1.0|\n|''Browser:''|Firefox 1.0.4+; Firefox 1.5; InternetExplorer 6.0|\n\n***/\n\n//{{{\n\n// Ensure that the LegacyStrikeThrough Plugin is only installed once.\nif(!version.extensions.LegacyStrikeThroughPlugin)\n {\n version.extensions.LegacyStrikeThroughPlugin = true;\n\nconfig.formatters.push(\n{\n name: "legacyStrikeByChar",\n match: "==",\n termRegExp: /(==)/mg,\n element: "strike",\n handler: config.formatterHelpers.createElementAndWikify\n});\n\n} // end of "install only once"\n//}}}\n
GettingStarted FootballGalleries
This is a collection of all the football game pictures that I could find in my album. I scanned my ticket stubs and prints and then added captions. Dates range from 1993 to 2001. This is a real historical archive. Enjoy! [[Click here|http://www.bndsports.com/pre2K1/index.html]]
the reusable non-linear personal web notebook of BND Sports
Nathan Davis, the owner and webmaster of bndsports.com.