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]];}

	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, #backstageArea {display: none ! important;}
#displayArea {margin: 1em 1em 0em 1em;}
/* Fixes a feature in Firefox 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 class='headerForeground'>
<span class='siteTitle' refresh='content' tiddler='SiteTitle'></span>&nbsp;
<span class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'></span>
<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 id='displayArea'>
<div id='messageArea'></div>
<div id='tiddlerDisplay'></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
Для того, чтобы начать работать с TiddlyWiki, вы можете поменять следующие записи:
* SiteTitle & SiteSubtitle: Заголовок и подзаголовок сайта (после сохранения вы увидите их в заголовке окна)
* MainMenu: Меню (оно обычно слева)
* DefaultTiddlers: Список записей, которые будут открыты при запуске wiki.
Можно также почитать [[справку по вики|Вики-разметка (примеры)]].
Имя, которым будут подписаны ваши записи, можете ввести тут: <<option txtUserName>>

|''Description:''|Support for legacy (pre 2.1) strike through formatting|
|''Date:''|Jul 21, 2006|
|''Author:''|MartinBudden (mjbudden (at) gmail (dot) com)|
|''License:''|[[BSD open source license]]|

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

	name: "legacyStrikeByChar",
	match: "==",
	termRegExp: /(==)/mg,
	element: "strike",
	handler: config.formatterHelpers.createElementAndWikify

} //# end of "install only once"
|''Version:''|2.3.8 (Mar 9, 2006)|
|''Author:''|Jeremy Sheeley(pop1280 [at] excite [dot] com)|
|''Licence:''|[[BSD open source license]]|
|''Macros:''|reminder, showreminders, displayTiddlersWithReminders, newReminder|
|''Browser:''|Firefox 1.0.4+; InternetExplorer 6.0|
|''Hacked by:'' | //Cleb. Support for Russian dates added// |
|''Hack version:'' | //0.8b// |
|''Hack source:'' | |

This plugin provides macros for tagging a date with a reminder.  Use the {{{reminder}}} macro to do this.  The {{{showReminders}}} and {{{displayTiddlersWithReminder}}} macros automatically search through all available tiddlers looking for upcoming reminders.

* Create a new tiddler in your tiddlywiki titled ReminderPlugin and give it the {{{systemConfig}}} tag.  The tag is important because it tells TW that this is executable code.
* Double click this tiddler, and copy all the text from the tiddler's body.
* Paste the text into the body of the new tiddler in your TW.
* Save and reload your TW.
* You can copy some examples into your TW as well.  See [[Simple examples]], [[Holidays]], [[showReminders]] and [[Personal Reminders]]

|>|See [[ReminderSyntax]] and [[showRemindersSyntax]]|

!Revision history
* v2.3.8 (Mar 9, 2006)
**Bug fix: A global variable had snuck in, which was killing FF
**Feature: You can now use TIDDLER and TIDDLERNAME in a regular reminder format
* v2.3.6 (Mar 1, 2006)
**Bug fix: Reminders for today weren't being matched sometimes.
**Feature:  Solidified integration with DatePlugin and CalendarPlugin
**Feature:  Recurring reminders will now return multiple hits in showReminders and the calendar.
**Feature:  Added TIDDLERNAME to the replacements for showReminders format, for plugins that need the title without brackets.
* v2.3.5 (Feb 8, 2006)
**Bug fix: Sped up reminders lots.  Added a caching mechanism for reminders that have already been matched.
* v2.3.4 (Feb 7, 2006)
**Bug fix: Cleaned up code to hopefully prevent the Firefox crash that was causing lots of plugins 
to crash Firefox.  Thanks to
* v2.3.3 (Feb 2, 2006)
**Feature: newReminder now has drop down lists instead of text boxes.
**Bug fix:  A trailing space in a title would trigger an infinite loop.
**Bug fix:  using tag:"birthday !reminder" would filter differently than tag:"!reminder birthday"
* v2.3.2 (Jan 21, 2006)
**Feature: newReminder macro, which will let you easily add a reminder to a tiddler. Thanks to Eric Shulman ( for the code to do this.
** Bug fix: offsetday was not working sometimes
** Bug fix: when upgrading to 2.0, I included a bit to exclude tiddlers tagged with excludeSearch.  I've reverted back to searching through all tiddlers
* v2.3.1 (Jan 7, 2006)
**Feature: 2.0 compatibility
**Feature AlanH sent some code to make sure that showReminders prints a message if no reminders are found.
* v2.3.0 (Jan 3, 2006)
** Bug Fix:  Using "Last Sunday (-0)" as a offsetdayofweek wasn't working.
** Bug Fix:  Daylight Savings time broke offset based reminders (for example year:2005 month:8 day:23 recurdays:7 would match Monday instead of Tuesday during DST.


//           ReminderPlugin

version.extensions.ReminderPlugin = {major: 2, minor: 3, revision: 8, date: new Date(2006,3,9), source: ""};

// Configuration
// Modify this section to change the defaults for 
// leadtime and display strings

config.macros.reminders = {};
config.macros["reminder"] = {};
config.macros["newReminder"] = {};
config.macros["showReminders"] = {};
config.macros["displayTiddlersWithReminders"] = {};

config.macros.reminders["defaultLeadTime"] = [0,6000];
config.macros.reminders["defaultReminderMessage"] = "DIFF: TITLE: DATE ANNIVERSARY";
config.macros.reminders["defaultShowReminderMessage"] = "DIFF: TITLE: DATE ANNIVERSARY -- TIDDLER";
config.macros.reminders["defaultAnniversaryMessage"] = "(DIFF-летие)";
config.macros.reminders["untitledReminder"] = "Что-то";
config.macros.reminders["noReminderFound"] = "В ближайшие дни (LEADTIMEUPPER) TITLE отсутствует в планах."
config.macros.reminders["todayString"] = "''Сегодня''";
config.macros.reminders["tomorrowString"] = "''Завтра''";
config.macros.reminders["ndaysString"] = "Через DIFF дней";
config.macros.reminders["emtpyShowRemindersString"] = "Ничего не запланировано!";

//  Code
// You should not need to edit anything 
// below this.  Make sure to edit this tiddler and copy 
// the code from the text box, to make sure that 
// tiddler rendering doesn't interfere with the copy 
// and paste.

// This line is to preserve 1.2 compatibility
 if (!story) var story=window; 
//this object will hold the cache of reminders, so that we don't
//recompute the same reminder over again.
var reminderCache = {};

config.macros.showReminders.handler = function showReminders(place,macroName,params)
   var now = new Date().getMidnight();
   var paramHash = {};
   var leadtime = [0,14];
   paramHash = getParamsForReminder(params);
   var bProvidedDate = (paramHash["year"] != null) || 
			(paramHash["month"] != null) || 
			(paramHash["day"] != null) || 
			(paramHash["dayofweek"] != null);
   if (paramHash["leadtime"] != null)
      leadtime = paramHash["leadtime"];
      if (bProvidedDate)
         //If they've entered a day, we need to make 
         //sure to find it.  We'll reset the 
         //leadtime a few lines down.
         paramHash["leadtime"] = [-10000, 10000];
   var matchedDate = now;
   if (bProvidedDate)
      var leadTimeLowerBound = new Date().getMidnight().addDays(paramHash["leadtime"][0]);
      var leadTimeUpperBound = new Date().getMidnight().addDays(paramHash["leadtime"][1]);
      matchedDate = findDateForReminder(paramHash, new Date().getMidnight(), leadTimeLowerBound, leadTimeUpperBound); 

   var arr = findTiddlersWithReminders(matchedDate, leadtime, paramHash["tag"], paramHash["limit"]);
   var elem = createTiddlyElement(place,"span",null,null, null);
   var mess = "";
   if (arr.length == 0)
      mess += config.macros.reminders.emtpyShowRemindersString; 
   for (var j = 0; j < arr.length; j++)
      if (paramHash["format"] != null)
         arr[j]["params"]["format"] = paramHash["format"];
         arr[j]["params"]["format"] = config.macros.reminders["defaultShowReminderMessage"];
      mess += getReminderMessageForDisplay(arr[j]["diff"], arr[j]["params"], arr[j]["matchedDate"], arr[j]["tiddler"]);
      mess += "\n";
   wikify(mess, elem, null, null);

config.macros.displayTiddlersWithReminders.handler = function displayTiddlersWithReminders(place,macroName,params)
   var now = new Date().getMidnight();
   var paramHash = {};
   var leadtime = [0,14];
   paramHash = getParamsForReminder(params);
   var bProvidedDate = (paramHash["year"] != null) || 
			(paramHash["month"] != null) || 
			(paramHash["day"] != null) || 
			(paramHash["dayofweek"] != null);
   if (paramHash["leadtime"] != null)
      leadtime = paramHash["leadtime"];
      if (bProvidedDate)
         //If they've entered a day, we need to make 
         //sure to find it.  We'll reset the leadtime 
         //a few lines down.
         paramHash["leadtime"] = [-10000,10000];
   var matchedDate = now;
   if (bProvidedDate)
      var leadTimeLowerBound = new Date().getMidnight().addDays(paramHash["leadtime"][0]);
      var leadTimeUpperBound = new Date().getMidnight().addDays(paramHash["leadtime"][1]);
      matchedDate = findDateForReminder(paramHash, new Date().getMidnight(), leadTimeLowerBound, leadTimeUpperBound); 
   var arr = findTiddlersWithReminders(matchedDate, leadtime, paramHash["tag"], paramHash["limit"]);
   for (var j = 0; j < arr.length; j++)
      displayTiddler(null, arr[j]["tiddler"], 0, null, false, false, false);

config.macros.reminder.handler = function reminder(place,macroName,params)
   var dateHash = getParamsForReminder(params);
   if (dateHash["hidden"] != null)
   var leadTime = dateHash["leadtime"];
   if (leadTime == null)
      leadTime = config.macros.reminders["defaultLeadTime"]; 
   var leadTimeLowerBound = new Date().getMidnight().addDays(leadTime[0]);
   var leadTimeUpperBound = new Date().getMidnight().addDays(leadTime[1]);
   var matchedDate = findDateForReminder(dateHash, new Date().getMidnight(), leadTimeLowerBound, leadTimeUpperBound);
   if (!window.story) 
   if (!store.getTiddler) 
      store.getTiddler=function(title) {return this.tiddlers[title];};
   var title = window.story.findContainingTiddler(place).id.substr(7);
   if (matchedDate != null)
      var diff = matchedDate.getDifferenceInDays(new Date().getMidnight());
      var elem = createTiddlyElement(place,"span",null,null, null);
      var mess = getReminderMessageForDisplay(diff, dateHash, matchedDate, title);
      wikify(mess, elem, null, null);
      createTiddlyElement(place,"span",null,null, config.macros.reminders["noReminderFound"].replace("TITLE", dateHash["title"]).replace("LEADTIMEUPPER", leadTime[1]).replace("LEADTIMELOWER", leadTime[0]).replace("TIDDLERNAME", title).replace("TIDDLER", "[[" + title + "]]") );

config.macros.newReminder.handler = function newReminder(place,macroName,params)
  var today=new Date().getMidnight();
  var formstring = '<html><form>год: <select name="year"><option value="">Каждый год</option>';
  for (var i = 0; i < 5; i++)
    formstring += '<option' + ((i == 0) ? ' selected' : '') + ' value="' + (today.getFullYear() +i) + '">' + (today.getFullYear() + i) + '</option>';
formstring += '</select>&nbsp;&nbsp;день:<select name="day"><option value="">Каждый день</option>';
  for (i = 1; i < 32; i++)
    formstring += '<option' + ((i == (today.getDate() )) ? ' selected' : '') + ' value="' + i + '">' + i + '</option>';

  formstring += '</select>&nbsp;&nbsp;месяца:<select name="month"><option value="">Каждый месяц</option>';
  for (i = 0; i < 12; i++)
    formstring += '<option' + ((i == today.getMonth()) ? ' selected' : '') + ' value="' + (i+1) + '">' + config.messages.dates.months[i] + '</option>';
formstring += '</select>&nbsp;&nbsp;<br />название:<input type="text" size="40" name="title" value="Введите название. Можно форматировать." onfocus=";"><input type="button" value="Добавить" onclick="addReminderToTiddler(this.form)"></form></html>';

  var panel = config.macros.slider.createSlider(place,null,"Добавить новое напоминание","Откройте, чтобы добавить напоминание в эту запись");
  wikify(formstring ,panel,null,store.getTiddler(params[1]));

// onclick: process input and insert reminder at 'marker'
window.addReminderToTiddler = function(form) {
   if (!window.story) 
   if (!store.getTiddler) 
      store.getTiddler=function(title) {return this.tiddlers[title];};
   var title = window.story.findContainingTiddler(form).id.substr(7);
   var tiddler=store.getTiddler(title);
  var txt='\n<<reminder ';
  if (form.year.value != "")
    txt += 'year:'+form.year.value + ' ';
  if (form.month.value != "")
    txt += 'month:'+form.month.value + ' ';
  if ( != "")
    txt += 'day:' + ' ';
  txt += 'title:"'+form.title.value+'" ';
  txt +='>>';
   tiddler.set(null,tiddler.text + txt);

function hasTag(tiddlerTags, tagFilters)
  //Make sure we respond well to empty tiddlerTaglists or tagFilterlists
  if (tagFilters.length==0 || tiddlerTags.length==0)
    return true;

  var bHasTag = false;
  /*bNoPos says: "'till now there has been no check using a positive filter"
     Imagine a filterlist consisting of 1 negative filter:
         If the filter isn't matched, we want hasTag to be true.
         Yet bHasTag is still false ('cause only positive filters cause bHasTag to change)
     If no positive filters are present bNoPos is true, and no negative filters are matched so we have not returned false
         Thus: hasTag returns true.
      If at any time a positive filter is encountered, we want at least one of the tags to match it, so we turn bNoPos to false, which
      means bHasTag must be true for hasTag to return true*/
  var bNoPos=true;
for (var t3 = 0; t3 < tagFilters.length; t3++)
      for(var t2=0; t2<tiddlerTags.length; t2++)
           if (tagFilters[t3].length > 1 && tagFilters[t3].charAt(0) == '!') 
              if (tiddlerTags[t2] == tagFilters[t3].substring(1))
                 //If at any time a negative filter is matched, we return false
                  return false;
              if (bNoPos)
                 //We encountered the first positive filter
              if (tiddlerTags[t2] == tagFilters[t3])
                  //A positive filter is matched. As long as no negative filter is matched, hasTag will return true
    return (bNoPos || bHasTag);

//This function searches all tiddlers for the reminder  //macro.  It is intended that other plugins (like //calendar) will use this function to query for 
//upcoming reminders.
//The arguments to this function filter out reminders //based on when they will fire.
//baseDate is the date that is used as "now".  
//leadtime is a two element int array, with leadtime[0] 
//         as the lower bound and leadtime[1] as the
//         upper bound.  A reasonable default is [0,14]
//tags is a space-separated list of tags to use to filter 
//         tiddlers.  If a tag name begins with an !, then 
//         only tiddlers which do not have that tag will 
//         be considered.  For example "examples holidays"  
//         will search for reminders in any tiddlers that  
//         are tagged with examples or holidays and 
//         "!examples !holidays" will search for reminders 
//         in any tiddlers that are not tagged with 
//         examples or holidays.  Pass in null to search 
//         all tiddlers.
//limit.  If limit is null, individual reminders can 
//        override the leadtime specified earlier.  
//        Pass in 1 in order to override that behavior.

window.findTiddlersWithReminders = function findTiddlersWithReminders(baseDate, leadtime, tags, limit)
//   var macroPattern = "<<([^>\\]+)(?:\\*)([^>]*)>>";
   var macroPattern = "<<(reminder)(.*)>>";
   var macroRegExp = new RegExp(macroPattern,"mg");
   var matches =,"title","");
   var arr = [];
   var tagsArray = null;
   if (tags != null)
      tagsArray = tags.split(" ");
   for(var t=matches.length-1; t>=0; t--)
      if (tagsArray != null)
         //If they specified tags to filter on, and this tiddler doesn't 
	 //match, skip it entirely.
         if ( ! hasTag(matches[t].tags, tagsArray))

      var targetText = matches[t].text;
      do {
         // Get the next formatting match
         var formatMatch = macroRegExp.exec(targetText);
         if(formatMatch && formatMatch[1] != null && formatMatch[1].toLowerCase() == "reminder")
            //Find the matching date.
            var params = formatMatch[2] != null ? formatMatch[2].readMacroParams() : {};
            var dateHash = getParamsForReminder(params);
            if (limit != null || dateHash["leadtime"] == null)
               if (leadtime == null)
                   dateHash["leadtime"] = leadtime;
                  dateHash["leadtime"] = [];
                  dateHash["leadtime"][0] = leadtime[0];
                  dateHash["leadtime"][1] = leadtime[1];
	    if (dateHash["leadtime"] == null)
               dateHash["leadtime"] = config.macros.reminders["defaultLeadTime"]; 
            var leadTimeLowerBound = baseDate.addDays(dateHash["leadtime"][0]);
            var leadTimeUpperBound = baseDate.addDays(dateHash["leadtime"][1]);
            var matchedDate = findDateForReminder(dateHash, baseDate, leadTimeLowerBound, leadTimeUpperBound);
            while (matchedDate != null)
               var hash = {};
               hash["diff"] = matchedDate.getDifferenceInDays(baseDate);
               hash["matchedDate"] = new Date(matchedDate.getFullYear(), matchedDate.getMonth(), matchedDate.getDate(), 0, 0);
               hash["params"] = cloneParams(dateHash);
               hash["tiddler"] = matches[t].title;
               hash["tags"] = matches[t].tags;
	       if (dateHash["recurdays"] != null || (dateHash["year"] == null))
	         leadTimeLowerBound = leadTimeLowerBound.addDays(matchedDate.getDifferenceInDays(leadTimeLowerBound)+ 1);
                 matchedDate = findDateForReminder(dateHash, baseDate, leadTimeLowerBound, leadTimeUpperBound);
	       else matchedDate = null;
   if(arr.length > 1)  //Sort the array by number of days remaining.
      arr.sort(function (a,b) {if(a["diff"] == b["diff"]) {return(0);} else {return (a["diff"] < b["diff"]) ? -1 : +1; } });
   return arr;

//This function takes the reminder macro parameters and
//generates the string that is used for display.
//This function is not intended to be called by 
//other plugins.
 window.getReminderMessageForDisplay= function getReminderMessageForDisplay(diff, params, matchedDate, tiddlerTitle)
   var anniversaryString = "";
   var reminderTitle = params["title"];
   if (reminderTitle == null)
      reminderTitle = config.macros.reminders["untitledReminder"];
   if (params["firstyear"] != null)
      anniversaryString = config.macros.reminders["defaultAnniversaryMessage"].replace("DIFF", (matchedDate.getFullYear() - params["firstyear"]));
   var mess = "";
   var diffString = "";
   if (diff == 0)
      diffString = config.macros.reminders["todayString"];
   else if (diff == 1)
      diffString = config.macros.reminders["tomorrowString"];
   else if (diff == 2)
      diffString = "''Послезавтра''";
   else if (diff == -1)
      diffString = "//Вчера//";
   else if (diff == -2)
      diffString = "//Позавчера//";
      diff-=1; //HACK(ru)
      diffString = config.macros.reminders["ndaysString"].replace("DIFF", diff);
   var format = config.macros.reminders["defaultReminderMessage"];
   if (params["format"] != null)
      format = params["format"];
   mess = format;
//HACK!  -- Avoid replacing DD in TIDDLER with the date
   mess = mess.replace(/TIDDLER/g, "TIDELER");
   mess = matchedDate.formatStringDateOnly(mess);
   mess = mess.replace(/TIDELER/g, "TIDDLER");
   if (tiddlerTitle != null)
      mess = mess.replace(/TIDDLERNAME/g, tiddlerTitle);
      mess = mess.replace(/TIDDLER/g, "[[" + tiddlerTitle + "]]");
   mess = mess.replace("DIFF", diffString).replace("TITLE", reminderTitle).replace("DATE", matchedDate.formatString("DDD, [[DD MMM]], YYYY")).replace("ANNIVERSARY", anniversaryString);
   var daysS = diff.toString();
   var lastD = daysS.charAt(daysS.length-1);
   var lastDs = daysS.substring(daysS.length-2 );

   var rD = "дней";
   var rD1 = "1";
   var rD234 = "2-3-4";
   var rD5_9 = "5-6-7-8-9";

   daysS = daysS.substring(daysS.length-2);

if( (lastDs.indexOf("14") == -1)&&(lastDs.indexOf("13") == -1)&&(lastDs.indexOf("12") == -1)&&(lastDs.indexOf("11") == -1) ){
      if (rD1.indexOf(lastD)!=-1){
         rD = "день";  
      if (rD234.indexOf(lastD)!=-1){
         rD = "дня";  

mess = mess.replace(/Через -/, ""  );
mess = mess.replace(/ дней/, " дней назад"  );
   mess = mess.replace(/ дней/, " "+rD  );
   return mess;

// Parse out the macro parameters into a hashtable.  This
// handles the arguments for reminder, showReminders and 
// displayTiddlersWithReminders.
window.getParamsForReminder = function getParamsForReminder(params)
   var dateHash = {};
   var type = "";
   var num = 0;
   var title = "";
   for(var t=0; t<params.length; t++)
      var split = params[t].split(":");
      type = split[0].toLowerCase();
      var value = split[1];
      for (var i=2; i < split.length; i++)
         value += ":" + split[i];
      if (type == "nolinks" || type == "limit" || type == "hidden")
         num = 1;
      else if (type == "leadtime")
         var leads = value.split("...");
         if (leads.length == 1)
            leads[1]= leads[0];
            leads[0] = 0;
         leads[0] = parseInt(leads[0], 10);
         leads[1] = parseInt(leads[1], 10);
         num = leads;
      else if (type == "offsetdayofweek")
          if (value.substr(0,1) == "-")
             dateHash["negativeOffsetDayOfWeek"] = 1;
	     value = value.substr(1);
          num = parseInt(value, 10);
      else if (type != "title" && type != "tag" && type != "format")
         num = parseInt(value, 10);
         title = value;
         while (title.substr(0,1) == '"' && title.substr(title.length - 1,1) != '"' && params[t] != undefined)
            title += " " + params[t++];
         //Trim off the leading and trailing quotes
         if (title.substr(0,1) == "\"" && title.substr(title.length - 1,1)== "\"")
            title = title.substr(1, title.length - 2);
         num = title;
      dateHash[type] = num;
   //date is synonymous with day
   if (dateHash["day"] == null)
      dateHash["day"] = dateHash["date"];
   return dateHash;

//This function finds the date specified in the reminder 
//parameters.  It will return null if no match can be
//found.  This function is not intended to be used by
//other plugins.
window.findDateForReminder= function findDateForReminder( dateHash, baseDate, leadTimeLowerBound, leadTimeUpperBound)
   if (baseDate == null)
     baseDate = new Date().getMidnight();
   var hashKey = baseDate.convertToYYYYMMDDHHMM();
   for (var k in dateHash)
      hashKey += "," + k + "|" + dateHash[k];
   hashKey += "," + leadTimeLowerBound.convertToYYYYMMDDHHMM();
   hashKey += "," + leadTimeUpperBound.convertToYYYYMMDDHHMM();
   if (reminderCache[hashKey] == null)
      //If we don't find a match in this run, then we will
      //cache that the reminder can't be matched.
      reminderCache[hashKey] = false;
   else if (reminderCache[hashKey] == false)
      //We've already tried this date and failed
      return null;
      return reminderCache[hashKey];
   var bOffsetSpecified = dateHash["offsetyear"] != null || 
				dateHash["offsetmonth"] != null || 
				dateHash["offsetday"] != null || 
				dateHash["offsetdayofweek"] != null || 
				dateHash["recurdays"] != null;
   // If we are matching the base date for a dayofweek offset, look for the base date a 
   //little further back.
   var tmp1leadTimeLowerBound = leadTimeLowerBound;  
   if ( dateHash["offsetdayofweek"] != null)
      tmp1leadTimeLowerBound = leadTimeLowerBound.addDays(-6);  
   var matchedDate = baseDate.findMatch(dateHash, tmp1leadTimeLowerBound, leadTimeUpperBound);
   if (matchedDate != null)
      var newMatchedDate = matchedDate;
      if (dateHash["recurdays"] != null)
         while (newMatchedDate.getTime() < leadTimeLowerBound.getTime())
            newMatchedDate = newMatchedDate.addDays(dateHash["recurdays"]);
      else if (dateHash["offsetyear"] != null || 
		dateHash["offsetmonth"] != null || 
		dateHash["offsetday"] != null || 
		dateHash["offsetdayofweek"] != null)
         var tmpdateHash = cloneParams(dateHash);
         tmpdateHash["year"] = dateHash["offsetyear"];
         tmpdateHash["month"] = dateHash["offsetmonth"];
         tmpdateHash["day"] = dateHash["offsetday"];
         tmpdateHash["dayofweek"] = dateHash["offsetdayofweek"];
	 var tmpleadTimeLowerBound = leadTimeLowerBound;
	 var tmpleadTimeUpperBound = leadTimeUpperBound;
	 if (tmpdateHash["offsetdayofweek"] != null)
	 	if (tmpdateHash["negativeOffsetDayOfWeek"] == 1)
		   tmpleadTimeLowerBound = matchedDate.addDays(-6);
		   tmpleadTimeUpperBound = matchedDate;

		   tmpleadTimeLowerBound = matchedDate;
		   tmpleadTimeUpperBound = matchedDate.addDays(6);

	 newMatchedDate = matchedDate.findMatch(tmpdateHash, tmpleadTimeLowerBound, tmpleadTimeUpperBound);
         //The offset couldn't be matched.  return null.
         if (newMatchedDate == null)
            return null;
      if (newMatchedDate.isBetween(leadTimeLowerBound, leadTimeUpperBound))
         reminderCache[hashKey] = newMatchedDate;
         return newMatchedDate;
   return null;

//This does much the same job as findDateForReminder, but
//this one doesn't deal with offsets or recurring 
Date.prototype.findMatch = function findMatch(dateHash, leadTimeLowerBound, leadTimeUpperBound)

   var bSpecifiedYear =     (dateHash["year"] != null);
   var bSpecifiedMonth =     (dateHash["month"] != null);
   var bSpecifiedDay =     (dateHash["day"] != null);
   var bSpecifiedDayOfWeek =     (dateHash["dayofweek"] != null);
   if (bSpecifiedYear && bSpecifiedMonth && bSpecifiedDay)
      return new Date(dateHash["year"], dateHash["month"]-1, dateHash["day"], 0, 0);
   var bMatchedYear = !bSpecifiedYear;
   var bMatchedMonth = !bSpecifiedMonth;
   var bMatchedDay = !bSpecifiedDay;
   var bMatchedDayOfWeek = !bSpecifiedDayOfWeek;
   if (bSpecifiedDay && bSpecifiedMonth && !bSpecifiedYear && !bSpecifiedDayOfWeek)

      //Shortcut -- First try this year.  If it's too small, try next year.
      var tmpMidnight = this.getMidnight();
      var tmpDate = new Date(this.getFullYear(), dateHash["month"]-1, dateHash["day"], 0,0);
      if (tmpDate.getTime() < leadTimeLowerBound.getTime())
         tmpDate = new Date((this.getFullYear() + 1), dateHash["month"]-1, dateHash["day"], 0,0);
      if ( tmpDate.isBetween(leadTimeLowerBound, leadTimeUpperBound))
         return tmpDate;
         return null;

   var newDate = leadTimeLowerBound; 
   while (newDate.isBetween(leadTimeLowerBound, leadTimeUpperBound))
      var tmp = testDate(newDate, dateHash, bSpecifiedYear, bSpecifiedMonth, bSpecifiedDay, bSpecifiedDayOfWeek);
      if (tmp != null)
        return tmp;
      newDate = newDate.addDays(1);

function testDate(testMe, dateHash, bSpecifiedYear, bSpecifiedMonth, bSpecifiedDay, bSpecifiedDayOfWeek)
   var bMatchedYear = !bSpecifiedYear;
   var bMatchedMonth = !bSpecifiedMonth;
   var bMatchedDay = !bSpecifiedDay;
   var bMatchedDayOfWeek = !bSpecifiedDayOfWeek;
   if (bSpecifiedYear)
      bMatchedYear = (dateHash["year"] == testMe.getFullYear());
   if (bSpecifiedMonth)
      bMatchedMonth = ((dateHash["month"] - 1)  == testMe.getMonth() );
   if (bSpecifiedDay)
      bMatchedDay = (dateHash["day"] == testMe.getDate());
   if (bSpecifiedDayOfWeek)
      bMatchedDayOfWeek = (dateHash["dayofweek"] == testMe.getDay());

   if (bMatchedYear && bMatchedMonth && bMatchedDay && bMatchedDayOfWeek)
      return testMe;

//Returns true if the date is in between two given dates
Date.prototype.isBetween = function isBetween(lowerBound, upperBound)
  return (this.getTime() >= lowerBound.getTime() && this.getTime() <= upperBound.getTime());
//Return a new date, with the time set to midnight (0000)
Date.prototype.getMidnight = function getMidnight()
   return new Date(this.getFullYear(), this.getMonth(), this.getDate(), 0, 0);
// Add the specified number of days to a date.
Date.prototype.addDays = function addDays(numberOfDays)
   return new Date(this.getFullYear(), this.getMonth(), this.getDate() + numberOfDays, 0, 0);
//Return the number of days between two dates.
Date.prototype.getDifferenceInDays = function getDifferenceInDays(otherDate)
//I have to do it this way, because this way ignores daylight savings
   var tmpDate = this.addDays(0);
   if (this.getTime() > otherDate.getTime())
      var i = 0;
      for (i = 0; tmpDate.getTime() > otherDate.getTime(); i++)
         tmpDate = tmpDate.addDays(-1);
      return i;
      var i = 0;
      for (i = 0; tmpDate.getTime() < otherDate.getTime(); i++)
         tmpDate = tmpDate.addDays(1);
      return i * -1;
   return 0;
function cloneParams(what) {
    var tmp = {};
    for (var i in what) {
        tmp[i] = what[i];
    return tmp;
// Substitute date components into a string
Date.prototype.formatStringDateOnly = function formatStringDateOnly(template)
	template = template.replace("YYYY",this.getFullYear());
	template = template.replace("YY",String.zeroPad(this.getFullYear()-2000,2));
	template = template.replace("MMM",config.messages.dates.months[this.getMonth()]);
	template = template.replace("0MM",String.zeroPad(this.getMonth()+1,2));
	template = template.replace("MM",this.getMonth()+1);
	template = template.replace("DDD",config.messages.dates.days[this.getDay()]);
	template = template.replace("0DD",String.zeroPad(this.getDate(),2));
	template = template.replace("DD",this.getDate());
	return template;

|''Description:''|TW russianization|
|''Author:''|Глеб Тржемецкий (Gleb Trzhemetski)|
|''License:''|BSD open source license|
|''Browser:''|Firefox 1.0.4+; Firefox 1.5; InternetExplorer 6.0|



	customConfigError: "Возникли проблемы при загрузке плагинов. См. PluginManager ",
	pluginError: "Ошибка: %0",
	pluginDisabled: "Не задействован, так как помечен 'systemConfigDisable' ",
	pluginForced: "Задействован, так как помечен 'systemConfigForce' ",
	pluginVersionError: "Не задействован из-за несоответствия версий",
	nothingSelected: "Ничего не выделено.",
	savedSnapshotError: "Похоже, эта wiki была неправильно сохранена. См. ",
	subtitleUnknown: "(неизвестно)",
	undefinedTiddlerToolTip: "Записи '%0' не существует",
	shadowedTiddlerToolTip: "Запись '%0' заполнена по умолчанию.",
	tiddlerLinkTooltip: "%0 - %1, %2",
	externalLinkTooltip: "Ссылка: %0",
	noTags: "Нет помеченных записей",
	notFileUrlError: "Сохраните TiddlyWiki в файл, чтобы иметь возможность сохранять изменения ",
	cantSaveError: "Сохранение невозможно. Либо ваш браузер не подерживает эту функцию (используйте по возможности FireFox), либо путь к файлу содержит недопустимые символы",
	invalidFileError: "Файл '%0' не похож на файл TiddlyWiki",
	backupSaved: "Резервная копия сохранена",
	backupFailed: "Не получилось сохранить резервную копию",
	rssSaved: "RSS сохранен",
	rssFailed: "Не получилось сохранить RSS",
	emptySaved: "Пустой шаблон сохранен",
	emptyFailed: "Не получилось сохранить пустой шаблон",
	mainSaved: "Файл TiddlyWiki сохранен",
	mainFailed: "Не получилось сохранить файл TiddlyWiki. Изменения не сохранены",
	macroError: "Ошибка в сценарии <<%0>>",
	macroErrorDetails: "Ошибка при выполнении сценария  <<%0>>:\n%1",
	missingMacro: "Нет такого сценария",
	overwriteWarning: "Запись '%0' уже есть. Нажмите OK, чтобы перезаписать",
	unsavedChangesWarning: "ВНИМАНИЕ! Есть несохраненные изменения! \n\nНажмите OK, чтобы сохранить\nНажмите CANCEL чтобы не сохранять",
	confirmExit: "--------------------------------\n\nИзменения в TiddlyWiki не сохранены. Если вы продолжите, они потеряются.\n\n--------------------------------",
	saveInstructions: "SaveChanges",
	unsupportedTWFormat: "Неподдерживаемый TiddlyWiki формат '%0'",
	tiddlerSaveError: "Ошибка при сохранении записи '%0'",
	tiddlerLoadError: "Ошибка при открытии записи '%0'",
	wrongSaveFormat: "Не получается сохранить в формате '%0'. Сохранено в стандартном формате.",
	invalidFieldName: "Недопустимое имя поля %0",
	fieldCannotBeChanged: "Поле '%0' нельзя изменять"});

	text: "×",
	tooltip: "скрыть сообщение"});

config.messages.dates.months = ["января", "февраля", "марта", "апреля", "мая", "июня", "июля", "августа", "сентября", "октября", "ноября","декабря"];
config.messages.dates.days = ["Воскресенье", "Понедельник", "Вторник", "Среда", "Четверг", "Пятница", "Суббота"];
config.messages.dates.shortMonths = ["I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX", "X", "XI", "XII"];
config.messages.dates.shortDays = ["Вс", "Пн", "Вт", "Ср", "Чт", "Пт", "Сб"];

	labelNoTags: "меток нет",
	labelTags: "метки: ",
	openTag: "Открыть метку '%0'",
	tooltip: "Показать записи, помеченные как '%0'",
	openAllText: "Открыть все",
	openAllTooltip: "Открыть все эти записи",
	popupNone: "Нет других записей с меткой '%0'"});

	defaultText: "Записи '%0' не существует. Создайте ее двойным щелчком.",
	defaultModifier: "(?)",
	shadowModifier: "(системная запись)",
	createdPrompt: "создана: "});

	tagPrompt: "Введите метки, разделенные пробелами, [[используйте квадратные скобки]] если нужно, или выберите метки из списка.",
	defaultText: "Здесь мог бы быть осмысленный текст на тему '%0'"});

	text: "метки",
	tooltip: "Выберите метки из списка",
	popupNone: "Меток пока нет",
	tagTooltip: "Добавить метку '%0'"});

	label: "поиск",
	prompt: "Поиск по всем записям",
	accessKey: "F",
	successMsg: "%0 записей, соответствующих критерию: %1",
	failureMsg: "Не найдено записей по запросу: %0"});

	label: "отмечены: ",
	labelNotTag: "нету",
	tooltip: "Список записей, помеченных: '%0'"});

	dateFormat: "DD.mmm.YYYY"});

	tooltip: "Показать записи, помеченные '%0'",
	noTags: "Нет таких записей"});

config.macros.list.all.prompt = "Все записи по алфавиту";
config.macros.list.missing.prompt = "Ненаписанные";
config.macros.list.orphans.prompt = "Записи, на которые нет ссылок";
config.macros.list.shadowed.prompt = "Системные записи";

	label: "закрыть все",
	prompt: "Закрыть все записи \(кроме редактируемых\)"});

	label: "ссылка",
	prompt: "Постоянная ссылка"});

	label: "сохранить изменения",
	prompt: "Сохранить всё",
	accessKey: "S"});

	label: "новая запись",
	prompt: "Создать новую запись",
	title: "Новая запись",
	accessKey: "N"});

	label: "новая датированная запись",
	prompt: "Создать запись, с названием, соответствующим текущей дате",
	accessKey: "J"});

	skippedText: "(Этот плагин не запущен, так как был добавлен после запуска)",
	noPluginText: "Плагинов нет",
	confirmDeleteText: "Вы действительно хотите удалить записи:\n\n%0",
	listViewTemplate : {
		columns: [
			{name: 'Selected', field: 'Selected', rowName: 'title', type: 'Selector'},
			{name: 'Title', field: 'title', tiddlerLink: 'title', title: "Title", type: 'TiddlerLink'},
			{name: 'Forced', field: 'forced', title: "Forced", tag: 'systemConfigForce', type: 'TagCheckbox'},
			{name: 'Disabled', field: 'disabled', title: "Disabled", tag: 'systemConfigDisable', type: 'TagCheckbox'},
			{name: 'Executed', field: 'executed', title: "Loaded", type: 'Boolean', trueText: "Yes", falseText: "No"},
			{name: 'Error', field: 'error', title: "Status", type: 'Boolean', trueText: "Error", falseText: "OK"},
			{name: 'Log', field: 'log', title: "Log", type: 'StringList'}
		rowClasses: [
			{className: 'error', field: 'error'},
			{className: 'warning', field: 'warning'}
		actions: [
			{caption: "Действия...", name: ''},
			{caption: "Сделать не системной записью", name: 'remove'},
			{caption: "Удалить из wiki", name: 'delete'}

	label: "обновить",
	prompt: "Обновить отображение"

	defaultPath: "",
	fetchLabel: "загрузить",
	fetchPrompt: "Загрузить файл TiddlyWiki",
	fetchError: "Ошибка при загрузке файла",
	confirmOverwriteText: "Вы уверены, что хотите перезаписать следующие записи:\n\n%0",
	wizardTitle: "Импорт записей из файла TiddlyWiki",
	step1: "Шаг 1: Введите путь к файлу",
	step1prompt: "Введите URL или путь к локальному файлу: ",
	step1promptFile: "...или выберите тут: ",
	step1promptFeeds: "...или из предустановленных: ",
	step1feedPrompt: "Выберите...",
	step2: "Шаг 2: Загрузка файла",
	step2Text: "Дождитесь окончания загрузки: %0",
	step3: "Шаг 3: Выберите записи для импорта:",
	step4: "%0 записей импортировано",
	step5: "Готово!",
	listViewTemplate: {
		columns: [
			{name: 'Selected', field: 'Selected', rowName: 'title', type: 'Selector'},
			{name: 'Title', field: 'title', title: "Title", type: 'String'},
			{name: 'Snippet', field: 'text', title: "Snippet", type: 'String'},
			{name: 'Tags', field: 'tags', title: "Tags", type: 'Tags'}
		rowClasses: [
		actions: [
			{caption: "Действия...", name: ''},
			{caption: "Импортировать", name: 'import'}

	text: "закрыть",
	tooltip: "Закрыть запись"});

	text: "закрыть остальные",
	tooltip: "Закрыть все записи, кроме этой"});

	text: "редактировать",
	tooltip: "Редактировать запись",
	readOnlyText: "исходный код",
	readOnlyTooltip: "Просмотреть исходный код записи"});

	text: "готово",
	tooltip: "Сохранить изменения"});

	text: "отменить",
	tooltip: "Отменить изменения",
	warning: "Вы уверены, что не хотите сохранить запись '%0'?",
	readOnlyText: "обычный вид",
	readOnlyTooltip: "Вернуться к обычному просмотру"});

	text: "удалить",
	tooltip: "Удалить запись",
	warning: "Вы действительно хотите удалить '%0'?"});

	text: "ссылка",
	tooltip: "Постоянная ссылка на эту запись"});

	text: "ссылки сюда",
	tooltip: "Показать записи, ссылающиеся на эту",
	popupNone: "Ссылок нет"});

	text: "перейти...",
	tooltip: "Перейти на другие открытые записи"});

	DefaultTiddlers: "GettingStarted",
	MainMenu: "GettingStarted",
	SiteTitle: "~TiddlyWiki(ru)",
	SiteSubtitle: "нелинейный гипертекстовый органайзер",
	SiteUrl: "",
	GettingStarted: "Для того, чтобы начать работать с TiddlyWiki, вы можете поменять следующие записи:\n* SiteTitle & SiteSubtitle: Заголовок и подзаголовок сайта (после сохранения вы увидите их в заголовке окна)\n* MainMenu: Меню (оно обычно слева)\n* DefaultTiddlers: Список записей, которые будут открыты при запуске wiki.\nИмя, которым будут подписаны ваши записи, можете ввести тут: <<option txtUserName>>",
	SideBarOptions: "<<search>><<closeAll>><<permaview>><<newTiddler>><<newJournal 'DD MMM YYYY г.'>><<saveChanges>><<slider chkSliderOptionsPanel OptionsPanel 'установки »' 'Различные опции TidlyWiki'>>",
	OptionsPanel: "Эти установки сохраняются в&nbsp\;Вашем браузере\n\nВаше имя для подписывания заметок. Лучше, если вы напишете его WotTak\n\n<<option txtUserName>>\n<<option chkSaveBackups>> Сохранять резервные копии\n<<option chkAutoSave>> Автосохранение\n<<option chkRegExpSearch>> Поиск с&nbsp\;регулярными выражениями\n<<option chkCaseSensitiveSearch>> Поиск чувствителен к&nbsp\;регистру?\n<<option chkAnimate>> Анимация\n\n----\n[[Дополнительно|AdvancedOptions]]\n[[Плагины|PluginManager]]\n[[Импорт записей|ImportTiddlers]]",
	AdvancedOptions: "<<option chkGenerateAnRssFeed>> Публиковать RSS\n<<option chkOpenInNewWindow>>  Ссылки в новом окне\n<<option chkSaveEmptyTemplate>> Сохранять пустой шаблон\n<<option chkToggleLinks>> Щелчок по ссылке на открытую заметку закрывает ее\n^^(с Ctrl или другой функциональной клавишей не&nbsp\;будет срабатывать)^^\n<<option chkHttpReadOnly>> Не показывать инструменты редактирования через HTTP\n<<option chkForceMinorUpdate>> Не менять дату заметки при редактировании\n^^(для изменеия - жмите Shift при сохранеии, либо сохраняйте, нажимая Ctrl-Shift-Enter^^\n<<option chkConfirmDelete>> Подтверждать удаление\nМаксимум строк в&nbsp\;поле редактирования: <<option txtMaxEditRows>>\nСохранять бэкапы в&nbsp\;папке: <<option txtBackupFolder>>\n<<option chkInsertTabs>> При нажатии Tab вводить знак табуляции, а&nbsp\;не&nbsp\;переходить к&nbsp\;следующему элементу формы",
	SideBarTabs: "<<tabs txtMainTab История История TabTimeline Все 'Все заметки' TabAll Метки 'Все метки' TabTags Ещё... 'Остальные списки' TabMore>>",
	TabTimeline: "<<timeline>>",
	TabAll: "<<list all>>",
	TabTags: "<<allTags>>",
	TabMore: "<<tabs txtMoreTab Нужные 'Ненаписанные заметки' TabMoreMissing Забытые 'Забытые заметки' TabMoreOrphans Системные 'Системные записи' TabMoreShadowed>>",
	TabMoreMissing: "<<list missing>>",
	TabMoreOrphans: "<<list orphans>>",
	TabMoreShadowed: "<<list shadowed>>",
	PluginManager: "<<plugins>>",
	ImportTiddlers: "<<importTiddlers>>"});

Данная запись даёт примеры разных видов вики-разметки. Можете использовать эту запись как встроенную справку, чтобы узнать, как набирать текст в TiddlyWiki.

Самое важное: выделяйте слово или группу слов двойными квадратными скобками вот так:
[[Список дел]]
чтобы появилась вики-ссылка, например [[Список дел]]. На первое время этого хватит.

Другие возможности:
* [[Гипертекстовые ссылки (подробнее)|Ссылки (примеры)]]
* [[Разные шрифты|Разные шрифты (примеры)]]
* [[Нумерованные и ненумерованные списки|Списки (примеры)]]
* [[Выделение цитат|Цитирование (примеры)]]
* [[Подзаголовки|Подзаголовки (примеры)]]
* [[Таблицы|Набор таблиц (примеры)]]
* [[Вставка изображений|Вставка изображений (примеры)]]

Не забывайте сохранять сделанные изменения!

Если в вашу вики дополнительно установлен [[ReminderMacros(ru)]], то вы можете помещать напоминания в ваши записи:
* [[Напоминания (примеры)]]
Изображения вставляются следующим образом:

Обычно удобно, если изображение находится в том же каталоге, что и файл с TiddlyWiki. Тогда во внутренних квадратных скобках достаточно указать имя файла.
|!заголовок левой колонки|!заголовок правой колонки|
|>| объединение ячеек по горизонтали |
| объединение ячеек по вертикали |левое выравнивание|
|~| правое выравнивание|
|bgcolor(#a0ffa0):цветовыделение| центрирование |

Эта таблица набрана так:
|!заголовок левой колонки|!заголовок правой колонки|
|>| объединение ячеек по горизонтали |
| объединение ячеек по вертикали |левое выравнивание|
|~| правое выравнивание|
|bgcolor(#a0ffa0):цветовыделение| центрирование |
Прошу не обвинять в поклонении перед Западом, я просто оставил прилагавшийся к плагину файл, это все же просто демо. Ну, перевел кое-что.
!!!!Обычные напоминания, день месяца каждый год.
*<<reminder month:1 day:1 title:"Новый Год, один из моих любимых дней" >>
*<<reminder month:2 day:2 title:"День Сурка ;)" >>

!!!!Напоминания со смещением (...день недели месяца)
*Третий понедельник февраля
**<<reminder month:2 day:15 offsetdayofweek:1 title:"Американский День Президента">>
*Второе воскресенье мая
**<<reminder month:5 day:8 offsetdayofweek:0 title:"Американский День Матери">>
*Последний понедельник мая (обратите внимание -- offsetdayofweek отрицательное число, что означает обратный отсчет)
**<<reminder month:5 day:31 offsetdayofweek:-1 title:"Memorial Day">>

!!!И просто так
*<<reminder month:4 day:1 title:"День Юмора" >>
*<<reminder month:10 day:31 title:"Хэллоуин" >>
*<<reminder month:12 day:25 title:"Католическое рождество" >>
Подзаголовки разных уровней набираются так:
! Заголовок верхнего уровня
!! Подзаголовок
!!! Подподзаголовок
!!!! Подзаголовок 4 уровня
!!!!! Подзаголовок 5 уровня
а выглядят так:
! Заголовок верхнего уровня
!! Подзаголовок
!!! Подподзаголовок
!!!! Подзаголовок 4 уровня
!!!!! Подзаголовок 5 уровня

| !Как выглядит | !Как набирать |h
| ''полужирный'' | {{{''полужирный''}}} (два апострофа) |
| --перечёркнутый-- | {{{--перечёркнутый--}}} |
| __подчёркнутый__ | {{{__подчёркнутый__}}} (два подчёркивания) |
| //курсив// | {{{//курсив//}}} |
| верхний индекс: 2^^3^^=8 | {{{2^^3^^=8}}} |
| нижний индекс: a~~ij~~ | {{{a~~ij~~}}} |
| @@выделенный@@ | {{{@@выделенный@@}}} |
| {{{моноширинный}}} | тройные фигурные скобки |
Ненумерованный список набирается так:
* яблоки
* печенье
* молоко
а отображается так:
* яблоки
* печенье
* молоко

Нумерованный список набирается так:
# посадить дерево
# построить дом
# вырастить сына
а отображается так (номера подставляются автоматически):
# посадить дерево
# построить дом
# вырастить сына

Можете попробовать отредактировать эту запись, чтобы увидеть, как был набран вот этот многоуровневый список:
* Программы
** Свободные
*** GNU/Linux
*** Firefox
*** GIMP
*** TiddlyWiki
** Несвободные
*** Windows
*** Internet Explorer
*** MS Word
*** MS Paint
*** Notepad
* Пиво
** Бесплатное
** Платное
* Свобода слова
** Говори что хошь
** Все ходы записаны
| Ссылка | Как набирать |h
| GettingStarted | {{{GettingStarted}}}, слово латиницей, буквами разных регистров, автматически обрабатывается как вики-ссылка |
| [[Вики-разметка (примеры)]] | {{{[[Вики-разметка (примеры)]]}}}, двойные квадратные скобки указывают, что является ссылкой |
| [[Справка|Вики-разметка (примеры)]] | {{{[[Справка|Вики-разметка (примеры)]]}}}, прямая черта {{{|}}} внутри отделяет описание и ссылку |
| [[Яндекс|]] | {{{[[Яндекс|]]}}}, этот же приём можно использовать и для внешних ссылок |
| | {{{}}}, ссылки на интернет-адреса (URL) создаются автоматически |
Можно наглядно выделить цитату, например:
И я понял: прежде всего нужно строить корабль, снаряжать караван, возводить храм — они долговечнее человека. Люди с радостью будут тратить себя на то, что драгоценнее их самих.
//Антуан де Сент-Экзюпери, «Цитадель»//
Это было сделано с помощью знака {{{<<<}}}:
И я понял: прежде всего нужно строить
корабль, снаряжать караван, возводить
храм — они долговечнее человека. Люди
с радостью будут тратить себя на то,
что драгоценнее их самих.
//Антуан де Сент-Экзюпери, «Цитадель»//

Также доступно цитирование в стиле электронной почты, с использованием знака {{{>}}} в начале строки:
>> Уже пользуешься TiddlyWiki?
> Да, просто невероятная вещь!
Это набирается так:
>> Уже пользуешься TiddlyWiki?
> Да, просто невероятная вещь!