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
<!--{{{-->
<div class='toolbar' macro='toolbar [[ToolbarCommands::EditToolbar]]'></div>
<div class='title' macro='view title'></div>
<div class='editor' macro='edit title'></div>
<div macro='annotations'></div>
<div class='editor' macro='edit text'></div>
<div class='editor' macro='edit tags'></div><div class='editorFooter'><span macro='message views.editor.tagPrompt'></span><span macro='tagChooser excludeLists'></span></div>
<!--}}}-->
When getting started, you may want to:
* Set your username for signing your edits: <<option txtUserName>>
* Change the page [[title|SiteTitle]] (now "<<tiddler SiteTitle>>") and [[subtitle|SiteSubtitle]] (now "<<tiddler SiteSubtitle>>"); they also set the browser tab title
* Create a tiddler where your content "starts"
** Use the button on the sidebar or [[link|My first tiddler]] it here, follow the link, edit, and click "done"
** It will be shown in the Timeline (usually on the right), but you may want to link it in the MainMenu (usually on the left)
** and/or make it open when the ~TiddlyWiki is opened by editing the list of [[DefaultTiddlers]] (separate links with spaces or linebreaks)
* Save your ~TiddlyWiki
** Although "download saving" works in any browser, it's not that convenient, so you'll probably want to use [[a dedicated saver|https://classic.tiddlywiki.com/#%5B%5BSetting up saving%5D%5D]]
<<importTiddlers>>
<!--{{{-->
<link rel='alternate' type='application/rss+xml' title='RSS' href='index.xml' />
<!--}}}-->
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]]
<!--{{{-->
<div class='header' role='banner'>
  <div class='headerShadow'>
    <span class='siteTitle' refresh='content' tiddler='SiteTitle'></span>&nbsp;
    <span class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'></span>
  </div>
  <div class='headerForeground'>
    <span class='siteTitle' refresh='content' tiddler='SiteTitle'></span>&nbsp;
    <span class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'></span>
  </div>
</div>
<div id='mainMenu' role='navigation' refresh='content' tiddler='MainMenu'></div>
<div id='sidebar'>
  <div id='sidebarOptions' role='navigation' refresh='content' tiddler='SideBarOptions'></div>
  <div id='sidebarTabs' role='complementary' refresh='content' force='true' tiddler='SideBarTabs'></div>
</div>
<div id='displayArea' role='main'>
<div id='messageArea'></div>
<div id='tiddlerDisplay'></div>
</div>
<!--}}}-->
/*{{{*/
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]]; }
h1 {border-bottom:2px solid [[ColorPalette::TertiaryLight]];}
h2,h3 {border-bottom:1px solid [[ColorPalette::TertiaryLight]];}

.txtOptionInput {background:[[ColorPalette::Background]]; color:[[ColorPalette::Foreground]];}

.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: -moz-linear-gradient(to bottom, [[ColorPalette::PrimaryLight]], [[ColorPalette::PrimaryMid]]);
	background: linear-gradient(to bottom, [[ColorPalette::PrimaryLight]], [[ColorPalette::PrimaryMid]]);
}
.header a:hover {background:transparent;}
.headerShadow {color:[[ColorPalette::Foreground]];}
.headerShadow a {font-weight:normal; color:[[ColorPalette::Foreground]];}
.headerForeground {color:[[ColorPalette::Background]];}
.headerForeground a {font-weight:normal; color:[[ColorPalette::PrimaryPale]];}

.tabSelected {
	color:[[ColorPalette::Foreground]];
	background:[[ColorPalette::Background]];
	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 {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]]; }
.wizard__title    { color:[[ColorPalette::PrimaryDark]]; border:none; }
.wizard__subtitle { color:[[ColorPalette::Foreground]]; border:none; }
.wizardStep { background:[[ColorPalette::Background]]; color:[[ColorPalette::Foreground]]; }
.wizardStep.wizardStepDone {background:[[ColorPalette::TertiaryLight]];}
.wizardFooter {background:[[ColorPalette::PrimaryPale]];}
.wizardFooter .status {background:[[ColorPalette::PrimaryDark]]; color:[[ColorPalette::Background]];}
.wizardFooter .status a { color: [[ColorPalette::PrimaryPale]]; }
.wizard .button {
	color:[[ColorPalette::Foreground]]; background:[[ColorPalette::SecondaryLight]]; border: 1px solid;
	border-color:[[ColorPalette::SecondaryDark]];
}
.wizard .button:hover {color:[[ColorPalette::Foreground]]; background:[[ColorPalette::Background]];}
.wizard .button:active {
	color:[[ColorPalette::Background]]; background:[[ColorPalette::Foreground]]; border: 1px solid;
	border-color:[[ColorPalette::PrimaryDark]] [[ColorPalette::PrimaryPale]] [[ColorPalette::PrimaryPale]] [[ColorPalette::PrimaryDark]];
}

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

#messageArea { background:[[ColorPalette::SecondaryLight]]; color:[[ColorPalette::Foreground]]; box-shadow: 1px 2px 5px [[ColorPalette::TertiaryMid]]; }
.messageToolbar__button { color:[[ColorPalette::PrimaryMid]]; background:[[ColorPalette::SecondaryPale]]; border:none; }
.messageToolbar__button_withIcon { background:inherit; }
.messageToolbar__button_withIcon:active { background:inherit; border:none; }
.tw-icon line { stroke: [[ColorPalette::TertiaryDark]]; }
.messageToolbar__button:hover .tw-icon line { stroke: [[ColorPalette::Foreground]]; }

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

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

.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: 2px solid [[ColorPalette::TertiaryPale]]; }
.selected .tagging, .selected .tagged { border: 2px solid [[ColorPalette::TertiaryLight]]; }
.tagging .listTitle, .tagged .listTitle {color:[[ColorPalette::PrimaryDark]];}
.tagging .button, .tagged .button { border:none; }

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

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

.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 th, .viewer thead td, .twtable th, .twtable thead td { background: [[ColorPalette::SecondaryMid]]; color: [[ColorPalette::Background]]; }
.viewer td, .viewer tr, .twtable td, .twtable tr { border: 1px solid [[ColorPalette::TertiaryLight]]; }
.twtable caption { color: [[ColorPalette::TertiaryMid]]; }

.viewer pre {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]]; background:[[ColorPalette::Background]]; color:[[ColorPalette::Foreground]];}
.editor textarea {border:1px solid [[ColorPalette::PrimaryMid]]; width:100%; background:[[ColorPalette::Background]]; color:[[ColorPalette::Foreground]];}
.editorFooter {color:[[ColorPalette::TertiaryMid]];}
.readOnly {background:[[ColorPalette::TertiaryPale]];}

#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);}
/*}}}*/
/*{{{*/
body { font-size:.75em; font-family:arial,helvetica,sans-serif; margin:0; padding:0; }

* html .tiddler {height:1%;}

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

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; border-width: 1px; }

#contentWrapper .chkOptionInput {border:0;}

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


a {text-decoration:none;}

.externalLink {text-decoration:underline;}

.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;}
.headerShadow {position:relative; padding:3em 0 1em 1em; left:-1px; top:-1px;}
.headerForeground {position:absolute; padding:3em 0 1em 1em; left:0; top:0;}

.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:0 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 0.3em 0;}
#sidebarTabs .tabContents {width:15em; overflow:hidden;}

.wizard { padding:0.1em 2em 0; }
.wizard__title    { font-size:2em; }
.wizard__subtitle { font-size:1.2em; }
.wizard__title, .wizard__subtitle { font-weight:bold; background:none; padding:0; margin:0.4em 0 0.2em; }
.wizardStep { padding:1em; }
.wizardFooter { padding: 0.8em 0; }
.wizardFooter .status { display: inline-block; line-height: 1.5; padding: 0.3em 1em; }
.wizardFooter .button { margin:0.5em 0 0; font-size:1.2em; padding:0.2em 0.5em; }

#messageArea { position:fixed; top:2em; right:0; margin:0.5em; padding:0.7em 1em; z-index:2000; }
.messageToolbar { text-align:right; padding:0.2em 0; }
.messageToolbar__button { text-decoration:underline; }
.messageToolbar__button_withIcon { display: inline-block; }
.tw-icon { height: 1em; width: 1em; } /* width for IE */
.tw-icon line { stroke-width: 1; stroke-linecap: round; }
.messageArea__text a { text-decoration:underline; }

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

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

.tabset {padding:1em 0 0 0.5em;}
.tab {display: inline-block; white-space: nowrap; position: relative; bottom: -0.7px; margin: 0 0.25em 0 0; padding:0.2em;}
.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 0 14em;}

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

.tiddler { padding: 1em; }

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

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

.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;}
.tagged li, .tagging li { margin: 0.3em 0; }
.tagClear {clear:both;}

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

.annotation { padding: 0.5em 0.8em; margin: 0.5em 1px; }

.viewer {line-height:1.4em; padding-top:0.5em;}
.viewer .button {margin:0 0.25em; padding:0 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 0; }
.viewer th, .viewer td, .viewer tr, .viewer caption, .twtable th, .twtable td, .twtable tr, .twtable caption { padding: 0.2em 0.4em; }
.twtable caption { font-size: 0.9em; }
table.listView { margin: 0.8em 1.0em; }
table.listView th, table.listView td, table.listView tr { text-align: left; }
.listView > thead { position: sticky; top: 0; }

* html .viewer pre {width:99%; padding:0 0 1em 0;}
.viewer pre {padding:0.5em; overflow:auto;}
pre, code { font-family: monospace, monospace; font-size: 1em; }
.viewer pre, .viewer code { line-height: 1.4em; }

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

.fieldsetFix {border:0; padding:0; margin:1px 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;}
#backstageToolbar {position:relative;}
#backstageArea a {font-weight:bold; margin-left:0.5em; padding:0.3em 0.5em;}
#backstageButton {display:none; position:absolute; z-index:175; top:0; right:0;}
#backstageButton a {padding: 0.3em 0.5em; display: inline-block;}
#backstage {position:relative; width:100%; z-index:50;}
#backstagePanel { display:none; z-index:100; position:absolute; width:90%; margin:0 5%; }
.backstagePanelFooter {padding-top:0.2em; float:right;}
.backstagePanelFooter a {padding:0.2em 0.4em;}
#backstageCloak {display:none; z-index:20; position:absolute; width:100%; height:100px;}

.whenBackstage {display:none;}
.backstageVisible .whenBackstage {display:block;}
/*}}}*/
/***
StyleSheet for use when a translation requires any css style changes.
This StyleSheet can be used directly by languages such as Chinese, Japanese and Korean which need larger font sizes.
***/
/*{{{*/
body {font-size:0.8em;}
#sidebarOptions {font-size:1.05em;}
#sidebarOptions a {font-style:normal;}
#sidebarOptions .sliderPanel {font-size:0.95em;}
.subtitle {font-size:0.8em;}
.viewer table.listView {font-size:0.95em;}
/*}}}*/
/*{{{*/
@media print {
  #mainMenu, #sidebar, #messageArea, .toolbar, #backstageButton, #backstageArea { display: none !important; }
  #displayArea { margin: 1em 1em 0em; }
}
/*}}}*/
<!--{{{-->
<div class='toolbar' role='navigation' macro='toolbar [[ToolbarCommands::ViewToolbar]]'></div>
<div class='title' macro='view title'></div>
<div class='subtitle'><span macro='view modifier link'></span>, <span macro='view modified date'></span> (<span macro='message views.wikified.createdPrompt'></span> <span macro='view created date'></span>)</div>
<div class='tagging' macro='tagging'></div>
<div class='tagged' macro='tags'></div>
<div class='viewer' macro='view text wikified'></div>
<div class='tagClear'></div>
<!--}}}-->
//{{{
config.shadowTiddlers['Test tiddler which is a shadow in the main document and not in the included one'] =
        'This is the the text of the shadow from the main document.';
//}}}
[[Introduction to SharedTiddlersPlugin]]
Are there any problems with it? This one is from the main document.
/***
|Description|checks and reports updates of installed extensions on startup, introduces a macro/backstage button to explore, install and update extensions|
|Version    |0.6.2|
|Author     |Yakov Litvin|
|Source     |https://github.com/YakovL/TiddlyWiki_ExtensionsExplorerPlugin/blob/master/ExtensionsExplorerPlugin.js|
|License    |[[MIT|https://github.com/YakovL/TiddlyWiki_YL_ExtensionsCollection/blob/master/Common%20License%20(MIT)]]|
!!!Installation & configuration
Installation of the plugin is as usual: import the tiddler or copy and tag it with {{{systemConfig}}}; reload TW.

{{FpG{not yet (will be useful once collections are introduced): In some cases, you may want to customize AvailableExtensions: {{PoGc{when/why? how?}}} }}}

!!!What EEP does, how to use it
Once you install this plugin, on startup, it will try to check if installed extensions have any updates available and report if it finds any. An update of a particular extension is looked up by the url in the Source slice (see this tiddler for example). EEP will recognize an "update" if it finds the content by that url, and that content has a Version slice and the version is higher than the installed one (like: 0.4.2 is higher than 0.3.9; 0.0.1 is also higher than none).

It also adds "explore extensions" in the backstage (and the {{{<<extensionsExplorer>>}}} macro with the same interface) that shows some extensions available for installation and the list of installed plugins with buttons to check for updates.

Note: With some TW savers/servers, loading an extension may fail if its author hasn't enabled CORS on the server pointed by Source.

!!!For extension authors: how to prepare extensions and repositories
To make EEP find updates for your extensions, you have to
# put it somewhere in the internet:
** the server should have CORS enabled (~GitHub is fine);
** the extension should be in either form: "plain text" (.js or .txt file extension) or a tiddler in a TW (.html extension);
# ensure that the extension has a Source slice with a url that points to itself (i.e. where to look for the latest version):
** for plain text, one can use a direct url, like: https://raw.githubusercontent.com/YakovL/TiddlyWiki_ShowUnsavedPlugin/master/ShowUnsavedPlugin.js;
** for ~GitHub, one can also use the url of the UI page (i.e. navigate to it via ~GitHub UI and copy the address): https://github.com/YakovL/TiddlyWiki_ShowUnsavedPlugin/blob/master/ShowUnsavedPlugin.js;
** for a tiddler inside a TW, use a permalink, like: https://TiddlyTools.com/Classic/#NestedSlidersPlugin (note that the Source slice in this plugin is in fact outdated: http://www.TiddlyTools.com/#NestedSlidersPlugin – you should avoid that as this will break the updating flow);
** for a tiddler inside a TW on ~GitHub, use ~GitHub Pages (this is in fact how ~TiddlyTools is served, they just use a custom domain; an example of an "ordinary" url: https://yakovl.github.io/TiddlyWiki_ExtraFilters/#ExtraFiltersPlugin);
** for your dev flow, it may be useful to put the plugin to ~GitHub as a .js file and load it into the demo TW via [[TiddlerInFilePlugin|https://github.com/YakovL/TiddlyWiki_TiddlerInFilePlugin]]. An example of such setup can be found [[here|https://github.com/YakovL/TiddlyWiki_FromPlaceToPlacePlugin]].

To make your extension explorable, you can do one of the following:
* simply announce [[in the community|https://groups.google.com/group/TiddlyWikiClassic]] or elsewhere
* [single extension, PR to .. collection]
* [multiple extensions, own collection, PR to ..]
{{PoGc{collections: not yet}}}
***/
//{{{
// Returns the slice value if it is present or defaultText otherwise
//
Tiddler.prototype.getSlice = Tiddler.prototype.getSlice || function(sliceName, defaultText) {
	let re = TiddlyWiki.prototype.slicesRE, m
	re.lastIndex = 0
	while(m = re.exec(this.text)) {
		if(m[2]) {
			if(m[2] == sliceName) return m[3]
		} else {
			if(m[5] == sliceName) return m[6]
		}
	}
	return defaultText
}

const centralSourcesListName = "AvailableExtensions"

config.macros.extensionsExplorer = {
	lingo: {
// TODO: review order, looks somewhat chaotic
// TODO: probably add listeners of custom events, displayMessage there
		installButtonLabel: "install",
		installButtonPrompt: "get and install this extension",
		getFailedToLoadMsg: name => "failed to load " + name,
		getSucceededToLoadMsg: name => `loaded ${name}, about to import and install...`,
		noSourceUrlAvailable: "no source url",
		getEvalSuccessMsg: name => `Successfully installed ${name} (reload is not necessary)`,
		getEvalFailMsg: (name, error) => `${name} failed with error: ${error}`,
		getImportSuccessMsg: (title, versionString, isUpdated) => isUpdated ?
			`Updated ${title}${versionString ? " to " + versionString : ""}` :
			`Imported ${title}${versionString ? " v" + versionString : ""}`,

		updateButtonCheckLabel: "check",
		updateButtonCheckPrompt: "check for updates",
		updateButtonUpdateLabel: "update",
		updateButtonUpdatePrompt: "install available update",
		getUpdateAvailableMsg: name => `update of ${name} is available!`,
		getUpdateAvailableAndVersionsMsg: (existingTiddler, newTiddler) => {
			const getVersionString = config.macros.extensionsExplorer.getVersionString
			return `update of ${existingTiddler.title} is available ` +
				"(current version: " + getVersionString(existingTiddler) +
				", available version: " + getVersionString(newTiddler) + ")"
		},
		updateNotAvailable: "update is not available",
		getUpdateConfirmMsg: (title, loadedVersion, presentVersion) => {
			const loadedVersionString = loadedVersion ? formatVersion(loadedVersion) : ""
			const presentVersionString = presentVersion ? formatVersion(presentVersion) : ""
			return `Would you like to update ${title}` +
				` (new version: ${loadedVersionString || "unknown"}, ` +
			 	`current version: ${presentVersionString || "unknown"})?`
		},

		centralSourcesListAnnotation: "The JSON here describes extensions so that ExtensionsExplorerPlugin can install them"
	},

	// helpers specific to tiddler format
	guessExtensionType: function(tiddler) {
		if(tiddler.tags.contains('systemConfig') ||
		   tiddler.getSlice('Type', '').toLowerCase() == 'plugin' ||
		   /Plugin$/.exec(tiddler.title)
		)
			return 'plugin'
	},
	// We use the server.host field a bit different than the core does (see importing):
	// we keep #TiddlerName part which won't hurt except for the plugin https://github.com/TiddlyWiki/tiddlywiki/blob/master/plugins/Sync.js (which we kinda substitute anyway),
	// we also don't set server.type and server.page.revision fields yet (unlike import); see also server.workspace, wikiformat fields.
	sourceUrlField: 'server.host',
	getSourceUrl: function(tiddler) {
		return tiddler.fields[this.sourceUrlField] || tiddler.getSlice('Source')
		//# try also the field set by import (figure the name by experiment)
	},
	setSourceUrl: function(tiddler, url) {
		//# simple implementation, not sure if setValue should be used instead
		tiddler.fields[this.sourceUrlField] = url
	},
	getDescription: tiddler => tiddler.getSlice('Description', ''),
	getVersionString: tiddler => tiddler.getSlice('Version', ''),
	getVersion: function(tiddler) {
		const versionString = this.getVersionString(tiddler)
		//# should use a helper from core instead
		const parts = /(\d+)\.(\d+)(?:\.(\d+))?/.exec(versionString)
		return parts ? {
			major: parseInt(parts[1]),
			minor: parseInt(parts[2]),
			revision: parseInt(parts[3] || '0')
		} : {}
	},

	// helpers to get stuff from external repos
	//# start from hardcoding 1 (.oO data sctructures needed
	//  for getAvailableExtensions and various user scenarios),
	//  then several (TW/JSON, local/remote)
	availableRepositories: [],
	getAvailableRepositories: function() {
		return this.availableRepositories
	},
	// fallback used when AvailableExtensions is empty
	defaultAvailableExtensions: [
		{
			url: 'https://github.com/YakovL/TiddlyWiki_ExtensionsExplorerPlugin/blob/master/ExtensionsCollection.txt',
			description: 'A central extensions collection for ExtensionsExplorerPlugin meant to both gather collections of existing extensions and help new authors make their work more explorable',
			type: 'collection'
		},
		{
			// js file @ github - worked /# simplify url to be inserted?
			name: 'ShowUnsavedPlugin',
			sourceType: 'txt',
			url: 'https://github.com/YakovL/TiddlyWiki_ShowUnsavedPlugin/blob/master/ShowUnsavedPlugin.js',
			description: 'highlights saving button (bold red by default) and the document title (adds a leading "*") when there are unsaved changes',
			type: 'plugin',
			text: ''
		},
		{
			url: 'https://github.com/YakovL/TiddlyWiki_DarkModePlugin/blob/master/DarkModePlugin.js',
			description: 'This plugin introduces "dark mode" (changes styles) and switching it by the {{{darkMode}}} macro and operating system settings'
		},
		{
			// in TW @ remote (CORS-enabled) – worked
			name: 'FieldsEditorPlugin',
			sourceType: 'tw',
			url: 'https://yakovl.github.io/VisualTW2/VisualTW2.html#FieldsEditorPlugin',
			description: 'adds controls (create/edit/rename/delete) to the "fields" toolbar dropdown',
			type: 'plugin'
		},
		{
			// txt file @ remote without CORS – worked with _
			url: 'http://yakovlitvin.pro/TW/pre-releases/Spreadsheets.html#HandsontablePlugin',
			description: 'a test plugin on a site without CORS'
		},
		{
			url: 'https://github.com/tobibeer/TiddlyWikiPlugins/blob/master/plugins/ListFiltrPlugin.js'
		}
	],
	guessNameByUrl: function(extension) {
		if(!extension.url) return undefined
		const urlParts = extension.url.split('#')

		// site.domain/path/tw.html#TiddlerName  or  site.domain/path/#TiddlerName
		if(urlParts.length > 1 && /(\.html|\/)$/.exec(urlParts[0])) return urlParts[1]

		// <url part>/TiddlerName.txt or <url part>/TiddlerName.js
		const textPathMatch = /\/(\w+)\.(js|txt)$/.exec(urlParts[0])
		return textPathMatch ? textPathMatch[1] : undefined
	},
	collectionTag: 'systemExtensionsCollection',
	parseCollection: function(text) {
		/* expected format:

		< additional info, like |Source|...| and other metadata >
		//{{{
		< extensions as JSON >
		//}}}

		*/
		const match = /(\/\/{{{)\s+((?:.|\n)+)\s+(\/\/}}})$/.exec(text)
		if(match) try {
			return JSON.parse(match[2])
		} catch (e) {
			console.log(`problems with parsing ${centralSourcesListName}:`, e)
			return null
		}
	},
	// checks .centralSourcesListName, .defaultAvailableExtensions, collections
	getAvailableExtensions: function() {
		const listText = store.getTiddlerText(centralSourcesListName)
		const availableExtensions = this.parseCollection(listText)
			|| this.defaultAvailableExtensions

		const otherCollections = store.filterTiddlers("[tag[" + this.collectionTag + "]]")
		for(const collectionTiddler of otherCollections) {
			const extensions = this.parseCollection(collectionTiddler.text)
			// for now, just merge
			if(extensions) for(const extension of extensions) {
				availableExtensions.push(extension)
			}
		}

		//# move name normalizing to the reading method
		//  once we move the list of available extensions from hardcode
		for(const extension of availableExtensions) {
			extension.name = extension.name || this.guessNameByUrl(extension)
		}
		return availableExtensions
	},
	// map by url of extension tiddlers
	// (those loaded from txt may be detected by !tiddler.creator)
	availableUpdatesCache: {},
	cacheAvailableUpdate: function(sourceUrl, tiddler) {
		this.availableUpdatesCache[sourceUrl] = { tiddler: tiddler }
	},
	// github urls like https://github.com/tobibeer/TiddlyWikiPlugins/blob/master/plugins/FiltrPlugin.js
	// are urls of user interface; to get raw code, we use the official githubusercontent.com service
	// also, we change the old urls https://raw.github.com/tobibeer/TiddlyWikiPlugins/master/plugins/FiltrPlugin.js
	getUrlOfRawIfGithub: function(url) {
		const ghUrlRE = /^https:\/\/github\.com\/(\w+?)\/(\w+?)\/blob\/(.+)$/
		const oldGhRawUrlRE = /^https:\/\/raw.github.com\/(\w+?)\/(\w+?)\/(.+)$/
//# test
		const match = ghUrlRE.exec(url) || oldGhRawUrlRE.exec(url)
		if(match) return 'https://raw.githubusercontent.com/' + match[1] + // username
			'/' + match[2] + // repository name
			'/' + match[3] // path
		return url
	},
	twsCache: {}, // map of strings
	/*
	@param sourceType: 'tw' | string | fasly (default = 'txt') -
	 of the tiddler source (a TW or a text file)
	@param url: string - either url of the text file or url#TiddlerName
	 for a TW (TiddlerName defines the title of the tiddler to load)
	@param title: string - is assigned to the loaded tiddler
	@param callback: tiddler | null => void
	 support second param of callback? (error/xhr)
	*/
	loadExternalTiddler: function(sourceType, url, title, callback, useCache) {
		sourceType = sourceType || this.guessSourceType(url)
		//# if sourceType is uknown, we can load file and guess afterwards
		if(sourceType == 'tw') {
			const tiddlerName = url.split('#')[1] || title
			const requestUrl = url.split('#')[0]
			const cache = this.twsCache
			const onTwLoad = function(success, params, responseText, url, xhr) {
				//# pass more info? outside: warn?
				if(!success) return callback(null)
				if(!useCache) cache[requestUrl] = responseText

				const externalTW = new TiddlyWiki()
				const result = externalTW.importTiddlyWiki(responseText)
				//# pass more info? outside: warn?
				if(!result) return callback(null)

				const tiddler = externalTW.fetchTiddler(tiddlerName)
				tiddler.title = title
				callback(tiddler)

				// above is a simple "from scratch" implementation
				//# should we reuse existing core code? (see import)
				//  currently, this only loads and passes tiddler,
				//  actual import is done in _
				const context = {
					adaptor: {},
					complete: function() {}
				}
//				FileAdaptor.loadTiddlyWikiSuccess(context, );
				//# import, see ...
				//# tiddler.title = title;
				//# callback(tiddler);
			}
			if(useCache && cache[requestUrl])
				onTwLoad(true, null, cache[requestUrl])
			else
				httpReq('GET', requestUrl, onTwLoad)
		} else {
			url = this.getUrlOfRawIfGithub(url)
			httpReq('GET', url, function(success, params, responseText, url, xhr) {
				//# pass more info? outside: warn?
				if(!success) return callback(null)

				const tiddler = new Tiddler(title)
				tiddler.text = responseText
				tiddler.generatedByTextOnly = true
				callback(tiddler)
			})
		}
	},

	getInstalledExtensions: function() {
		//# instead of returning tiddlers, create extension objects,
		//  those should have ~isInstalled, ~isEnabled, ~hasUpdates flags
		//  (and change refresh accordingly)
		return store.filterTiddlers(`[tag[systemConfig]] ` +
			`[tag[${this.collectionTag}]] [[${centralSourcesListName}]]`)
		//# implement others: themes, transclusions
	},
	// for each installed extension, check for update and reports (now: displays message)
	init: function() {
		//# set delegated handlers of install, update buttons
		const extensionTiddlers = this.getInstalledExtensions()
		if(!config.options.chkSkipExtensionsUpdatesCheckOnStartup)
			for(const eTiddler of extensionTiddlers) {
				const url = this.getSourceUrl(eTiddler)
				if(!url) continue
				this.checkForUpdate(url, eTiddler, result => {
		console.log(`checkForUpdate for ${url},`, eTiddler, 'result is:', result)
					if(result.tiddler && !result.noUpdateMessage) {
						displayMessage(this.lingo.getUpdateAvailableAndVersionsMsg(eTiddler, result.tiddler))
					}
					//# either report each one at once,
					//   (see onUpdateCheckResponse)
					//  create summary and report,
					//   (use availableUpdates)
					//  create summary and just show "+4" or alike (better something diminishing),
					//  or even update (some of) ext-s silently
					//# start with creating summary
				})
			}

		const taskName = "explorePlugins"
		config.backstageTasks.push(taskName)
		config.tasks[taskName] = {
			text: "explore extensions",
			tooltip: "see if there's any updates or install new ones",
			content: '<<extensionsExplorer>>',
		}
	},
	handler: function(place, macroName, params, wikifier, paramString) {
		const tableHeaderMarkup = "|name|description|version||h"
		// name is supposted to be a link to the repo; 3d row – for "install" button
		wikify(tableHeaderMarkup, place)
		const table = place.lastChild

		jQuery(table).attr({ refresh: 'macro', macroName: macroName })
			.addClass('extensionsExplorer').append('<tbody>')

		this.refresh(table)
	},
	// grabs list of available extensions and shows with buttons to install;
	// for each installed plugin, shows a button to check update or "no url" message,
	refresh: function(table) {
		const $tbody = jQuery(table).find('tbody')
			.empty()

		// safe method (no wikification, innerHTML etc)
		const appendRow = function(cells) {
			const row = document.createElement('tr')
			const nameCell = createTiddlyElement(row, 'td')
			if(cells.url)
				createExternalLink(nameCell, cells.url, cells.name)
			else
				createTiddlyLink(nameCell, cells.name, true)

			createTiddlyElement(row, 'td', null, null, cells.description)

			createTiddlyElement(row, 'td', null, null, cells.version)

			const actionsCell = createTiddlyElement(row, 'td')
			for(const e of cells.actionElements)
				actionsCell.appendChild(e)

			$tbody.append(row)
		}

		//# when implemented: load list of available extensions (now hardcoded)

		const installedExtensionsTiddlers = this.getInstalledExtensions()
			.sort((e1, e2) => {
				const up1 = this.availableUpdatesCache[this.getSourceUrl(e1)]
				const up2 = this.availableUpdatesCache[this.getSourceUrl(e2)]
				return	up1 && up2 ? 0 :
					up1 && !up2 ? -1 :
					up2 && !up1 ? +1 :
					!this.getSourceUrl(e1) ? +1 :
					!this.getSourceUrl(e2) ? -1 : 0
			})

		// show extensions available to install
		const availableExtensions = this.getAvailableExtensions()

		for(const extension of availableExtensions) {
			// skip installed
			if(installedExtensionsTiddlers.some(tid => tid.title === extension.name
				&& this.getSourceUrl(tid) === extension.url)) continue

			if(!extension.name && extension.sourceType == 'tw')
				extension.name = extension.url.split('#')[1]

			appendRow({
				name:		extension.name,
				url:		extension.url,
				description:	extension.description,
				version:	extension.version,
				actionElements: [
					createTiddlyButton(null,
						this.lingo.installButtonLabel,
						this.lingo.installButtonPrompt,
						() => this.grabAndInstall(extension) )
				]
			})
		}
		//# add link to open, update on the place of install – if installed

		// show installed ones.. # or only those having updates?
		$tbody.append(jQuery(`<tr><td colspan="4" style="text-align: center;">Installed</td></tr>`))
		for(const extensionTiddler of installedExtensionsTiddlers) {
			//# limit the width of the Description column/whole table
			const updateUrl = this.getSourceUrl(extensionTiddler)
				//# check also list of extensions to install
			const onUpdateCheckResponse = (result, isAlreadyReported) => {
				if(!result.tiddler) {
					displayMessage(this.lingo.updateNotAvailable)
					//# use result.error
					return
				}
				const versionOfLoaded = this.getVersion(result.tiddler)
				const versionOfPresent = this.getVersion(extensionTiddler)
				if(compareVersions(versionOfLoaded, versionOfPresent) >= 0) {
					displayMessage(this.lingo.updateNotAvailable)
					//# use result.error
					return
				}
debugger;
				if(!isAlreadyReported) displayMessage(this.lingo.getUpdateAvailableMsg(extensionTiddler.title), updateUrl)

				//# later: better than confirm? option for silent?
				if(confirm(this.lingo.getUpdateConfirmMsg(
					extensionTiddler.title,
					versionOfLoaded, versionOfPresent))
				) {
					this.updateExtension(result.tiddler, updateUrl)
//					displayMessage(this.lingo.getImportedUpdateMsg(
//						result.tiddler.title,
//						this.getVersionString(result.tiddler)
//					))
				}
			}

			const checkUpdateButton = createTiddlyButton(null,
				this.lingo.updateButtonCheckLabel,
				this.lingo.updateButtonCheckPrompt,
				() => this.checkForUpdate(updateUrl, extensionTiddler,
					onUpdateCheckResponse))

			const cachedUpdate = this.availableUpdatesCache[updateUrl]
			const installUpdateButton = createTiddlyButton(null,
				this.lingo.updateButtonUpdateLabel,
				this.lingo.updateButtonUpdatePrompt,
				() => onUpdateCheckResponse(cachedUpdate, true))

			appendRow({
				name: extensionTiddler.title,
				description: this.getDescription(extensionTiddler),
				version: this.getVersionString(extensionTiddler),
				actionElements: [
					!updateUrl ? document.createTextNode(this.lingo.noSourceUrlAvailable) :
					cachedUpdate ? installUpdateButton :
					checkUpdateButton
				]
			})
		}
	},
	grabAndInstall: function(extension) {
//# initial goal: add displayMessage on .install success
//# move ~user interaction~ (displayMessage) into callbacks? merge with checkForUpdate?
		if(!extension) return
		if(extension.text) {
//# is this ever called? do we cache extension.text on checking update? what about version?
			const extensionTiddler = new Tiddler(extension.name)
			extensionTiddler.text = extension.text
			extensionTiddler.generatedByTextOnly = true
			//# share 3 ↑ lines as ~internalize helper (with loadExternalTiddler)
			this.install(extensionTiddler, extension.type, extension.url)
			return
		}
		this.loadExternalTiddler(
			extension.sourceType,
			extension.url,
			extension.name,
			tiddler => {
				if(!tiddler) {
					displayMessage(this.lingo.getFailedToLoadMsg(extension.name))
					return
				}
				displayMessage(this.lingo.getSucceededToLoadMsg(tiddler.title))
				this.install(tiddler, extension.type ||
					this.guessExtensionType(tiddler), extension.url)
			}
		)
	},
	// evaluate if a plugin, import
	//# simple unsafe version, no dependency handling, registering as installed,
	//  _install-only-once check_, result reporting, refreshing/notifying, ..
	install: function(extensionTiddler, extensionType, sourceUrl) {
		if(!extensionTiddler) return
		//# displayMessage _

		const { text, title } = extensionTiddler
		switch(extensionType) {
			case 'plugin':
				// enable at once
				try {
					eval(text)
					displayMessage(this.lingo.getEvalSuccessMsg(title))
				} catch(e) {
					displayMessage(this.lingo.getEvalFailMsg(title, e))
					//# don't import? only on confirm?
					//# if(!confirm(title + " seem to produce errors, import anyway?")) return
				}
				// plugin-specific import preparation
				extensionTiddler.tags.pushUnique('systemConfig')
			break;

			case 'collection':
				extensionTiddler.tags.pushUnique(this.collectionTag)
			break;

			default:
			//# add _ tag for themes?
			//# displayMessage _
		}

		// actually import etc
		this.updateExtension(extensionTiddler, sourceUrl)
		//# what if exists already? (by the same name; other name)
	},
	updateExtension: function(extensionTiddler, sourceUrl) {
		// import
		var existingTiddler = store.fetchTiddler(extensionTiddler.title)
		if(extensionTiddler.generatedByTextOnly && existingTiddler) {
			existingTiddler.text = extensionTiddler.text
			existingTiddler.modified = new Date()
			//# update also modifier? changecount?
		} else {
			store.addTiddler(extensionTiddler)
		}
		if(sourceUrl && this.getSourceUrl(extensionTiddler) !== sourceUrl) {
			this.setSourceUrl(extensionTiddler, sourceUrl)
		}

		delete this.availableUpdatesCache[sourceUrl]
		store.setDirty(true)
		//# store url for updating if slice is not present?
		// make explorer and other stuff refresh
		store.notify(extensionTiddler.title, true)
		//# .oO reloading, hot reinstalling
		displayMessage(this.lingo.getImportSuccessMsg(extensionTiddler.title,
			this.getVersionString(extensionTiddler), !!existingTiddler))
	},
	guessSourceType: function(url) {
		if(/\.(txt|js)$/.exec(url.split('#')[0])) return 'txt'
		//# guess by url instead, fall back to 'txt'
		return 'tw'
	},
//# careful: extension keyword is overloaded (extension object/tiddler)
	/*
	  tries to load update for tiddler, if succeeds calls callback with
	   argument depending on whether it has newer version than the existing one
	  @param url: _
	  @param extensionTiddler: _
	  @param callback: is called [not always yet..] with argument
		{ tiddler: Tiddler | null, error?: string, noUpdateMessage?: string }
		if update is found and it has version newer than extensionTiddler,
		it is called with { tiddler: Tiddler }
	*/
	checkForUpdate: function(url, extensionTiddler, callback) {
		if(!url) return
		const title = extensionTiddler.title
		this.loadExternalTiddler(null, url, title, loadedTiddler => {
			if(!loadedTiddler) return callback({
				tiddler: null,
				error: "" //# specify
			})
			if(compareVersions(this.getVersion(loadedTiddler),
					   this.getVersion(extensionTiddler)
					  ) >= 0)
			//# also get and compare modified dates?
			{
				//# what about undefined?
				console.log('loaded is not newer')
				callback({
					tiddler: loadedTiddler,
					// TODO: move to lingo; may be change to noUpdate
					noUpdateMessage: "current version is up-to-date"
				})
			} else {
				this.cacheAvailableUpdate(url, loadedTiddler)
				callback({ tiddler: loadedTiddler })
			}
		})
	}
}

config.shadowTiddlers[centralSourcesListName] = '//{{{\n' +
	JSON.stringify(config.macros.extensionsExplorer.defaultAvailableExtensions, null, 2) +
	'\n//}}}'
config.annotations[centralSourcesListName] =
	config.macros.extensionsExplorer.lingo.centralSourcesListAnnotation
//}}}
<<include "demo-included/example included.html" filters:"[tag[external]]">>
<<include "demo-included/example included.html" filters:"[tag[tagged to be external]]" substituteShadows>>
<<include "demo-included/example included.html" filters:"[[A tiddler to be included with substituting]]" substitute>>
<<include "demo-included/example second level inclusion.html" filters:"[[A tiddler to be included with substituting]]" substitute>>
"""<<include "demo-included/example%20included.html" filters:"[tag[external]]">>"""
/***
|''Name''|InnerExternalLinkPlugin|
|''Version''|0.9.1|
|''Comment''|This plugin (by Yakov Litvin) is not fully released yet, but will definitely be released later|
***/
//{{{
config.extensions.InnerExternalLinkPlugin_orig_createExternalLink = createExternalLink;
createExternalLink = function(place,url,label) {

	var permaLinkRegExp = /([^#]+)#(?:(?:([^%\[]+))|(?:\[\[([^\]]+)\]\])|(?:%5B%5B([^\]]+)%5D%5D))/,
		// better to use decoding
	    match = permaLinkRegExp.exec(url),
	    siteUrlText = store.getTiddlerText("SiteUrl"),
	    pageLocation = window.location,
	    urlRegExp = /^(([^:\/\?#]+):)?(\/\/([^\/\?#]*))?([^\?#]*)(\?([^#]*))?(#(.*))?/,
	    matched = false;

	if(match) {
		var bareUrl = match[1],
		    tiddlerName = match[4]? match[4] : (match[3]? match[3] : match[2]);
		tiddlerName = decodeURIComponent(tiddlerName);
	} else
		return config.extensions.InnerExternalLinkPlugin_orig_createExternalLink(place,url,label);

	if(siteUrlText == bareUrl)
		matched = true;

	match = urlRegExp.exec(pageLocation.toString());
	if(match[1]+match[3]+match[5] == bareUrl)
		matched = true;

	// may be additional normalizing (stripping the protocol etc, encoding/decoding) should be added

	if(matched)
		return createTiddlyLink(place, tiddlerName, label);
	else
		return config.extensions.InnerExternalLinkPlugin_orig_createExternalLink(place,url,label);
};
//}}}
Sometimes having multiple ~TiddlyWikis causes some problems:
* some tiddlers with content may belong to more than one TW: for instance, if you created wikis about health and about cooking, or about coding and about ~TiddlyWiki, you may desire to have some tiddlers (like "Food for muscles" or "Interface development") in both of them
* if you constantly improve interface of your ~TWs and add new extensions, you probably wonder if you can store them in one place and share them somehow among your wikis (see also this [[discussion|https://groups.google.com/forum/#!topic/tiddlywikiclassic/ehoYOoayHTU]])
* also, it may be useful to aggregate some tiddlers (for instance, the ones tagged "~ToDo") in one place
and on the other hand it's not always convenient to have one big ~TiddlyWiki, because:
* it can grow too large to use it as a web-site and you will probably need to store in a separate wiki the only content which is meant to be published
* it can make workflow worse, because separate ~TWs can be opened in separate browser tabs and changed "asynchronously" (in contrast to two copies of one TW opened in separate tabs)
* different ~TWs can naturally appear on different devices/storages and are needed to be "merged" only from time to time
etc.

And that's where ~SharedTiddlersPlugin comes forward. It's idea is to load tiddlers from one ~TiddlyWiki in another when opening it. Create your "Food for muscles" or "Interface development" in one TW and include it into the the other -- you will see it in both (although, will be able to //edit// it only in one of them which can be no problem if things are put together in a right way). Or include ~PageTemplate from one "central" ~TiddlyWiki to each other and get your interface common for all ones. Or for aggregating "~ToDo"s, "problem"s, "question"s, whatever, include all your ~TWs in another one and use {{{<<tag>>}}} or {{{<<tagged>>}}} macro. Or use autoimport for central updating of extensions including those you develope yourself from their repositories (currently only local ones) -- or even launch included plugins without importing them.

Note: ~SharedTiddlersPlugin is a fork of the [[IncludePlugin|http://tiddlywiki.abego-software.de/#IncludePlugin]] and is backward compatible with v1.0.1, except now abego plugins should be made "include-aware" manually as any others, see the "API changes and coding with ~SharedTiddlersPlugin" section.

|tcenter|k
|[[The plugin|SharedTiddlersPlugin]]|[[Documentation|SharedTiddlersPluginInfo]]|[[Source code|SharedTiddlersPluginCode]]|[[License|Yakov Litvin Public Licence]]|
[[Intro|Introduction to SharedTiddlersPlugin]]
[[The plugin|SharedTiddlersPlugin]]
[[Docs|SharedTiddlersPluginInfo]]
[[License|Yakov Litvin Public Licence]]
[[Source|SharedTiddlersPluginCode]]
<!--{{{-->
<div style="text-align: center; margin: 2%"><!-- my wrapper -->
<!-- Yandex.Metrika informer -->
<a href="https://metrika.yandex.ru/stat/?id=22899424&amp;from=informer"
target="_blank" rel="nofollow"><img src="//bs.yandex.ru/informer/22899424/3_1_FFFFFFFF_EFEFEFFF_0_pageviews"
style="width:88px; height:31px; border:0;" alt="Яндекс.Метрика" title="Яндекс.Метрика: данные за сегодня (просмотры, визиты и уникальные посетители)" onclick="try{Ya.Metrika.informer({i:this,id:22899424,lang:'ru'});return false}catch(e){}"/></a>
<!-- /Yandex.Metrika informer -->

<!-- Yandex.Metrika counter -->
<script type="text/javascript">
(function (d, w, c) {
    (w[c] = w[c] || []).push(function() {
        try {
            w.yaCounter22899424 = new Ya.Metrika({id:22899424,
                    clickmap:true,
                    trackLinks:true,
                    accurateTrackBounce:true,
                    trackHash:true});
        } catch(e) { }
    });

    var n = d.getElementsByTagName("script")[0],
        s = d.createElement("script"),
        f = function () { n.parentNode.insertBefore(s, n); };
    s.type = "text/javascript";
    s.async = true;
    s.src = (d.location.protocol == "https:" ? "https:" : "http:") + "//mc.yandex.ru/metrika/watch.js";

    if (w.opera == "[object Opera]") {
        d.addEventListener("DOMContentLoaded", f, false);
    } else { f(); }
})(document, window, "yandex_metrika_callbacks");
</script>
<noscript><div><img src="//mc.yandex.ru/watch/22899424" style="position:absolute; left:-9999px;" alt="" /></div></noscript>
<!-- /Yandex.Metrika counter -->
</div><!-- end of my wrapper -->
<!--}}}-->
The ~TiddlyWiki ~PureStore is a file format compatible with some ~TiddlyWiki methods which allows, for instance, to use them with [[STP|SharedTiddlersPluginInfo]]. Here's an example of a minimalistic version of ~PureStore:
{{{
<html>
	<body>
		<div id="storeArea">
<div tiddler="SampleTiddler1" modifier="UdoBorkowski" modified="200702021726" created="200702021136" tags="And Some Tags">Content of SampleTiddler1</div>
<div tiddler="SampleTiddler2" modifier="UdoBorkowski" modified="200702021257" created="200702021256" tags="">Content of SampleTiddler2</div>
		</div>
	</body>
</html>
}}}
Here, tiddlers are stored like in an ordinary ~TiddlyWiki: a {{{div}}} element for each tiddler (only without those {{{pre}}} elements), inside the {{{div}}} element with the {{{id="storeArea"}}}, inside {{{body}}} inside {{{html}}}. Nothing but content should be present in the
{{{
		<div id="storeArea">
...
		</div>
}}}
part. Other things are optional: for instance, one can add {{{header}}} with stylings and other things, and other content can be put to the {{{body}}} element. Also, it {{DDn{may be}}} important to set a correct encoding. To illustrate these things, here's a copy of an example [[from abego-software.de|http://www.abego-software.de/references/TiddlyWikiPureStoreFormat.html]].
{{{
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
	<head>
		<meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
		<title>TiddlyWiki PureStore File</title>
		<style>body {font-family: arial,helvetica,sans-serif;background-color:#FFCC66;} #storeArea {display: none};</style>
	</head>
	<body>
		<h1>TiddlyWiki PureStore File</h1>
		<em>(This page contains hidden data. 
                        For details see <a href="http://www.abego-software.de/references/TiddlyWikiPureStoreFormat.html" target="_blank">
                        TiddlyWiki PureStore Format</a>.)</em>
		<div id="storeArea">
<div tiddler="SampleTiddler1" modifier="UdoBorkowski" modified="200702021726" created="200702021136" tags="And Some Tags">Content of SampleTiddler1</div>
<div tiddler="SampleTiddler2" modifier="UdoBorkowski" modified="200702021257" created="200702021256" tags="">Content of SampleTiddler2</div>
		</div>
	</body>
</html>
}}}
There's a number of tools out there that can generate ~PureStore: for instance, at ~TiddlyTools you can find [[ExportTiddlersPlugin, SaveAsPlugin and SaveToClipboard transclusion/bookmarklet|http://tiddlytools.com/#ExportTiddlersPlugin%20SaveAsPlugin%20SaveToClipboard]].

Here's a [[test|PureStoreTest]] of including from a ~PureStore file.
<<describeNode pureStoreTest "./demo-included/pureStoreTest.html">>
[[SampleTiddler1]]@pureStoreTest
/***
|Description |Allows to use tiddlers from other ~TiddlyWikis (with or without importing them)|
|Docs        |https://yakovl.github.io/TiddlyWiki_SharedTiddlersPlugin/#SharedTiddlersPluginInfo|
|Source      |https://yakovl.github.io/TiddlyWiki_SharedTiddlersPlugin/#SharedTiddlersPlugin|
|Author      |Yakov Litvin|
|~CoreVersion|2.7.0|
|Version     |2.5.1|
|Forked from |[[IncludePlugin|http://tiddlywiki.abego-software.de/#IncludePlugin]], by Udo Borkowski|
|Contact     |see [[docs|SharedTiddlersPluginInfo]]|
|Licence     |[[BSD-like open source license|https://yakovl.github.io/TiddlyWiki_SharedTiddlersPlugin/#%5B%5BYakov%20Litvin%20Public%20Licence%5D%5D]] |
|Copyright   |Yakov Litvin, 2013|
|>| In this tiddler, the code is minified and hidden; the full code can be found [[here|https://yakovl.github.io/TiddlyWiki_SharedTiddlersPlugin/#SharedTiddlersPluginCode]]. |
''Config:''
***/
//{{{
config.options.STP_hijackPrettyLink = true;
config.options.STP_hijackImageFormatter = true;
//}}}
// /%
config.filters.all=function(k,t){if("with included"==t[3]){var l,n=this.reverseLookup();for(l=0;l<n.length;l++)k.pushUnique(n[l])}else this.forEachTiddler(function(l,n){k.pushUnique(n)});return k};config.filters.includedFrom=function(k,t){var l=twWeb.getStoreUrlById(t[3]);if(!l)return[];for(var n=0;n<k.length;n++)k[n].getIncludeURL()!=l&&k.splice(n--,1);return k};config.filters.external=function(k,t){for(var l=0;l<k.length;l++)k[l].getIncludeURL()||k.splice(l--,1);return k};
config.filters.internal=function(k,t){for(var l=0;l<k.length;l++)k[l].getIncludeURL()&&k.splice(l--,1);return k};
(function(){function k(){var a={};this.isUsed=function(c){return a[c]?!0:!1};this.setUsed=function(c){a[c]=1};this.getUsed=function(){return jQuery.extend(!0,{},a)};this.markUnused=function(c){for(var b in c)a[b]=void 0}}function t(a){if(!a)return null;a="object"!=typeof a?{mode:a}:a;if(!a.mode&&!a.which&&void 0===a.ask)return null;void 0===a.which&&(a.which=a.mode in{1:!0,3:!0}?"all":a.mode in{2:!0,4:!0}?"newer":void 0!==a.ask?"all":void 0);void 0===a.ask?a.ask=a.mode in{1:!0,2:!0}?!1:a.mode in{3:!0,
4:!0}?!0:void 0!==a.which?!1:void 0:"false"==a.ask&&(a.ask=!1);return a}window.abego||(window.abego={});if(abego.TiddlyWikiIncluder)return alert("Warning: abego.TiddlyWikiIncluder already exists, so probably two copies of SharedTiddlersPlugin and/or IncludePlugin are installed and activated. It is highly recommended to deactivate all but one copy. You can find those by searching 'abego.TiddlyWikiIncluder'.");window.sharedTiddlersAPI={};var l=function(a,c){displayMessage(a,c);console.log(a)},n=function(a,
c,b){return setTimeout(a,c)},D=function(a){return 0!=a.search(/^(?:((http(s)?)|(file)):)|(.:\\)|(\\\\)|(\/)/)},z=function(a,c){if(D(a)&&c){var b=c.lastIndexOf("#");b=-1<b?c.substr(0,b):c;var e=b.lastIndexOf("/");b=(-1<e?b.substr(0,e+1):"")+a}else b=a;return b},E=function(a){0!=a.search(/^((http(s)?)|(file)):/)&&(a=D(a)?z(a,document.location.toString()):"file://"+a,a=a.replace(/\\/mg,"/"));return a},M=function(a,c,b){a=E(a);httpReq("GET",a,function(a,b,d,g,h){return a?c(d,g,b):c(void 0,g,b,"Error loading %0".format([g]))},
b)},O=function(a,c,b,e){var f=function(d,c){e&&e(d,"stp_loadTiddlyWikiStore",c,a,b)},d=function(d){f("Error when loading %0".format([a]),"Failed");c(void 0,a,b,d);return d};f("Start loading %0".format([a]),"Started");M(a,function(g,e,p,r){if(void 0===g)d(r);else{f("Processing %0".format([a]),"Processing");try{var h=new TiddlyWiki,F=h.importTiddlyWiki(g)?null:"Problem with importing TiddlyWiki, probable reason is: "+"The file '%0' does not appear to be a valid TiddlyWiki file".format([a]);F?d(F):(f("Loaded %0".format([a]),
"Done"),c(h,a,b))}catch(N){d(exceptionText(N))}}},b)},G=function(a){var c={tiddler:a,title:a.title,log:[]},b={},e=store.slicesRE,f="Name Description Version Requires CoreVersion Date Source Author License Browsers".split(" ");e.lastIndex=0;for(var d;d=e.exec(a.text);)d[2]?b[d[2]]=d[3]:b[d[5]]=d[6];for(a=0;a<f.length;a++)b[f[a]]&&(c[f[a]]=b[f[a]]);return c},A,m={},B=[],u,C=[],w,q=new function(){var a={};this.add=function(c,b,e,f){if(e||f)void 0==a[c]&&(a[c]={urlsSubs:[],urlsSubsSh:[]}),e&&a[c].urlsSubs.pushUnique(b),
f&&a[c].urlsSubsSh.pushUnique(b)};this.getSubsUrl=function(c){c=a[c];return null==c||0==c.urlsSubs.length?null:c.urlsSubs[0]};this.getSubsShUrl=function(c){c=a[c];if(null==c||0==c.urlsSubsSh.length)return null;var b,e;for(b=0;b<c.urlsSubs.length;b++)for(e=0;b<c.urlsSubsSh.length;e++)if(c.urlsSubs[b]==c.urlsSubsSh[e])return c.urlsSubs[b];return c.urlsSubsSh[0]};this.containSubsUrl=function(c,b){var e=a[c];return null==e?!1:e.urlsSubs.contains(b)};this.containSubsShUrl=function(c,b){var e=a[c];return null==
e?!1:e.urlsSubsSh.contains(b)};this.removeByUrl=function(c){var b,e;for(b in a){var f=a[b];for(e=0;e<f.urlsSubs.length;e++)f.urlsSubs[e]==c&&f.urlsSubs.splice(e--,1);for(e=0;e<f.urlsSubsSh.length;e++)f.urlsSubsSh[e]==c&&f.urlsSubsSh.splice(e--,1)}}};conflicts=new function(){var a={},c={};this.init=function(){void 0==config.options.chkWarnOnSharedTiddlersConflicts&&(config.options.chkWarnOnSharedTiddlersConflicts=!0);void 0==config.options.chkAlertOnSharedTiddlersConflicts&&(config.options.chkAlertOnSharedTiddlersConflicts=
!1)};this.checkNew=function(b,e,f,d){var g=function(a,d){var b=a[d.title];if(b){var c=b[d.url];c?!c.subs&&d.substitute&&(b[d.url]={subs:d.substitute,warned:!1}):b[d.url]={subs:d.substitute,warned:!1}}else b=a[d.title]={},b[d.url]={subs:d.substitute,warned:!1}},h=x(function(a,d){if(d!=e)return a.fetchTiddler(b)})||window.sharedTiddlersAPI.orig_fetchTiddler(b);h&&(h=h.getIncludeURL(),a[b]||g(a,{title:b,url:h||"main store",substitute:h?q.containSubsUrl(b,h):void 0}),g(a,{title:b,url:e,substitute:f}),
d&&(d=x(function(a,d){if(d!=e&&q.containSubsShUrl(b,d))return a.fetchTiddler(b)})||window.sharedTiddlersAPI.orig_fetchTiddler(b)))&&(d=d.getIncludeURL(),c[b]||g(c,{title:b,url:d||"main store",substitute:d?q.containSubsShUrl(b,d):void 0}),g(c,{title:b,url:e,substitute:f}))};this.markNodeUnloaded=function(b){for(var e in a)a[e][b]&&delete a[e][b];for(e in c)c[e][b]&&delete c[e][b]};this.notify=function(){var b=config.options.chkWarnOnSharedTiddlersConflicts,e=config.options.chkAlertOnSharedTiddlersConflicts;
if(e||b){var f=function(d,a,b){var c="",g=function(d){c+="\n"+d;a&&l(d)},e,h;for(e in d){var f=d[e];var p=!1;for(h in f)f[h].subs&&(p=!0);var k=0;for(h in f)f[h].subs==p&&k++;if(2>k)break;k=!1;for(h in f)f[h].subs!=p||f[h].warned||(k=!0);if(k){g("* "+e+" in:");for(h in f)f[h].subs!=p||f[h].warned||(g("** "+h),b&&(f[h].warned=!0));p&&g("  (with the subsitute priority)")}}return c},d="";f(a,!1,!1)&&(d+="New conflicts:",b&&l(d),d+=f(a,b,!0));f(c,!1,!1)&&(d&&(d+="\n"),d+="New conflicts among tiddlers competing for substituting shadows:",
b&&l("New conflicts among tiddlers competing for substituting shadows:"),d+=f(c,b,!0));e&&d&&alert(d)}}};conflicts.init();var P=function(){var a=B;B=[];if(a.length)for(var c=0;c<C.length;c++)C[c](a)},y,H=function(){void 0!==u&&clearInterval(u);y=0;var a=function(){twWeb.sendProgress("","","Done")};u=setInterval(function(){y++;10>=y||(clearInterval(u),u=void 0,twWeb.sendProgress("Refreshing...","",""),refreshDisplay(),setTimeout(a,0))},1)},x=function(a){var c,b;for(b in m){var e=twWeb.getStore(b);
if(e&&(c=a(e,b)))return c}},I=function(){if(!window.store)return setTimeout(I,100);var a=store.fetchTiddler;window.sharedTiddlersAPI.orig_fetchTiddler=a;store.fetchTiddler=function(b){var c;if(c=q.getSubsUrl(b))return m[c].fetchTiddler(b);if(c=a.apply(this,arguments))return c;if(void 0!==config.shadowTiddlers[b]){if(c=q.getSubsShUrl(b))return m[c].fetchTiddler(b)}else if(b!=config.macros.newTiddler.title)return x(function(a,d){return a.fetchTiddler(b)})};var c=store.forEachTiddler;window.sharedTiddlersAPI.orig_forEachTiddler=
c;store.forEachTiddler=function(a){var b={},f=function(d,c){b[d]||q.getSubsUrl(d)&&q.getSubsUrl(d)!=c.getIncludeURL()||(b[d]=1,a.apply(this,arguments))};c.call(store,f);for(var d in config.shadowTiddlers)q.getSubsShUrl(d)||(b[d]=1);b[config.macros.newTiddler.title]=1;x(function(d,a){d.forEachTiddler(f)})};twWeb.getIncludedStoresUrls().length&&H()},J=function(){if(!window.store)return setTimeout(J,100);var a=store.fetchTiddler("IncludeList"),c=a.text;c&&wikify(c,document.createElement("div"),void 0,
a)};config.extensions.SharedTiddlersPlugin={getFunctionUsingForReallyEachTiddler:function(a){return a},useForReallyEachTiddler:function(a,c){return a[c]},addListener:function(a){C.push(a)}};config.extensions.SharedTiddlersPlugin.addListener(H);config.shadowTiddlers.AdvancedOptions+="\n~IncludePlugin settings:\n<<option chkUseInclude>> Include ~TiddlyWikis\n<<option chkAlertOnSharedTiddlersConflicts>> Alert on tiddler name conflicts\n<<option chkWarnOnSharedTiddlersConflicts>> Display messages and write log in the browser console on conflicts\nIncludeList | IncludeState | ImportIncluded | [[help|https://yakovl.github.io/TiddlyWiki_SharedTiddlersPlugin/#SharedTiddlersPluginInfo]]\n^^(Reload this ~TiddlyWiki to make changes become effective)^^";
config.shadowTiddlers.IncludeState="<<includeState>>";config.shadowTiddlers.ImportIncluded='|               <<option txtStoreUrl>>|url of the document to import from |\n| <<option txtFilterTiddlersToImport>>|filter of tiddlers to import |\n|            <<option chkImportNewer>>|import only newer tiddlers (if those with same title already present) |\n|              <<option chkImportAsk>>|interactive import (ask whether to import each tiddler) |\n<html><a href=\'javascript:;\' onclick=\'\n\tvar storeUrl = config.options.txtStoreUrl,\n\t    params = {\n\t\tfilterLine: config.options.txtFilterTiddlersToImport,\n\t\timportOptions: {\n\t\t\twhich: config.options.chkImportNewer ? "newer" : "all",\n\t\t\task: config.options.chkImportAsk\n\t\t},\n\t\tnoRefresh: true,\n\t};\n\tif(!storeUrl)\n\t\treturn displayMessage("please specify the url to import from");\n\tif(!params.filterLine)\n\t\treturn displayMessage("please specify the filter of tiddlers to import");\n\tif(!sharedTiddlersAPI.getStore(storeUrl))\n\t\tdisplayMessage("warning: no store was loaded from "+storeUrl+" previously, trying now");\n\ttwWeb.include(storeUrl,params);\n\'>import (without saving)<a/></html>';
Tiddler.prototype.isIncluded=function(){return void 0!=this.includeURL};Tiddler.prototype.getIncludeURL=function(){return this.includeURL};Tiddler.prototype.setIncludeURL=function(a){this.includeURL=a};Tiddler.prototype.deleteIncludeURL=function(){delete this.includeURL};config.extensions.SharedTiddlersPlugin.orig_Tiddler_isReadOnly||(config.extensions.SharedTiddlersPlugin.orig_Tiddler_isReadOnly=Tiddler.prototype.isReadOnly,Tiddler.prototype.isReadOnly=function(){return config.extensions.SharedTiddlersPlugin.orig_Tiddler_isReadOnly.apply(this,
arguments)||this.isIncluded()});config.extensions.SharedTiddlersPlugin.orig_Tiddler_doNotSave||(config.extensions.SharedTiddlersPlugin.orig_Tiddler_doNotSave=Tiddler.prototype.doNotSave,Tiddler.prototype.doNotSave=function(){return config.extensions.SharedTiddlersPlugin.orig_Tiddler_doNotSave.apply(this,arguments)||this.isIncluded()});twWeb=new function(){var a={},c={},b={},e,f=this;this.includeUsages=new k;this.setSelfNodeName=function(d){e=d};this.getSelfNodeName=function(){return e};this.setNodeDesc=
function(d,b){this.getNodeDesc(d)?this.addConflict(d,b):a[d]=b;this.callWaitingTasks(d)};this.getNodeDesc=function(d){return a[d]};this.deleteNodeDesc=function(d){a[d]=null};this.addNodeDesc=function(d,a){this.setNodeDesc(d,{url:a})};this.compareNodeDesc=function(d,a){return d.url==a.url?d:null};this.getNodeUrl=function(d){return(d=this.getNodeDesc(d))?d.url:null};this.getStoreUrlById=function(d){var a=f.checkNodeNotation(d);return a?f.getNodeUrl(a):d};this.setNodeNotation=function(a){return"node: "+
a};this.checkNodeNotation=function(a){return(a=/node: (.*)/.exec(a))?a[1]:null};this.addConflict=function(a,b){var d=this.compareNodeDesc(b,this.getNodeDesc(a));d?(this.deleteNodeDesc(a),this.setNodeDesc(a,d)):(c[a]?c[a].push(b):c[a]=[b],alert("Warning: more than one description of the "+a+" node was pushed. The earlier version is kept."))};this.setWaitingTask=function(a,c,e){c={action:c,self:e};b[a]?b[a].push(c):b[a]=[c];this.getNodeUrl(a)&&this.callWaitingTasks(a)};this.callWaitingTasks=function(a){var d=
b[a];if(d)for(var c=0;c<d.length;c++)d[c].action.call(d[c].self);b[a]=null};this.setProgressFunction=function(a){w=a};this.sendProgress=function(a,b,c){w&&w.apply(this,arguments)};this.hasPendingIncludes=function(){var a;for(a in m){var b=this.getState(a);if("waiting"==b||"loading"==b)return!0}return!1};this.onError=function(a,b){l("Error when including '%0':\n%1".format([a,b]))};this.importIncluded=function(a,b){var d,c={tiddler:null};if(a instanceof Tiddler){c.tiddler=window.sharedTiddlersAPI.orig_fetchTiddler(a.title);
var e=jQuery.extend(!0,new Tiddler,a)}else return c.status=-1,c.errorText="not a Tiddler instance",c;var f=e.getIncludeURL();null===b&&(b={which:"all",ask:!1});if("newer"==b.which&&(d=window.sharedTiddlersAPI.orig_fetchTiddler(e.title))&&d.modified>=e.modified)return c;if("newerVersion"==b.which&&(d=window.sharedTiddlersAPI.orig_fetchTiddler(e.title))){var g=e.getSlice("Version"),k=d.getSlice("Version");if(g&&k){if(0>=compareVersions(g,k))return c}else if(!confirm("%0 from %1 of %2 is available, import to substitute current one (%3)?".format(e.title,
f,g?"unknown version":"version"+g,k?"unknown version":"version"+k)))return c}if(b.ask&&(d="newer"==b.which?"Up-to-date "+e.title+" from "+f+" is availabe, import?":"newerVersion"==b.which?"%0 from %1 of %2 is available, import to substitute current one (%3)?".format(e.title,f,"version "+g,"version "+k):e.title+" from "+f+" is availabe, import?",!confirm(d)))return c;if(b.mode&&!(b.mode in{1:!0,2:!0,3:!0,4:!0}))return c.status=-1,c.errorText="unknown import mode",c;f&&e.deleteIncludeURL();store.addTiddler(e);
store.setDirty(!0);c.status=0;c.tiddler=e;c.from=f;return c};this.importAndLog=function(a,c){var b=t(c);b=twWeb.importIncluded(a,b);var d=a.title;switch(b.status){case 0:console.log("imported: "+d+" from "+b.from);break;case -1:console.log("error importing "+d+": "+b.errorText)}return b};this.include=function(a,b){void 0===A&&(A=void 0===config.options.chkUseInclude||config.options.chkUseInclude);if(A){var c=this,d=function(a){var d=function(b,d,f,g){void 0===b?(m[a]=g,c.onError(a,g)):(m[a]=b,m[a].orig_store=
new TiddlyWiki,m[a].forEachTiddler(function(b,c){c.setIncludeURL(a);m[a].orig_store.addTiddler(c)}),m[a].clear(),e())},e=function(){var c=b.substitute,d=b.substituteShadows,f=b.importOptions;if(null===twWeb.getStore(a))return setTimeout(e,100);var g,h=m[a].orig_store.filterTiddlers(b.filterLine);for(g=0;g<h.length;g++){var k=jQuery.extend(!0,new Tiddler,h[g]);if(m[a].orig_store.fetchTiddler(k.title)){f?twWeb.importAndLog(k,f):(conflicts.checkNew(k.title,a,c,d),m[a].addTiddler(k));if(b.evalTiddlers){var r=
k,p=G(r).Name||r.title;b:{for(var l=0;l<installedPlugins.length;l++)if(installedPlugins[l].title==p||installedPlugins[l].Name==p){p=!0;break b}p=!1}if(!p){p=G(r);r.getIncludeURL()&&p.log.push("Included via SharedTiddlersPlugin from "+r.getIncludeURL());p.executed=!0;l=new Date;try{window.eval(r.text)}catch(K){p.log.push(config.messages.pluginError.format([exceptionText(K)])),p.error=!0,console.log("error evaluating "+r.title,K),story.displayTiddler(null,"PluginManager"),displayMessage(config.messages.customConfigError)}p.startupTime=
String(new Date-l)+"ms";installedPlugins.push(p)}}b.wikifyTiddlers&&wikify(k.text,document.createElement("div"),void 0,k)}}if(!f&&(c||d))for(g=0;g<h.length;g++)q.add(h[g].title,a,c,d);conflicts.notify();store.slices={};b.noRefresh||(refreshAll(),story.refreshAllTiddlers());B.push(a);setTimeout(P,void 0)},f=function(){m[a]="loading";O(a,d,null,w)};m[a]?e():(m[a]="waiting",b.delayMilliSeconds?setTimeout(f,b.delayMilliSeconds):f())},e=this.checkNodeNotation(a);e?e!=this.getSelfNodeName()&&this.setWaitingTask(e,
function(){var a=this.getNodeUrl(e);d(a)},this):d(a)}};this.getIncludedStoresUrls=function(){var a=[],b;for(b in m)a.push(b);return a};this.getStore=function(a){a=f.getStoreUrlById(a);return a?(a=m[a])&&a instanceof TiddlyWiki?a:null:null};this.getState=function(a){var b=f.getStoreUrlById(a);return b?(a=m[b])?"string"==typeof a?a:null:"No include specified for %0".format([b]):"the node "+f.checkNodeNotation(a)+" is not described yet, the address is unknown"};this.reload=function(a){var b,c=a.urlOrNodeParam;
if(c)for(b=0;b<c.length;b++){var d=this.checkNodeNotation(c[b]);c[b]=d?this.getNodeUrl(d):c[b];c[b]||c.splice(b--,1)}if(void 0===a["import"]||null===a["import"])a["import"]=!0;if(void 0===a.wikify||null===a.wikify)a.wikify=!0;var e,f=this.includeUsages.getUsed();for(e in f){b=e.substring(10,e.length-2);var k=b.readMacroParams();var l=b.parseParams("url",null,!0,!1,!0);var n=l[0].url[0];n=(d=this.checkNodeNotation(n))?this.getNodeUrl(d):n;d=!0;if(c)for(b=0;b<c.length;b++)n==c[b]&&(d=!1);else d=!1;
if(!a["import"]&&getParam(l,"import",void 0)||!a.eval&&k.contains("eval")||!a.wikify&&k.contains("wikify"))d=!0;d?delete f[e]:(m[n]=void 0,q.removeByUrl(n),conflicts.markNodeUnloaded(n))}this.includeUsages.markUnused(f);for(e in f)wikify(e,document.createElement("div"),void 0,null)}};config.extensions.SharedTiddlersPlugin.getDefaultProgressFunction=function(){setStylesheet(".includeProgressState{\nbackground-color:#FFCC00;\nposition:absolute;\nright:0.2em;\ntop:0.2em;\nwidth:7em;\npadding-left:0.2em;\npadding-right:0.2em\n}\n",
"stp_Include");var a=function(){var a=document.createElement("div");a.className="includeProgressState";a.style.display="none";document.body.appendChild(a);return a}(),c=function(){n(function(){a.style.display="none"},100,-100)};return function(b,e,f,d,g){"Done"==f||"Failed"==f?c():"stp_loadTiddlyWikiStore"==e?(y=0,"Processing"==f&&(removeChildren(a),createTiddlyText(a,"Including..."),a.style.display="block")):(removeChildren(a),createTiddlyText(a,b),a.style.display="block")}};twWeb.setProgressFunction(config.extensions.SharedTiddlersPlugin.getDefaultProgressFunction());
var v=function(a){for(var c=0;c<config.formatters.length;c++)if(config.formatters[c].name==a)return c;return null};if(config.options.STP_hijackPrettyLink){var L=v("prettyLink");config.extensions.SharedTiddlersPlugin.orig_prettyLinkFormatter=config.formatters[L];config.formatters[L]={name:"prettyLink",match:"\\[\\[",lookaheadRegExp:/\[\[(.*?)(?:\|(~)?(.*?))?\]\](?:(?:@(\w+))(?:@([\w\s:]+)@)?)?/mg,handler:function(a){this.lookaheadRegExp.lastIndex=a.matchStart;var c=this.lookaheadRegExp.exec(a.source);
if(c&&c.index==a.matchStart){config.extensions.SharedTiddlersPlugin.orig_prettyLinkFormatter.handler(a);var b=c[4]?c[4]:void 0,e=a.tiddler?a.tiddler.getIncludeURL():null;b=b?twWeb.setNodeNotation(b):e?e:void 0;e="{{"+JSON.stringify("[["+(c[3]?c[3]:c[1])+"]]")+"}}";e='"'+b+'" filters:'+e+" hide noRefresh ";c[5]&&(e+=c[5]);b&&config.macros.include.handler(a.output,"include",e.readMacroParams(!0),a,e,a.tiddler);a.nextMatch=this.lookaheadRegExp.lastIndex}}}}config.options.STP_hijackImageFormatter&&(v=
v("image"),config.extensions.SharedTiddlersPlugin.orig_imageFormatterHandler=config.formatters[v].handler,config.formatters[v].handler=function(a){var c=a.output.lastChild;config.extensions.SharedTiddlersPlugin.orig_imageFormatterHandler.apply(this,arguments);if(a.output.lastChild!=c){c=a.output.lastChild;c="img"==c.tagName.toLowerCase()?c:jQuery(c).find("img")[0];var b=a.tiddler?a.tiddler.getIncludeURL():"",e=jQuery(c).attr("src");c.src=z(e,b)}});config.extensions.SharedTiddlersPlugin.orig_editHandler=
config.macros.edit.handler;config.macros.edit.handler=function(a,c,b,e,f,d){var g=d.getIncludeURL();if("text"==b[0]&&g){var h=createTiddlyElement(null,"div");h.className="manageIncludedPanel";createTiddlyText(h,"manage the included tiddler: ");var k=g+"#[["+d.title+"]]";createExternalLink(h,k,"open in the source TiddlyWiki");createTiddlyText(h," (");createTiddlyButton(h,"view link","view the link to the source",function(a){var b=Popup.create(this);createTiddlyText(createTiddlyElement(b,"li","","disabled"),
k);Popup.show();a=a||window.event;a.cancelBubble=!0;a.stopPropagation&&a.stopPropagation();return!1}," ");createTiddlyText(h,")");readOnly||(createTiddlyText(h," | "),createTiddlyButton(h,"import","import this tiddler",function(){var a=twWeb.importAndLog(d,1);switch(a.status){case 0:displayMessage('imported "'+d.title+'" from '+a.from);break;case -1:displayMessage('error importing "'+d.title+'": '+a.errorText)}}," "));createTiddlyText(h," | ");config.macros.reloadIncluded.handler(h,"",null,null,"urls:'[\""+
g+"\"]'",d);a.appendChild(h)}return config.extensions.SharedTiddlersPlugin.orig_editHandler(a,c,b,e,f,d)};config.macros.describeNode={};config.macros.describeNode.handler=function(a,c,b,e,f,d){c=e.source.substring(e.matchStart,e.nextMatch);createTiddlyText(createTiddlyElement(a,"code"),c);d=d.getIncludeURL();a=b[0];b=b[1];if("self"==b){if((b=twWeb.getSelfNodeName())&&b!=a)return alert("The '"+b+"' alias is already assigned as the name of the current TiddlyWiki; the new attempt to assign '"+a+"' is ignored.");
twWeb.setSelfNodeName(a)}else b=z(b,d),b=E(b),twWeb.addNodeDesc(a,b)};config.macros.include={};config.macros.include.handler=function(a,c,b,e,f,d){e=e.source.substring(e.matchStart,e.nextMatch);c=f.parseParams("url",null,!0,!1,!0);getFlag(c,"hide",!1)||b.contains("hide")||createTiddlyText(createTiddlyElement(a,"code"),e);if(!twWeb.includeUsages.isUsed(e)){twWeb.includeUsages.setUsed(e);f=c[0].url;e=t({mode:getParam(c,"import",void 0),which:getParam(c,"importOnly",void 0),ask:getParam(c,"askBeforeImport",
void 0)});b={delayMilliSeconds:parseInt(getParam(c,"delay","0")),filterLine:getParam(c,"filter")||getParam(c,"filters","[all[-]]"),substitute:b.contains("substitute"),substituteShadows:b.contains("substituteShadows"),noRefresh:b.contains("noRefresh"),importOptions:e,evalTiddlers:b.contains("eval"),wikifyTiddlers:b.contains("wikify")};c=a.parentElement;for(e=0;f&&e<f.length;e++)d=f[e],"hide"!=d&&"substituteShadows"!=d&&"substitute"!=d&&"eval"!=d&&"wikify"!=d&&"noRefresh"!=d&&twWeb.include(d,b);c&&
c.appendChild(a)}};config.macros.reloadIncluded={};config.macros.reloadIncluded.handler=function(a,c,b,e,f,d){var g=f.parseParams("url",null,!0,!1,!0);c=getParam(g,"label","refresh");b=getParam(g,"tooltip",void 0);e=getParam(g,"class"," ");f=getParam(g,"urls",void 0);g=getParam(g,"reloadParams","{}");var h=JSON&&JSON.parse(g)||jQuery.parseJSON(g);h.urlOrNodeList=f?JSON&&JSON.parse(f)||jQuery.parseJSON(f):void 0;if(!b)if(h.urlOrNodeList){b="refresh '"+h.urlOrNodeList[0]+"'";for(f=1;f<h.urlOrNodeList.length;f++)b+=
", '"+h.urlOrNodeList[f]+"'";b+=0<f?" nodes":" node"}else b="refresh all included nodes";createTiddlyButton(a,c,b,function(){var a=function(){if(twWeb.hasPendingIncludes())setTimeout(a,100);else{var b=d.title;story.displayTiddler(this,b,story.chooseTemplateForTiddler(b,DEFAULT_VIEW_TEMPLATE))}};twWeb.reload(h);setTimeout(a,100)},e)};config.macros.includeState={};config.macros.includeState.handler=function(a,c,b,e,f,d){var g=function(){removeChildren(h);var a=wikify;var b="";var c=twWeb.getIncludedStoresUrls();
if(c.length){b+="|!Address|!State|\n";for(var d=0;d<c.length;d++){var e=c[d];b+="|{{{"+e+"}}}|";e=twWeb.getState(e);b+=e?"{{{"+e+"}}}":"included";b+="|\n"}b+="|includeState|k\n"}else b="{{noIncludes{\nNo TiddlyWiki is included or including is disabled (see AdvancedOptions)\n}}}\n";a(b,h);twWeb.hasPendingIncludes()&&setTimeout(g,500)},h=createTiddlyElement(a,"div");setTimeout(g,0)};I();setTimeout(J,100);window.sharedTiddlersAPI.getIncludes=twWeb.getIncludedStoresUrls;window.sharedTiddlersAPI.getState=
twWeb.getState;window.sharedTiddlersAPI.getStore=twWeb.getStore;window.sharedTiddlersAPI.importAndLog=twWeb.importAndLog;window.sharedTiddlersAPI.forReallyEachTiddler=function(a){store.forEachTiddler(a)};abego.TiddlyWikiIncluder={getIncludes:twWeb.getIncludedStoresUrls,getState:twWeb.getState,getStore:twWeb.getStore}})();
//%/ //
/***
|Description |Allows to use tiddlers from other ~TiddlyWikis (with or without importing them)|
|Docs        |https://yakovl.github.io/TiddlyWiki_SharedTiddlersPlugin/#SharedTiddlersPluginInfo|
|Source      |https://yakovl.github.io/TiddlyWiki_SharedTiddlersPlugin/#SharedTiddlersPluginCode|
|Author      |Yakov Litvin|
|~CoreVersion|2.7.0|
|Version     |2.5.1|
|Forked from |[[IncludePlugin|http://tiddlywiki.abego-software.de/#IncludePlugin]], by Udo Borkowski|
|Contact     |see [[docs|SharedTiddlersPluginInfo]]|
|Licence     |[[BSD-like open source license|https://yakovl.github.io/TiddlyWiki_SharedTiddlersPlugin/#%5B%5BYakov%20Litvin%20Public%20Licence%5D%5D]] |
|Copyright   |Yakov Litvin, 2013|
***/
// // ''Config:''
//{{{
config.options.STP_hijackPrettyLink = true;
config.options.STP_hijackImageFormatter = true;
//}}}
// // ''Code:''
//{{{
config.filters.all = function(results,match) {
	if(match[3] == "with included") { // brings included tiddlers as well
		var m,matched = this.reverseLookup();
		for(m = 0; m < matched.length; m++)
			results.pushUnique(matched[m]);
	} else
		this.forEachTiddler(function(tName,tiddler){
			results.pushUnique(tiddler);
		});
	return results;
};
config.filters.includedFrom = function(results,match) {

	var url = twWeb.getStoreUrlById(match[3]);
	if(!url)
		return [];

	for(var i = 0; i < results.length; i++)
		if(results[i].getIncludeURL() != url)
			results.splice(i--,1);
	return results;
};
config.filters.external = function(results,match) {

	for(var i = 0; i < results.length; i++)
		if(!results[i].getIncludeURL())
			results.splice(i--,1);
	return results;
};
config.filters.internal = function(results,match) {

	for(var i = 0; i < results.length; i++)
		if(results[i].getIncludeURL())
			results.splice(i--,1);
	return results;
};
(function(){ // install only once wrapper

// Ensure the global abego namespace is set up.
if (!window.abego) window.abego = {};

// Install only once (don't install if abego.IncludePlugin is installed as well)
if (abego.TiddlyWikiIncluder)
	return alert("Warning: abego.TiddlyWikiIncluder already exists, so probably two copies of SharedTiddlersPlugin and/or IncludePlugin are installed and activated. It is highly recommended to deactivate all but one copy. You can find those by searching 'abego.TiddlyWikiIncluder'.");

// abego.TiddlyWikiIncluder is defined near the end of the code

// Define the API namespace:
window.sharedTiddlersAPI = {};

//==============================================================================
// Helpers

// This is used instead of displayMessage, because the latter sometimes doesn't show the messages
var displayAndLogMessage = function(text,linkText) {
	displayMessage(text,linkText);
	console.log(text);
};

var invokeLater = function(func, delay, priority) {
	return setTimeout(func,delay);
};

//------------------------------------------------------------------------------
// url helpers

var isRelativeURL = function(url) {
// as Unix filesystem root is "/", urls starting with it are not considered as relative

	return (url.search(/^(?:((http(s)?)|(file)):)|(.\:\\)|(\\\\)|(\/)/) != 0);
};

var getPathFromURL = function(url) {

	// cut off hash first to handle a FF issue
	var hashPos  = url.lastIndexOf("#"),
	    bareUrl  = (hashPos > -1) ? url.substr(0, hashPos) : url,
	// then all but path
	    slashPos = bareUrl.lastIndexOf("/");
	return (slashPos > -1) ? bareUrl.substr(0, slashPos + 1) : "";
};

var resolveUrlFrom = function(urlToResolve, sourceUrl) {

	return (isRelativeURL(urlToResolve) && sourceUrl) ?
		getPathFromURL(sourceUrl) + urlToResolve : urlToResolve;
};

// limitedly turns URI (URL) reference into an absolute URI (URL) and windows paths into URL
var stp_resolveURL = function(url) {

	if (url.search(/^((http(s)?)|(file)):/) != 0) {
	// no protocol prefix..

		if (isRelativeURL(url))

			url = resolveUrlFrom(url, document.location.toString());
		else
		// "url" is an "absolute" path to a local file. Prefix it with file://

			url = "file://" + url;

		// replace every \ by a /, to cover Windows style pathes
		url = url.replace(/\\/mg,"/");
	}
	return url;
};

//------------------------------------------------------------------------------
// file/tw loading functions

// Asynchronously load the given (local or remote) file.
// 
// @param	url
// value:	either an URL or a local file path to a file
//
//	Examples:
//	* http://www.abego-software.de/index.html
//	* file:///C:/abegoWebSite-Copy/index.html
//	* C:\abegoWebSite-Copy\index.html    (for Windows machines)
//
//	Notice: backslashes in JavaScript string constants must be escaped, 
//	i.e. the last example must be written as: "C:\\abegoWebSite-Copy\\index.html"
//	when "hardcoded" in JavaScript source code.
// 
// @param	callback
// value:	function(content,url,params,errorMessage) 
//		called at the end of the operation. 
//		On success content holds the content of the loaded file. 
//		On error content is undefined and errorMessage holds an error message. 
//		params is the params passed into stp_LoadFile.
//
// @param	params
//		passed through to the callback function
// 
var stp_LoadFile = function(url,callback,params) {

	var onLoad = function(status,params,responseText,url,xhr) {
		return status 
				? callback(responseText, url, params)
				: callback(undefined, url, params, "Error loading %0".format([url]));
	};

	// Make sure the URL is a real URL, with protocol prefix etc.
	url = stp_resolveURL(url);
	
	httpReq("GET",url,onLoad,params);
};

// Asynchronously load the given (local or remote) TiddlyWiki store.
// 
// @param	url
// value:	either an URL or a local file path to a TiddlyWiki file (absolute or relative)
//
//	Examples:
//	* http://www.abego-software.de/index.html
//	* file:///C:/abegoWebSite-Copy/index.html
//	* include/beta.html
//	* C:\abegoWebSite-Copy\index.html    (for Windows machines)
//
//	Notice: backslashes in JavaScript string constants must be escaped, 
//	i.e. the last example must be written as: "C:\\abegoWebSite-Copy\\index.html"
//	when "hardcoded" in JavaScript source code.
// 
// @param	callbackWithStore
// value:	function(theStore,url,params,errorMessage) 
//			called at the end of the operation. 
//			On success theStore holds the loaded store (a TiddlyWiki object). 
//			On error theStore is undefined and errorMessage holds an error message. 
//			params is the params passed into stp_loadTiddlyWikiStore
//
// @param	params
//		passed through to the callbackWithStore
//
// @param	progress	[optional]
// value:	function(message, sender, state, url, params)
//		called in various situations during the operation,
//		typically used to show "the progress" of the operation.
//		sender: the constant "stp_loadTiddlyWikiStore"
//		state: one of these: "Started", "Processing", "Done", "Failed"
//		"Processing" means the data has been received and in now processed.
// 
var stp_loadTiddlyWikiStore = function(url,callbackWithStore,params,progress) {
	
	var sendProgress = function(message, state) {
		if (progress)
			progress(message,"stp_loadTiddlyWikiStore",state,url,params);
	};
	
	var sendError = function(message) {
		sendProgress("Error when loading %0".format([url]),"Failed");
		callbackWithStore(undefined, url, params, message);
		return message;
	};

	var sendStore = function(store) {
		sendProgress("Loaded %0".format([url]),"Done");
		callbackWithStore(store, url, params);
		return null;
	};
	
	
	var callback = function(content,theURL,params,errorMessage) {
		if (content === undefined) {
			sendError(errorMessage);
			return;
		};
		
		sendProgress("Processing %0".format([url]),"Processing");
		var invalidFileErrorMsg = "The file '%0' does not appear to be a valid TiddlyWiki file";
		try {
			// Load the content from the "content" string into a TiddlyWiki() object
			var importStore = new TiddlyWiki();
			var errorText = importStore.importTiddlyWiki(content) ? null :
				"Problem with importing TiddlyWiki, probable reason is: "+
				invalidFileErrorMsg.format([url]);
			if(errorText)
				sendError(errorText);
			else
				sendStore(importStore);
		} catch (ex) {
			sendError(exceptionText(ex));
		};
	};
	
	sendProgress("Start loading %0".format([url]),"Started");
	stp_LoadFile(url,callback,params);
};

//------------------------------------------------------------------------------
// plugin installation helpers

var getArbitraryPluginInfo = function(tiddler) {
// getPluginInfo can't be used (for included tids) due to the ugly slice handling of the core
	var pluginInfo = {
		tiddler: tiddler,
		title: tiddler.title,
		log: []
	};

	var slices = {}, slicesRE = store.slicesRE;
	var requiredInfo = ["Name", "Description", "Version", "Requires", "CoreVersion", "Date", "Source", "Author", "License", "Browsers"];
	slicesRE.lastIndex = 0;
	var match;
	while(match = slicesRE.exec(tiddler.text)) {
		if(match[2])
			slices[match[2]] = match[3];
		else
			slices[match[5]] = match[6];
	}

	for(var i = 0; i < requiredInfo.length; i++)
		if(slices[requiredInfo[i]])
			pluginInfo[requiredInfo[i]] = slices[requiredInfo[i]];

	return pluginInfo;
}

var checkPluginInstalled = function(pluginName) {
	for(var i = 0; i < installedPlugins.length; i++)
		if(installedPlugins[i].title == pluginName || installedPlugins[i].Name == pluginName)
			return true;
	return false;
}

var installPlugin = function(tiddler,force) {

	var pluginName = getArbitraryPluginInfo(tiddler).Name || tiddler.title;
	// check if such a plugin was installed previously, return if so
	if(!force) // two layers to improve the speed in the "force == true" case
		if(checkPluginInstalled(pluginName))
			return;

	// get the plugin info
	var pluginInfo = getArbitraryPluginInfo(tiddler);
	if(tiddler.getIncludeURL())
		pluginInfo.log.push("Included via SharedTiddlersPlugin from "+tiddler.getIncludeURL());

	// install the plugin
	pluginInfo.executed = true;
	var startTime = new Date();

	try {
		window.eval(tiddler.text);
	} catch(ex) {
		pluginInfo.log.push(config.messages.pluginError.format([exceptionText(ex)]));
		pluginInfo.error = true;
		console.log("error evaluating " + tiddler.title, ex);
		story.displayTiddler(null,"PluginManager");
		displayMessage(config.messages.customConfigError);
	}
	pluginInfo.startupTime = String((new Date()) - startTime) + "ms";

	// register the plugin
	installedPlugins.push(pluginInfo);
}


//==============================================================================
// Shared Tiddlers Plugin

// Constants

var WAITING = "waiting";
var LOADING = "loading";

var ANI_DURATION_HIDE_STATE = 1000;

var REFRESH_PRIORITY = -200;
var ANIMATION_PRIORITY = -100;
var UPDATE_STATE_PRIORITY = -300;

// --------------------------------------------------
// Variables

var useInclude;         // this variable can be used to control include enabling by other things than cookies
var includedStores = {};  // url(String) -> TiddlyWiki or String; if not (yet) loaded a status or an error string
var pendingOnLoadURLs = []; // [] of String: a list of urls that should be passed with the next "notifyListeners"
var refreshTiddlyWikiTimerID; // for delayed refresh
var listeners = [];
var progress;

// rules pointing which stores tiddlers with conflicting names should be fetched from
function FetchPreferences() {
	var prefs = {};
	
	this.add = function(tiddlerName,sourceUrl,substitute,substituteShadow) {
		if(!substitute && !substituteShadow)
			return;
		if(prefs[tiddlerName] == undefined)
			prefs[tiddlerName] = {urlsSubs: [], urlsSubsSh: []};
		if(substitute)
			prefs[tiddlerName].urlsSubs.pushUnique(sourceUrl);
		if(substituteShadow)
			prefs[tiddlerName].urlsSubsSh.pushUnique(sourceUrl);
	};
/*	this.getPrefs = function(tiddlerName) {
		return jQuery.extend(true, {}, prefs[tiddlerName]);
	};
*/	this.getSubsUrl = function(tiddlerName) {
		var pref = prefs[tiddlerName];
		if(pref == null)
			return null;
		if(pref.urlsSubs.length == 0)
			return null;
		return pref.urlsSubs[0];
	};
	this.getSubsShUrl = function(tiddlerName) {
		var pref = prefs[tiddlerName];
		if(pref == null)
			return null;
		if(pref.urlsSubsSh.length == 0)
			return null;

		// check if there's a tiddler with both preferences
		var i, j;
		for(i = 0; i < pref.urlsSubs.length; i++)
			for(j = 0; i < pref.urlsSubsSh.length; j++)
				if(pref.urlsSubs[i] == pref.urlsSubsSh[j])
					return pref.urlsSubs[i];

		return pref.urlsSubsSh[0];
	};
	this.containSubsUrl = function(tName,url) {
		var pref = prefs[tName];
		if(pref == null)
			return false;
		return pref.urlsSubs.contains(url);
	};
	this.containSubsShUrl = function(tName,url) {
		var pref = prefs[tName];
		if(pref == null)
			return false;
		return pref.urlsSubsSh.contains(url);
	};
	// removes all priorities of tiddlers, included from the url
	this.removeByUrl = function(url) {

		var tName, pref, i;

		for(tName in prefs) {
			pref = prefs[tName]
			for(i = 0; i < pref.urlsSubs.length; i++)
				if(pref.urlsSubs[i] == url)
					pref.urlsSubs.splice(i--, 1);
			for(i = 0; i < pref.urlsSubsSh.length; i++)
				if(pref.urlsSubsSh[i] == url)
					pref.urlsSubsSh.splice(i--, 1);
		}
	};
};
var fetchPreferences = new FetchPreferences();

function Conflicts() {

	// hashmaps by tiddler name of potentially conflicting tiddlers with that name;
	// each element is a hashmap by url of tiddlers with such names
	var pConfs = {},  // doesn't contain info about tiddlers in the main store
	    pSConfs = {}; // for tiddlers that may conflict when substituting a shadow

	this.init = function() {
		// notify of name conflicts in the whole set of initial and included tiddlers?
		if(config.options.chkWarnOnSharedTiddlersConflicts == undefined) config.options.chkWarnOnSharedTiddlersConflicts = true;
		// use alert() for notifications?
		if(config.options.chkAlertOnSharedTiddlersConflicts == undefined) config.options.chkAlertOnSharedTiddlersConflicts = false;
	};
	// check whether a new tiddler (not included yet) may cause a conflict (now or in the future)
	this.checkNew = function(tName, url, subs, subsSh) {

		// use to add when a tiddler with such name is already present
		var addData = function(confsMap, tidParams) {

			var includeData = function(tidParams) {		// better to create a separate class
				return { subs: tidParams.substitute, warned: false };
			};
			var getSubsPriority = function(data) {
				return data.subs;
			}

			var conf = confsMap[tidParams.title];
			if(!conf) {
				conf = confsMap[tidParams.title] = {};
				conf[tidParams.url] = includeData(tidParams);
			} else {
				var confPart = conf[tidParams.url];
				if(!confPart)
					conf[tidParams.url] = includeData(tidParams);
				else {
					if(!getSubsPriority(confPart) && tidParams.substitute)
						conf[tidParams.url] = includeData(tidParams);
						// better to set subs to true and warned to false
				}
			}
		}

		// check if there's a tiddler with such a name..
		// ..in included stores
		var existingTid = forEachLoadedStore(function(theStore, storeUrl) {

			if(storeUrl != url) return theStore.fetchTiddler(tName);
		}) ||
		// ..or in the main one
		      window.sharedTiddlersAPI.orig_fetchTiddler(tName);

		// if the tiddler is added to the main store after exactly one tiddler is
		// included, no conflict is detected by this algorithm;
		// also, it doesn't account deleting the tiddler from the main store

		if(!existingTid)
			return;
		var mainStoreId = "main store",
		    existingTidUrl = existingTid.getIncludeURL();

		// check conflicts among all included tiddlers (important when no shadow with such name exists)
		if(!pConfs[tName])
			addData(pConfs, {
				title: tName,
				url: existingTidUrl || mainStoreId,
				substitute: existingTidUrl ? fetchPreferences.containSubsUrl(tName,existingTidUrl) : undefined
			});
		addData(pConfs, { title: tName, url: url, substitute: subs });

		// check conflicts among tiddlers that substitute a shadow
		if(subsSh) {
			var existingTidSubsSh = forEachLoadedStore(function(theStore, storeUrl) {
				if(storeUrl != url && fetchPreferences.containSubsShUrl(tName,storeUrl))
					return theStore.fetchTiddler(tName);
			}) || window.sharedTiddlersAPI.orig_fetchTiddler(tName);
			// same problems
			
			if(!existingTidSubsSh)
				return;
			var existingTidSubsShUrl = existingTidSubsSh.getIncludeURL();

			// conflicts among substituting tiddlers are important when a shadow with such name exists
			if(!pSConfs[tName])
				addData(pSConfs, {
					title: tName,
					url: existingTidSubsShUrl || mainStoreId,
					substitute: existingTidSubsShUrl ? fetchPreferences.containSubsShUrl(tName,existingTidSubsShUrl) : undefined
				});
			addData(pSConfs, { title: tName, url: url, substitute: subs });
		}
	};
	this.markNodeUnloaded = function(url) {
		
		for(var t in pConfs)
			if(pConfs[t][url])
				delete pConfs[t][url];
		for(t in pSConfs)
			if(pSConfs[t][url])
				delete pSConfs[t][url];
	};
	this.notify = function() {
		var msgAndLog = config.options.chkWarnOnSharedTiddlersConflicts;
		var doAlert   = config.options.chkAlertOnSharedTiddlersConflicts;
		if(!doAlert && !msgAndLog)
			return; // no conflict is marked as "warned" - this is by intent
		var tName, tUrl;

		var checkOrDisplayConflicts = function(map,msgAndLog,markWarned) {
			var msg = ""; // message to return (for alerting etc)
			var addM = function(m) { // pushes all notification messages
				msg += ("\n" + m);
				if(msgAndLog)
					displayAndLogMessage(m);
			};
			var tName, tSources, tUrl, subs, nOfConflicting, newPresent,
				subsMsg = "  (with the subsitute priority)";
				// mark conflicts among tiddlers with the substitute priority

			// find out where necessary, notify
			for(tName in map) {
				tSources = map[tName];

				// find out which priority is of interest
				subs = false;
				for(tUrl in tSources)
					if(tSources[tUrl].subs)
						subs = true;

				// if there's only one tiddler with "substitute", there's no conflict
				nOfConflicting = 0;
				for(tUrl in tSources)
					if(tSources[tUrl].subs == subs)
						nOfConflicting++;
				if(nOfConflicting < 2)
					break;

				// find out if new conflicting tiddlers are present
				newPresent = false;
				for(tUrl in tSources)
					if(tSources[tUrl].subs == subs && !tSources[tUrl].warned)
						newPresent = true;

				// start notification
				if(newPresent) {
					addM("* "+tName+" in:");
					for(tUrl in tSources)
						if(tSources[tUrl].subs == subs && !tSources[tUrl].warned) {
							addM("** "+tUrl);
							if(markWarned)
								tSources[tUrl].warned = true;
						}
					if(subs)
						addM(subsMsg);
				}
			}
			return msg;
		};

		var msg = "";
		if(checkOrDisplayConflicts(pConfs,false,false)) { // new conflicts present
			msg += "New conflicts:";
			if(msgAndLog) displayAndLogMessage(msg);
			msg += checkOrDisplayConflicts(pConfs,msgAndLog,true);
		};
		if(checkOrDisplayConflicts(pSConfs,false,false)) { // new conflicts among tiddlers substituting shadows present
			if(msg) msg += "\n";
			var m = "New conflicts among tiddlers competing for substituting shadows:";
			msg += m;
			if(msgAndLog) displayAndLogMessage(m);
			msg += checkOrDisplayConflicts(pSConfs,msgAndLog,true);
		};
		if(doAlert && msg)
			alert(msg);
	};
//	this.state = // return current state as a string (for includeState)
};
conflicts = new Conflicts();
conflicts.init();

// --------------------------------------------------
// Helper functions

var isIncludeEnabled = function() {
	if (useInclude === undefined)
		useInclude = config.options.chkUseInclude === undefined || config.options.chkUseInclude;
	return useInclude;
};

var getMissingIncludeMsg = function(url) {
	return "No include specified for %0".format([url])
};

// Called after one or more included TiddlyWikis are loaded
//
var notifyListeners = function() {
	var urls = pendingOnLoadURLs;
	pendingOnLoadURLs = [];
	if (urls.length)
		for (var i = 0; i < listeners.length; i++)
			listeners[i](urls);
};

var idleCount; // Reset to 0 when the system is "not idle", incremented inside refreshTiddlyWiki

var refreshTiddlyWiki = function() {
	// To avoid to much refreshing/flickering don't refresh immediately 
	// but wait until the system was idle for a certain time.

	if (refreshTiddlyWikiTimerID !== undefined) clearInterval(refreshTiddlyWikiTimerID);

	idleCount = 0;

	var sendDone = function() {
		twWeb.sendProgress("","","Done");
	};

	refreshTiddlyWikiTimerID = setInterval(function() {
		idleCount++;
		if (idleCount <= 10)
			return;

		clearInterval(refreshTiddlyWikiTimerID);
		refreshTiddlyWikiTimerID = undefined;

		twWeb.sendProgress("Refreshing...","","");
		refreshDisplay();
		invokeLater(sendDone,0,REFRESH_PRIORITY);
	},1);
};

// Calls callback for every loaded store and returns the first non-false/null.. value returned by callback.
//
// @param	callback
// value:	function(store, url)
//
var forEachLoadedStore = function(callback) {
	var result;
	for(var url in includedStores) {
		var theStore = twWeb.getStore(url);
		if (theStore && (result = callback(theStore, url)))
			return result;
	}
};

// hijack fetchTiddler and store.forEachTiddler to make them work with tiddlers from included stores as well
var attachToStore = function() {

	if (!window.store) return invokeLater(attachToStore,100);

	var orig_fetchTiddler = store.fetchTiddler;
	// add API to be able to fetch substituted tiddlers in the main store:
	window.sharedTiddlersAPI.orig_fetchTiddler = orig_fetchTiddler;

	store.fetchTiddler = function(title) {

		var t, subsUrl = fetchPreferences.getSubsUrl(title), subsShUrl;

		// first, look for the tiddler in the main store, unless there's nothing to substitute with
		if(!subsUrl) {
			t = orig_fetchTiddler.apply(this,arguments);
			if(t) return t;
		} else
			return includedStores[subsUrl].fetchTiddler(title);
		
		// then, look for shadowed tiddlers in main store and external ones to substitute those
		if(config.shadowTiddlers[title] !== undefined) {
			if(subsShUrl = fetchPreferences.getSubsShUrl(title))
				return includedStores[subsShUrl].fetchTiddler(title);
			else
				return undefined;
		};

		// Including "New Tiddler" tiddler would prevent creating new tiddlers
		// via standart "new tiddler" button, so don't look for such
		if (title == config.macros.newTiddler.title) return undefined;

		// finally, look for an external one without "substitute" preference
		return forEachLoadedStore(function(theStore, url) {
			return theStore.fetchTiddler(title);
		});
	};

	var orig_forEachTiddler = store.forEachTiddler;
	window.sharedTiddlersAPI.orig_forEachTiddler = orig_forEachTiddler;
	store.forEachTiddler = function(callback) {

		var done = {};

		var callbackWrapper = function(title, tiddler) {
			// ensure every title is only processed once
			if(done[title]) 
				return;
			
			// do and set done for appropriate tiddlers
			if(!fetchPreferences.getSubsUrl(title)||
			   (fetchPreferences.getSubsUrl(title) == tiddler.getIncludeURL())) {
				done[title] = 1;
				callback.apply(this,arguments);
			};
		};
		
		// first, forEachTiddler over the original tiddlers
		orig_forEachTiddler.call(store, callbackWrapper);

		// add nonsubstituted shadowTiddler titles to done 
		// (to avoid an included store hide a shadow tiddler)
		for (var n in config.shadowTiddlers)
			if(!fetchPreferences.getSubsShUrl(n))
				done[n] = 1;

		// add the "New Tiddler" tiddler to done
		// to avoid an included store (with such tiddler) prevent creating new tiddlers
		done[config.macros.newTiddler.title] = 1;

		// forEachTiddler over every included store
		forEachLoadedStore(function(theStore, url) {
			theStore.forEachTiddler(callbackWrapper);
		});
	};

	// refresh TiddlyWiki to reflect the new included Tiddlers (if we have any).
	if(twWeb.getIncludedStoresUrls().length)
		refreshTiddlyWiki();
};

var includeFromIncludeList = function() {
	if (!window.store)
		return invokeLater(includeFromIncludeList,100);

	var includeList = store.fetchTiddler("IncludeList"),
	    includeListText = includeList.text;
	if (includeListText)
		wikify(includeListText,document.createElement("div"),undefined, includeList);
};


//================================================================================
// config.extensions.SharedTiddlersPlugin (the "includer" engine)

config.extensions.SharedTiddlersPlugin = {

	// function config.extensions.SharedTiddlersPlugin.getFunctionUsingForReallyEachTiddler(func)
	//
	// Deprecated: returned a function that behaved as func, but every call
	// to store.forEachTiddler was actually a call to forReallyEachTiddler
	// (see below). Now forEachTiddler is changed globally and this method
	// returns the function without changes
	//
	// @return the patched function
	//
	getFunctionUsingForReallyEachTiddler: function(func) { return func; },
	
	// function config.extensions.SharedTiddlersPlugin.useForReallyEachTiddler(object,methodName)
	//
	// Deprecated: used for patching the object's method so that a call
	// to store.forEachTiddler was actually a call to forReallyEachTiddler
	// (iterating over the tiddlers of the main store and included ones)
	// Now store.forEachTiddler is changed globally and patching is not needed
	// and the method is returned unchanged
	//
	// @param  object
	// @param  methodName the name of the object' method to be patched
	// @return the method
	//
	useForReallyEachTiddler: function(object,methodName) {
		return object[methodName];
	},
	
	// Add a listener function to the TiddlyWikiIncluder.
	//
	// @param  listener  function(urls)
	//	urls: [] of Strings, containing the urls of the TiddlyWiki just included
	//	(see url@config.extensions.SharedTiddlersPlugin.include)
	//	called whenever one or more TiddlyWiki store are successfully included.
	//
	addListener: function(listener) {
		listeners.push(listener);
	}
};


// -------------------------------------------------------------------------------
// TiddlyWikiIncluder initialization code

config.extensions.SharedTiddlersPlugin.addListener(refreshTiddlyWiki);

config.shadowTiddlers.AdvancedOptions +=
	("\n~IncludePlugin settings:"+
	 "\n<<option chkUseInclude>> Include ~TiddlyWikis"+
	 "\n<<option chkAlertOnSharedTiddlersConflicts>> Alert on tiddler name conflicts"+
	 "\n<<option chkWarnOnSharedTiddlersConflicts>> Display messages and write log in the browser console on conflicts"+
	 "\nIncludeList | IncludeState | ImportIncluded | [[help|https://yakovl.github.io/TiddlyWiki_SharedTiddlersPlugin/#SharedTiddlersPluginInfo]]"+
	 "\n^^(Reload this ~TiddlyWiki to make changes become effective)^^");
config.shadowTiddlers.IncludeState = "<<includeState>>";

// add the "importer" engine
config.shadowTiddlers.ImportIncluded =
"|               <<option txtStoreUrl>>|url of the document to import from |\n"+
"| <<option txtFilterTiddlersToImport>>|filter of tiddlers to import |\n"+
"|            <<option chkImportNewer>>|import only newer tiddlers (if those with same title already present) |\n"+
"|              <<option chkImportAsk>>|interactive import (ask whether to import each tiddler) |\n"+
"<html><a href='javascript:;' onclick='\n"+
"	var storeUrl = config.options.txtStoreUrl,\n"+
"	    params = {\n"+
"		filterLine: config.options.txtFilterTiddlersToImport,\n"+
"		importOptions: {\n"+
"			which: config.options.chkImportNewer ? \"newer\" : \"all\",\n"+
"			ask: config.options.chkImportAsk\n"+
"		},\n"+
"		noRefresh: true,\n"+
"	};\n"+
"	if(!storeUrl)\n"+
"		return displayMessage(\"please specify the url to import from\");\n"+
"	if(!params.filterLine)\n"+
"		return displayMessage(\"please specify the filter of tiddlers to import\");\n"+
"	if(!sharedTiddlersAPI.getStore(storeUrl))\n"+
"		displayMessage(\"warning: no store was loaded from \"+storeUrl+\" previously, trying now\");\n"+

"	twWeb.include(storeUrl,params);\n"+
"'>import (without saving)<a/></html>";

//================================================================================
// Tiddler extension/modification

Tiddler.prototype.isIncluded = function() {
	return this.includeURL != undefined;
};

Tiddler.prototype.getIncludeURL = function() {
	return this.includeURL;
};

Tiddler.prototype.setIncludeURL = function(url) {
	this.includeURL = url;
};

Tiddler.prototype.deleteIncludeURL = function() {
	delete this.includeURL;
};

// make included tiddlers readonly and non-savable
if(!config.extensions.SharedTiddlersPlugin.orig_Tiddler_isReadOnly) {
  config.extensions.SharedTiddlersPlugin.orig_Tiddler_isReadOnly = Tiddler.prototype.isReadOnly;

  Tiddler.prototype.isReadOnly = function() {
	return config.extensions.SharedTiddlersPlugin.orig_Tiddler_isReadOnly.apply(this,arguments) || this.isIncluded();
  };
}
if(!config.extensions.SharedTiddlersPlugin.orig_Tiddler_doNotSave) {
  config.extensions.SharedTiddlersPlugin.orig_Tiddler_doNotSave = Tiddler.prototype.doNotSave;

  Tiddler.prototype.doNotSave = function() {
	return config.extensions.SharedTiddlersPlugin.orig_Tiddler_doNotSave.apply(this,arguments) || this.isIncluded();
  };
}

//================================================================================
// Web of TiddlyWikis

function IncludingMemorizer() { // the structure to store info about already handled include macros
	var used = {};
	this.isUsed  = function(line) { return used[line]? true : false; };
	this.setUsed = function(line) { used[line] = 1; };
	this.getUsed = function() { return jQuery.extend(true, {}, used) };
	this.markUnused = function(usedMap) {

		for(var u in usedMap)
			// don't delete to keep the order of inclusion (for reloading)
			used[u] = undefined;
	};
};

function TwWeb() {

	var nodes = {};			// hashmap by node name of nodes' metadata
	var nodeConflicts = {};		// hashmap by node name of arrays of conflicts
	var nodeWaitingTasks = {};	// hashmap by node name of arrays of Waiting Tasks
	var nodeDescription = function(url) { // PoG: can be turned into a separated "class"
		return { url : url };
	};
	var selfNodeName;
	var self = this;

	this.includeUsages = new IncludingMemorizer();

// ----- Nodes desctiptions part ---------------------------------------------------------

	// set/get the name of "main" (including) node
	this.setSelfNodeName = function(name) {
		selfNodeName = name;
	};
	this.getSelfNodeName = function() {
		return selfNodeName;
	};

	// set/get/delete node description
	this.setNodeDesc = function(nodeName, desc) {

		var existing = this.getNodeDesc(nodeName);

		// currently, doesn't change metadata on conflict
		if(existing)
			this.addConflict(nodeName, desc);
		else
			nodes[nodeName] = desc;

		this.callWaitingTasks(nodeName);
	};
	this.getNodeDesc = function(nodeName) {
		return nodes[nodeName];
	};
	this.deleteNodeDesc = function(nodeName) {
		nodes[nodeName] = null;
	};

	// "API" method to be used in the macro
	this.addNodeDesc = function(nodeName, url) {
		this.setNodeDesc(nodeName, nodeDescription(url));
	};

	// returns "better" description if one is "strictly better" than the other or "even" and null otherwise
	this.compareNodeDesc = function(desc1, desc2) {

// looks like here's a mistake: probably ": desc2" (?)
		return (desc1.url == desc2.url)? desc1 : null;
	};

	this.getNodeUrl = function(nodeName) {

		var desc = this.getNodeDesc(nodeName);
		return desc? desc.url : null;
	};

	// @param	nodeId
	//		url or "node: nodeName" id of the node
	// @return	url of the node (if it is defined) or null
	//
	this.getStoreUrlById = function(nodeId) {

		var node = self.checkNodeNotation(nodeId),
		    url  = node ? self.getNodeUrl(node) : nodeId;
		return url;
	}

	this.setNodeNotation = function(nodeName) {

		return "node: " + nodeName;
	};
	this.checkNodeNotation = function(urlParam) {

		var nodeCalcRE = /node: (.*)/,
		    nodeCalcMatch = nodeCalcRE.exec(urlParam);

		return nodeCalcMatch ? nodeCalcMatch[1] : null;
	};

	this.addConflict = function(nodeName, nodeDesciption) {

		var betterDesc = this.compareNodeDesc(nodeDesciption,this.getNodeDesc(nodeName));
		if(betterDesc) {
			this.deleteNodeDesc(nodeName);
			this.setNodeDesc(nodeName, betterDesc);
			return;
		}

		if(nodeConflicts[nodeName])
			nodeConflicts[nodeName].push(nodeDesciption);
		else
			nodeConflicts[nodeName] = [ nodeDesciption ];

		alert(  "Warning: more than one description of the "+nodeName+" node was pushed. "+
			"The earlier version is kept."  );
	};

// ----- Waiting tasks part --------------------------------------------------------------

	this.setWaitingTask = function(nodeName, waitingTaskFunc, waitingTaskSelf) {

		var waitingTask = { action: waitingTaskFunc, self: waitingTaskSelf };

		if(nodeWaitingTasks[nodeName])
			nodeWaitingTasks[nodeName].push(waitingTask);
		else
			nodeWaitingTasks[nodeName] = [ waitingTask ];

		if(this.getNodeUrl(nodeName))
			this.callWaitingTasks(nodeName);
	};
	this.callWaitingTasks = function(nodeName) {

		var toDo = nodeWaitingTasks[nodeName];

		if(toDo)
			for(var i = 0; i < toDo.length; i++)
				toDo[i].action.call(toDo[i].self);

		nodeWaitingTasks[nodeName] = null; // remove called Waiting Tasks
	};

// ----- Including stuff part ------------------------------------------------------------

	// ---- helpers ----

	this.setProgressFunction = function(func) {
		progress = func;
	};
/*	this.getProgressFunction = function() {	// is not in use
		return progress;
	};
*/	this.sendProgress = function(message, sender, state) {
		if (progress)
			progress.apply(this,arguments);
	};

	// Returns true when there are "pending" includes, i.e. TiddlyWiki that are not yet loaded.
	// A TiddlyWiki that failed loading is not pending.
	//
	this.hasPendingIncludes = function() {
		var state;
		for(var url in includedStores) {
			state = this.getState(url);
			if (state == WAITING || state == LOADING)
				return true;
		};
		return false;
	};

	// Called when an included TiddlyWiki could not be loaded.
	// By default an error message is displayed.
	//
	this.onError = function(url, errorMessage) {
		displayAndLogMessage("Error when including '%0':\n%1".format([url, errorMessage]));
	};

	// import a tiddler from an included store
	//
	// @param  tiddler - a tiddler to import
	// @param  options: ...
//# update doc: options.mode: undefined or 1 - import anyway (other modes, like "don't substitute" will be supported)
	// @return the result object:
	//  .status means: -1 = error, 0 = tiddler is imported, >0 - reserved for other situations
	//  .errorText is not empty on error
	//  .tiddler is the tiddler with /the title/ which is in the store after "it is over" (may be null)
	//  .from is the url line equal to the includeURL of the imported tiddler
	//
	this.importIncluded = function(tiddler, options) {

		var t, tInMain, result = { tiddler: null };

		if(tiddler instanceof Tiddler) {
			// see return value, this is for the case when the import is not done
			result.tiddler = window.sharedTiddlersAPI.orig_fetchTiddler(tiddler.title);
			t = jQuery.extend(true, new Tiddler(), tiddler);
		} else {
			result.status = -1;
			result.errorText = "not a Tiddler instance";
			return result;
		};
		var url = t.getIncludeURL();

		if(options === null) options = { which: 'all', ask: false };
		if(options.which == 'newer') {
			tInMain = window.sharedTiddlersAPI.orig_fetchTiddler(t.title);
			if(tInMain && tInMain.modified >= t.modified) return result;
		}
		var importAnotherVersionConfirmation = "%0 from %1 of %2 is available, "+
			"import to substitute current one (%3)?";
		if(options.which == 'newerVersion') {
			var parseVersion = function(versionString) {
				var parts = /(\d+)\.(\d+)\.(\d+)/.exec(versionString);
				return parts ? {
					major: parts[1],
					minor: parts[2],
					revision: parts[3]
				} : null;
			};
			tInMain = window.sharedTiddlersAPI.orig_fetchTiddler(t.title);
			if(tInMain) {
				var version = t.getSlice('Version'),
				    versionInMain = tInMain.getSlice('Version');
				if(version && versionInMain) {
					if(compareVersions(version, versionInMain) <= 0)
						return result;
				} else {
					var getVersionString = function(v) {
						return v ? "unknown version" :
							("version" + v);
					}
					
					if(!confirm(importAnotherVersionConfirmation
						.format(t.title, url,
						 getVersionString(version),
						 getVersionString(versionInMain)))
					) return result;
				}
			}
		}

		if(options.ask) {
			var confirmMessage = options.which == 'newer' ?
				"Up-to-date "+ t.title +" from "+ url +" is availabe, import?" :
					options.which == 'newerVersion' ?
				importAnotherVersionConfirmation.format(t.title, url,
					"version "+ version, "version "+ versionInMain) :
				t.title +" from "+ url +" is availabe, import?"
			if(!confirm(confirmMessage))
				return result;
		}

		// report unsupported mode
		if(options.mode && !(options.mode in { 1: true, 2:true, 3:true, 4:true }))
		{
			result.status = -1;
			result.errorText = "unknown import mode";
			return result;
		}

		var doImport = function(t) {
			if(url) t.deleteIncludeURL();
			store.addTiddler(t);
			store.setDirty(true);
			result.status = 0;
			result.tiddler = t;
			result.from = url;
		};
		doImport(t);

		return result;
	};
	this.importAndLog = function(tiddler, modeOrOptions) {

		var options = calcImportOptions(modeOrOptions),
		    result  = twWeb.importIncluded(tiddler, options),
		    name    = tiddler.title;
		// this.importIncluded is not used to be able to pass the method to the API

		switch(result.status) {
			case 0:	 console.log("imported: "+name+" from "+result.from);
				 break
			case -1: console.log("error importing "+name+": "+result.errorText);
				 break
		}
		return result;
	};

	// ---- main ----

	// Includes the (local or remote) TiddlyWiki store with the given url.
	//
	// @param url		see url@stp_loadTiddlyWikiStore
	// @param includeParams	a set of the following params for including:
	//	filterLine		a filter expression defining a set of tiddlers to include
	//	substituting		points whether an included tiddler should sustitute
	//				one in the main document if there's a conflict of names
	//	substituteShadows	points whether shadowed tiddlers of the main document with names equal to
	//				those of included ones should be substituted (in cases of conflicts);
	//				works only with (substituting == true)
	//	delayMilliSeconds	addition delay of loading
	//	noRefresh
	//	importOptions
	//	evalTiddlers
	//	wikifyTiddlers
	//
	this.include = function(urlOrNodeParam, includeParams) {

		if (!isIncludeEnabled())
			return;
		var self = this;

		var includeOrHandleUrl = function(url) {

			var loadStoreCallback = function(theStore,urlInCallback,params,errorMessage) {

				if(theStore === undefined) {
				
					includedStores[url] = errorMessage;
					self.onError(url, errorMessage);
					return;
				} else
					includedStores[url] = theStore;

				// keep orig_store not to load tw-documents multiple times
				// because of multiple include macros:
				includedStores[url].orig_store = new TiddlyWiki();
				includedStores[url].forEachTiddler(function(tName,tiddler){
					tiddler.setIncludeURL(url);
					includedStores[url].orig_store.addTiddler(tiddler);
				});
				includedStores[url].clear();

				// include, create fetchPreferences and notify of conflicts; or import
				addFromLoadedStore();
			};

			var addFromLoadedStore = function() {
			// uses url and includeParams exploiting closure

				var substituting = includeParams.substitute,
				    substituteShadows = includeParams.substituteShadows,
				    importOptions = includeParams.importOptions;

				// new tiddlers can be added *when the store is loaded*
				if(twWeb.getStore(url) === null)
					return invokeLater(addFromLoadedStore, 100);

				// add tiddlers to included stores and check new conflicts (among non-subs. tids)
				var i, t,
				    new_tiddlers = includedStores[url].orig_store.filterTiddlers(includeParams.filterLine);

				for(i = 0; i < new_tiddlers.length; i++) {

					t = jQuery.extend(true, new Tiddler(), new_tiddlers[i]); //copy (by value)

					if(includedStores[url].orig_store.fetchTiddler(t.title)) {
					// ignore empty tiddlers created by the "tiddler" filter
					    if(importOptions) {
					        twWeb.importAndLog(t, importOptions);
					    } else {
					        // check for upcoming conflicts first
					        conflicts.checkNew(t.title, url, substituting, substituteShadows);
					        // then include
					        includedStores[url].addTiddler(t);
					    };
					    if(includeParams.evalTiddlers)
					        installPlugin(t);
					    if(includeParams.wikifyTiddlers)
					        wikify(t.text,document.createElement("div"),undefined,t);
					};
				};

				// add items to fetchPreferences if have to
				if(!importOptions && (substituting || substituteShadows))
					for(i = 0; i < new_tiddlers.length; i++)
						fetchPreferences.add(new_tiddlers[i].title,url,substituting, substituteShadows);
				conflicts.notify();

				// "recalc" slices
				store.slices = {};
				// refresh things to get included stylesheets, PageTemplate and ViewTemplate applied
				if(!includeParams.noRefresh) {
					refreshAll();
					story.refreshAllTiddlers();
				}

				pendingOnLoadURLs.push(url);
				invokeLater(notifyListeners);
			};

			var loadStore = function() {
				includedStores[url] = LOADING;
				stp_loadTiddlyWikiStore(url,loadStoreCallback,null,progress);
				// {includeParams:includeParams} can be used instead of null so that
				// loadStoreCallback will have access to the includeParams
			};

			var urlIsNew = !(includedStores[url]);

			if(urlIsNew) {

				includedStores[url] = WAITING;

				if (includeParams.delayMilliSeconds)
					invokeLater(loadStore, includeParams.delayMilliSeconds);
				else
					loadStore();
			} else
				addFromLoadedStore();
		};

		var nodeName = this.checkNodeNotation(urlOrNodeParam);

		if(nodeName) {
			if(nodeName == this.getSelfNodeName()) // don't include from the main (self) TiddlyWiki
				return;

			this.setWaitingTask(nodeName,function(){
				var url = this.getNodeUrl(nodeName);
				includeOrHandleUrl(url);
			},this);
		} else
			includeOrHandleUrl(urlOrNodeParam);
	};
	
// ----- Methods for dealing with included stuff -----------------------------------------

	// @return [] of Strings, the URLs of the includes
	//
	this.getIncludedStoresUrls = function() { // in a form of an array

		var includes = [];
		for(var url in includedStores)
			includes.push(url);
		return includes;
	};
	// @return the (TiddlyWiki) store with the given URL or "node: nodeName", or null if not (yet) loaded.
	//
	this.getStore = function(nodeId) {

		var url = self.getStoreUrlById(nodeId)
		if(!url)
			return null;

		var s = includedStores[url];
		if(s && s instanceof TiddlyWiki)
			return s;
		return null;
	};
	// @return a state/error text of the store with the given URL, or null when the store is already loaded
	//
	this.getState = function(nodeId) {

		var url = self.getStoreUrlById(nodeId)
		if(!url)
			return "the node "+self.checkNodeNotation(nodeId)+" is not described yet, the address is unknown";

		var s = includedStores[url];
		if (!s)
			return getMissingIncludeMsg(url);
		return typeof s == "string" ? s : null;
	};
	// reload one included store or all of them
	// previous inclusions are done again, by default only those without eval and import
	// important: reload doesn't work correctly with <<include>> usages with multiple urls
	//
	// @param  reloadParams  an object containing some of these configuration properties:
	//	urlOrNodeList	an array of TWs' IDs (url or "node: nodeName") to reload;
	//			if undefined, all TWs are reloaded
	//	eval		points whether to redo inclusions with the "eval" parameter (undefined == false)
	//	import		same for the "import" parameter, but undefined/null -> true
	//	wikify		same for the "wikify" parameter
	this.reload = function(reloadParams) {

		// determine a TW(s) to reload (undefined => all)
		var i, twsToReload = reloadParams.urlOrNodeParam;

		// turn "IDs" into actual urls; filter out node names for which urls are not defined
		// so waiting tasks are not doubled
		if(twsToReload)
			for(i = 0; i < twsToReload.length; i++){ 
				nodeName = this.checkNodeNotation(twsToReload[i]);
				twsToReload[i] = nodeName ? this.getNodeUrl(nodeName) : twsToReload[i];
				if(!twsToReload[i])
					twsToReload.splice(i--,1);
			}

		if(reloadParams.import === undefined || reloadParams.import === null)
			reloadParams.import = true;
		if(reloadParams.wikify === undefined || reloadParams.wikify === null)
			reloadParams.wikify = true;

		// collect macro expressions to reload
			// may the order of including be important?
		var usage, usages = this.includeUsages.getUsed(),
		    paramString, params, pParams, urlParam, nodeName,
			dontReload, i;

		for(usage in usages) {

			// parsing copied from config.macros.include.handler (to get macro params)
			paramString = usage.substring(10,usage.length - 2);
			params = paramString.readMacroParams();
			pParams = paramString.parseParams("url",null,true,false,true);
			urlParam = pParams[0]["url"][0];
			nodeName = this.checkNodeNotation(urlParam);
			urlParam = nodeName ? this.getNodeUrl(nodeName) : urlParam;

			// keep only inclusions that contain IDs corresponding to urls from twsToReload
			dontReload = true;
			if(twsToReload) {
				for(i = 0; i < twsToReload.length; i++)
					if(urlParam == twsToReload[i])
						dontReload = false;
			} else
				dontReload = false;

			// exclude inclusions with import and eval, if necessary
			if(!reloadParams.import && getParam(pParams,"import",undefined) ||
			   !reloadParams.eval && params.contains('eval') ||
			   !reloadParams.wikify && params.contains('wikify'))
				dontReload = true;

			if(dontReload) {
				delete usages[usage];
				continue;
			}

			// clean stuff: unload included store, clear priorities, remove conflicts;
			// deleting "used" marks is outside this loop
			includedStores[urlParam] = undefined;
			fetchPreferences.removeByUrl(urlParam);
			conflicts.markNodeUnloaded(urlParam);
		}
		// delete "used" marks
		this.includeUsages.markUnused(usages);
		
		// include again
		for(usage in usages)
			wikify(usage,document.createElement("div"),undefined,null);
	};
};
twWeb = new TwWeb();

//================================================================================
// Default Progress Handling for config.extensions.SharedTiddlersPlugin

var showAnimated = function(e, showing, duration) {
//	if (!anim || !abego.ShowAnimation) {
		e.style.display = showing ? "block" : "none";
		return;
//	}
	
//	anim.startAnimating(new abego.ShowAnimation(e,showing,duration));
};

config.extensions.SharedTiddlersPlugin.getDefaultProgressFunction = function() {

	setStylesheet(
		".includeProgressState{\n"+
		"background-color:#FFCC00;\n"+
		"position:absolute;\n"+
		"right:0.2em;\n"+
		"top:0.2em;\n"+
		"width:7em;\n"+
		"padding-left:0.2em;\n"+
		"padding-right:0.2em\n"+
		"}\n",
		"stp_Include");

	var createStateElem = function() {
		var e = document.createElement("div");
		e.className = "includeProgressState";
		e.style.display = "none";
		document.body.appendChild(e);
		return e;
	};
	
	var stateElem = createStateElem();


	var showState = function(message) {
		removeChildren(stateElem);
		createTiddlyText(stateElem,message);
		showAnimated(stateElem,true,0);
	};

	var hideState = function() {
		// hide the state the next idle time 
		invokeLater(function() {
			showAnimated(stateElem,false,ANI_DURATION_HIDE_STATE);
		},100,ANIMATION_PRIORITY);
	};
	
	var myProgressFunction = function(message, sender, state, url, params) {
		
		if (state == "Done" || state == "Failed") {
			hideState();
			return;
		}
		
		if (sender == "stp_loadTiddlyWikiStore") {
			idleCount = 0;
			if (state == "Processing")
				showState("Including...");
		} else {
			showState(message);
		}
	};
	return myProgressFunction;
};

twWeb.setProgressFunction(config.extensions.SharedTiddlersPlugin.getDefaultProgressFunction());


//================================================================================
// Change standart formatters

var getFormatterIndex = function(formatterName) {
	for(var i = 0; i < config.formatters.length; i++)
		if(config.formatters[i].name == formatterName)
			return i;
	return null;
}

//--------------------------------------------------------------------------------
// Change the prettyLink formatter so that it
// * recognizes [[text|target]]@nodeName and [[target]]@nodeName syntax
// * takes into account includeURL of the tiddler and propagates inclusion

if(config.options.STP_hijackPrettyLink) {
	var prettyLinkFormatterIndex = getFormatterIndex("prettyLink");
	config.extensions.SharedTiddlersPlugin.orig_prettyLinkFormatter = config.formatters[prettyLinkFormatterIndex];
	config.formatters[prettyLinkFormatterIndex] = {

		name:  "prettyLink",
		match: "\\[\\[",
		lookaheadRegExp: /\[\[(.*?)(?:\|(~)?(.*?))?\]\](?:(?:@(\w+))(?:@([\w\s\:]+)@)?)?/mg,
		handler: function(w) {

			this.lookaheadRegExp.lastIndex = w.matchStart;
			var lookaheadMatch = this.lookaheadRegExp.exec(w.source);
			if(lookaheadMatch && lookaheadMatch.index == w.matchStart) {

				// call the formatter
				config.extensions.SharedTiddlersPlugin.orig_prettyLinkFormatter.handler(w);

				// call the include.handler, if necessary
				var node = lookaheadMatch[4]? lookaheadMatch[4] : undefined,
				    includeURL = w.tiddler? w.tiddler.getIncludeURL() : null,
				    urlParam = node? twWeb.setNodeNotation(node) : (includeURL? includeURL : undefined),
				    target = lookaheadMatch[3]? lookaheadMatch[3] : lookaheadMatch[1],
				    // use a eval'ed filter expression to deal with titles containing ', " etc
				    filter = "{{"+JSON.stringify('[['+target+']]')+"}}",
				    paramString = '"'+urlParam+'" filters:'+filter+' hide noRefresh ';
				if(lookaheadMatch[5])
					paramString += lookaheadMatch[5];
				if(urlParam)
					config.macros.include.handler(w.output,"include",
						paramString.readMacroParams(true),w,paramString,w.tiddler);

				// move nextMatch according to this.lookaheadRegExp, not original prettyLink
				w.nextMatch = this.lookaheadRegExp.lastIndex;
			}
		}
	};
}

//--------------------------------------------------------------------------------
// Change the image formatter so that it
// * takes into account includeURL of the tiddler and recalcs relative urls

if(config.options.STP_hijackImageFormatter) {
	var imageFormatterIndex = getFormatterIndex("image");
	config.extensions.SharedTiddlersPlugin.orig_imageFormatterHandler = config.formatters[imageFormatterIndex].handler;
	config.formatters[imageFormatterIndex].handler = function(w) {

		var lastChildBeforeHandling = w.output.lastChild;
		config.extensions.SharedTiddlersPlugin.orig_imageFormatterHandler.apply(this,arguments);

		if(w.output.lastChild != lastChildBeforeHandling) {

			var elem = w.output.lastChild,
			    // sometimes elem is not the image itself, but a wrapper (<a>)
			    img = elem.tagName.toLowerCase() == "img" ? elem : jQuery(elem).find("img")[0],
			    includeURL = w.tiddler ? w.tiddler.getIncludeURL() : "",
			    imgSrc = jQuery(img).attr("src");

			// take includeURL into account:
			img.src = resolveUrlFrom(imgSrc, includeURL);
		}
	}
}

//================================================================================
// Add inline-management tools by hijacking .edit.handler

config.extensions.SharedTiddlersPlugin.orig_editHandler = config.macros.edit.handler;
config.macros.edit.handler = function(place,macroName,params,wikifier,paramString,tiddler) {
	var includeUrl = tiddler.getIncludeURL();
	if(params[0] == "text" && includeUrl){ // only for "text", not other fields
		var e = createTiddlyElement(null,"div");
		e.className = "manageIncludedPanel";
		createTiddlyText(e,"manage the included tiddler: ");

		// go to the source
		var sourceUrl = includeUrl + "#[["+tiddler.title+"]]";
		createExternalLink(e, sourceUrl, "open in the source TiddlyWiki");
		// view the link to the source
		createTiddlyText(e," (");
		createTiddlyButton(e, "view link", "view the link to the source", function(e){
			var popup = Popup.create(this);
			createTiddlyText(createTiddlyElement(popup, 'li', '', 'disabled'), sourceUrl);
			Popup.show();
			var ev = e || window.event;
			ev.cancelBubble = true;
			if(ev.stopPropagation)
				ev.stopPropagation();
			return false;
		}," ");
		createTiddlyText(e,")");

		// import
		if(!readOnly) {
			createTiddlyText(e," | ");
			createTiddlyButton(e,"import","import this tiddler",function(){
				var result = twWeb.importAndLog(tiddler, 1);
				switch(result.status) {
					case 0:	 displayMessage("imported \""+tiddler.title+"\" from "+result.from);
				 		break
					case -1: displayMessage("error importing \""+tiddler.title+"\": "+result.errorText);
						 break
				}
			}," ");
		}

		// reload
		createTiddlyText(e," | ");
		config.macros.reloadIncluded.handler(e,"",null,null,'urls:\'["'+includeUrl+'"]\'',tiddler);

		// other actions

		// if the read only mode is not set, display all tools otherwise ...
		place.appendChild(e);
	}
	return config.extensions.SharedTiddlersPlugin.orig_editHandler(place,macroName,params,wikifier,paramString,tiddler);
};
//============================================================================
// The "describeNode" macro
//
// Syntax: <<describeNode nodeName {nodeUrl|self}>>
//
config.macros.describeNode = {};
config.macros.describeNode.handler = function(place,macroName,params,wikifier,paramString,tiddler) {

	var macroTWcode = wikifier.source.substring(wikifier.matchStart, wikifier.nextMatch);
	createTiddlyText(createTiddlyElement(place,"code"), macroTWcode);

	// node description duplicates are handled when adding, no "handle only once" here

	var includeURL = tiddler.getIncludeURL(),
	    nodeName = params[0],
	    urlParam = params[1],
	    self = (urlParam == "self");

	if(self) {
		var oldSelf = twWeb.getSelfNodeName();
		if(oldSelf && (oldSelf != nodeName))
			return alert("The \'"+oldSelf+"\' alias is already assigned as "+
					"the name of the current TiddlyWiki; the new "+
					"attempt to assign \'"+nodeName+"\' is ignored.");
		twWeb.setSelfNodeName(nodeName);
		return;
	}

	var url = resolveUrlFrom(urlParam, includeURL);
	url = stp_resolveURL(url); // if no includeURL

	twWeb.addNodeDesc(nodeName,url);
};

function calcImportOptions(modeOrOptions) {

	if(!modeOrOptions) return null;
	var options = typeof modeOrOptions != "object" ? // string or number
			{ mode: modeOrOptions } : modeOrOptions;
	if(!options.mode && !options.which && options.ask === undefined) return null;

	// other import options take precedence over mode, so one may go more specific
	if(options.which === undefined)
		options.which =
			options.mode in { 1:true, 3:true } ? 'all' :
			options.mode in { 2:true, 4:true } ? 'newer' :
			options.ask !== undefined ? 'all' : undefined
	if(options.ask === undefined)
		options.ask =
			options.mode in { 1:true, 2:true } ? false :
			options.mode in { 3:true, 4:true } ? true :
			options.which !== undefined ? false : undefined;
	else if(options.ask == 'false')
		options.ask = false;

	return options;
}

//============================================================================
// The "include" macro
//
// Syntax:	<<include [url:]url [filters:filterLine] [substitute]
//			  [substituteShadows] [hide:hideFlag] [delay:delayDuration]>>
//
config.macros.include = {};
config.macros.include.handler = function(place,macroName,params,wikifier,paramString,tiddler) {

	var macroTWcode = wikifier.source.substring(wikifier.matchStart, wikifier.nextMatch),
	    pParams = paramString.parseParams('url',null,true,false,true); // allowEval, cascadeDefaults, names allowed

	var hide = getFlag(pParams, 'hide', false) || params.contains('hide');
	if(!hide) createTiddlyText(createTiddlyElement(place, 'code'), macroTWcode);

	if (twWeb.includeUsages.isUsed(macroTWcode)) return;
	twWeb.includeUsages.setUsed(macroTWcode);

	var urls = pParams[0]['url'];

	var importOptions = calcImportOptions({
		mode:  getParam(pParams, 'import', undefined),
		which: getParam(pParams, 'importOnly', undefined),
		ask:   getParam(pParams, 'askBeforeImport', undefined)
	});

	var includeParams = {
		delayMilliSeconds:	parseInt(getParam(pParams,'delay',"0")),
		filterLine:		getParam(pParams,'filter') ||
					getParam(pParams,'filters','[all[-]]'),
		substitute:		params.contains('substitute'),
		substituteShadows:	params.contains('substituteShadows'),
		noRefresh:		params.contains('noRefresh'),
		importOptions:		importOptions,
		evalTiddlers:		params.contains('eval'),
		wikifyTiddlers:		params.contains('wikify')
	};

	var checkUrlAndInclude = function(url)
	{
		if(url == 'hide' || url == 'substituteShadows' || url == 'substitute' ||
		   url == 'eval' || url == 'wikify' || url == 'noRefresh')
			return;

		twWeb.include(url,includeParams);
	};

	var placeParentHolder = place.parentElement;

	for (var i = 0; urls && i < urls.length; i++)
		checkUrlAndInclude(urls[i]);
	// here's a fix for the mysterious loss of the "place" of being a child of .. (kept in placeParentHolder)
	// reattach place to the placeParentHolder:
	if(placeParentHolder)
		placeParentHolder.appendChild(place);
		//placeParentHolder.getElementsByClassName('viewer')[0] = place;
};

//============================================================================
// The "reloadIncluded" macro
//
// Syntax: <<reloadIncluded [urls:urlsJSON] [reloadParams:otherReloadParamsJSON]
//		[label:labelText] [tooltip:tooltipText] [class:className]>>
// (for reloadParams, see twWeb.reload)
//
config.macros.reloadIncluded = {};
config.macros.reloadIncluded.handler = function(place,macroName,params,wikifier,paramString,tiddler) {

	// parse params
	var pParams = paramString.parseParams('url', null, true, false, true),
	    label    = getParam(pParams, 'label', "refresh"),
	    tooltip  = getParam(pParams, 'tooltip', undefined),
	    elClass  = getParam(pParams, 'class', ' '), // ' ' overwrites the default 'button' class
	    urlsText = getParam(pParams, 'urls', undefined),
	    otherReloadParamsText = getParam(pParams, 'reloadParams', '{}'),
	    reloadParams = JSON && JSON.parse(otherReloadParamsText) || jQuery.parseJSON(otherReloadParamsText);
	reloadParams.urlOrNodeList = !urlsText ? undefined :
			(JSON && JSON.parse(urlsText) || jQuery.parseJSON(urlsText));
	if(!tooltip) {
		if(reloadParams.urlOrNodeList) {
			tooltip = "refresh '"+reloadParams.urlOrNodeList[0]+"'";
			for(var i = 1; i < reloadParams.urlOrNodeList.length; i++)
				tooltip += ", '"+reloadParams.urlOrNodeList[i]+"'";
			tooltip += (i > 0) ? " nodes" : " node";
		} else
			tooltip = "refresh all included nodes";
	}

	// create button, add handler
	createTiddlyButton(place,label,tooltip,function() {
		var returnHere = function() {
			if(twWeb.hasPendingIncludes()) {
				invokeLater(returnHere,100);
				return;
			} // wait until all the stores are loaded and the page is refreshed
			var t = tiddler.title, te = DEFAULT_VIEW_TEMPLATE;
			story.displayTiddler(this,t,story.chooseTemplateForTiddler(t,te));
		}
		twWeb.reload(reloadParams);
		invokeLater(returnHere, 100); // wait a bit for the nodes to unload
	},elClass);
};

//============================================================================
// The "includeState" macro
//
// Syntax: <<includeState>>
//
config.macros.includeState = {};
config.macros.includeState.handler = function(place,macroName,params,wikifier,paramString,tiddler) {
	var getFullState = function () {
		var s = "";
		var includes = twWeb.getIncludedStoresUrls();
		if (!includes.length)
			return "{{noIncludes{\nNo TiddlyWiki is included or including is disabled (see AdvancedOptions)\n}}}\n";
			
		s += "|!Address|!State|\n";
		for (var i = 0; i < includes.length; i++) {
			var inc = includes[i];
			s += "|{{{"+inc+"}}}|";
			var t = twWeb.getState(inc);
			s += t ? "{{{"+t+"}}}" : "included";
			s += "|\n"
		}
		s += "|includeState|k\n";
		return s;
	};
	
	var updateState = function() {
		removeChildren(div);
		wikify(getFullState(),div);
		if (twWeb.hasPendingIncludes())
			invokeLater(updateState,500,UPDATE_STATE_PRIORITY);
	};

	var div = createTiddlyElement(place, 'div');
	
	invokeLater(updateState,0,UPDATE_STATE_PRIORITY);
};
// Perform plugin startup tasks
attachToStore();
invokeLater(includeFromIncludeList,100);

// add several more methods to the "API namespace"
window.sharedTiddlersAPI.getIncludes  = twWeb.getIncludedStoresUrls;
window.sharedTiddlersAPI.getState     = twWeb.getState;
window.sharedTiddlersAPI.getStore     = twWeb.getStore;
window.sharedTiddlersAPI.importAndLog = twWeb.importAndLog;

// Deprecated: now is same as store.forEachTiddler (iterates over all tiddlers
// of "the store" and all tiddlers of included [and loaded] stores)
//
window.sharedTiddlersAPI.forReallyEachTiddler = function(callback) {
	store.forEachTiddler(callback);
};

// for the "install only once" check, prevents conflicts with abego.IncludePlugin as well
// (this is also deprecated API for backward compability)
abego.TiddlyWikiIncluder = {
	getIncludes:	twWeb.getIncludedStoresUrls,
	getState:	twWeb.getState,
	getStore:	twWeb.getStore
};
})();
//}}}
|Description|Documentation for [[SharedTiddlersPlugin|https://yakovl.github.io/TiddlyWiki_SharedTiddlersPlugin/#SharedTiddlersPlugin]]|
|Source     |https://yakovl.github.io/TiddlyWiki_SharedTiddlersPlugin/#SharedTiddlersPluginInfo|
|Author     |Yakov Litvin|
|Version    |2.5.1|
|Contact    |Create an [[issue|https://github.com/YakovL/TiddlyWiki_SharedTiddlersPlugin/issues]] or start a new thread in the [[Google Group|https://groups.google.com/g/tiddlywikiclassic/]] (please read docs, esp. "Installation, configuring and troubleshooting" section before asking)|
|License    |[[BSD-like open source license|https://yakovl.github.io/TiddlyWiki_SharedTiddlersPlugin/#%5B%5BYakov%20Litvin%20Public%20Licence%5D%5D]]|
<<tabs txtSharedTiddlersPluginInfoTab
	"Installation, configuring and troubleshooting" "" [[SharedTiddlersPluginInfo##Installation, configuring and troubleshooting]]
	"Functionality and examples" "" [[SharedTiddlersPluginInfo##Functionality and examples]]
	"Detailed reference" "" [[SharedTiddlersPluginInfo##Detailed reference]]
	"More details on possible applications" "" [[SharedTiddlersPluginInfo##More details on possible applications]]
	"API changes and coding with SharedTiddlersPlugin" "" [[SharedTiddlersPluginInfo##API changes and coding with SharedTiddlersPlugin]]
	{{"Making other plugins \"include-(un)aware\""}} "" [[SharedTiddlersPluginInfo##Making other plugins include-(un)aware]]
	"Versions history and quality issues" "" [[SharedTiddlersPluginInfo##Versions history and quality issues]]
>>/%
!Functionality and examples
<html><h1>Including and include macro</h1>
<h2>Simple including</h2>
</html>Including is done via the {{{include}}} macro. For instance, a ~TiddlyWiki you'd like to include from is named {{{references.html}}} and is put in the same folder that another one, {{{main.html}}}, you'd like to include to. To include all the tiddlers from {{{references.html}}}, put the following macro in {{{main.html}}}:
{{{
<<include "./references.html">>
}}}
Where exactly should you write the macro? Usually, {{{include}}} macros are written in IncludeList: all the macros in there are wikified at startup, so the secondary TW is included each time the main one is opened. Alternatively, you can put {{{include}}} macro in an arbitrary tiddler, in that case including will be done when the tiddler is displayed (wikified). If you want to avoid it being visible, write it as
{{{
<<include "./references.html" hide>>
}}}

<html><h2>Partial including</h2>
</html>There are various reasons why you may prefer to include only a subset of tiddlers from another TW. For instance, you want to include only tiddlers tagged {{{ToDo}}} to your GTD thing and don't want the timeline to get crowded by other tiddlers from outside. For that case {{{include}}} macro supports core filter engine:
{{{
<<include "./projects/myProject.html" filters:"[tag[ToDo]] [[Summary]]">>
}}}
For more details about filters, see the "Detailed reference" part of the docs.

<html><h2>Substituting tiddlers in main TiddlyWiki</h2>
</html>By default, if the including and an included TW both have a tiddler named "A", the tiddler from the main ~TiddlyWiki will be displayed/fetched in all the situations; even if in the main TW only a shadowed tiddler "A" is present. As sometimes this is not a desirable behaviour, there's {{{substitute}}} and {{{substituteShadows}}} options in the {{{include}}} macro:
{{{
<<include "./commons.html" filters:"[[PageTemplate]] [[ViewTemplate]]" substituteShadows>>
}}}
will bring PageTemplate and ViewTemplate instead of the shadowed ones; and
{{{
<<include "./commons.html" filters:"[[PageTemplate]] [[ViewTemplate]]" substituteShadows substitute>>
}}}
will do so even if custom PageTemplate or ViewTemplate are created. Note: included tiddlers are not saved in the including TW, unless the import options are used (see below).

<html><h2>Import and autoimport of included tiddlers</h2>
</html>For some tiddlers, you may prefer importing instead of just including -- in this case you may use a "manual" tool ImportIncluded or autoimport via the {{{include}}} macro:
{{{
<<include "./local_repositories/STP.html" filters:"[[SharedTiddlersPlugin]]"
  importOnly:newer askBeforeImport:true>>
}}}
where {{{importOnly}}} may also be {{{all}}}. For details, see the "Detailed reference" part.

<html><h2>Launching (wikifying) macros from included tiddlers</h2>
</html>This feature was designed primarily for centralized system of customization of ~TiddlyWikis. Imagine a TW called "commons.html" which has different parts of interface (like PageTemplate or ToolbarCommands), some evaluated transclusions etc. The idea is do changes to that TW so that they are applied in all your ~TWs. You can include all the elements in other ~TWs but the problem is you still have to make changes in all the ~IncludeLists. The solution is brought by introducing the {{{wikify}}} parameter to the {{{include}}} macro. Consider this: IncludeList in each of your ~TWs contains just
{{{
<<include "./commons.html" filters:"[[IncludeHub]]" wikify>>
}}}
and all the changes are done in the {{{IncludeHub}}} tiddler in your commons.html like these:
{{{
<<include "./commons.html" filters:"[[PageTemplate]]" substituteShadows>>
<<include "./local_repositories/STP.html" filters:"[[SharedTiddlersPlugin]]" import:4>>
 // you can remove, change or add macros in here so that they are applied in each of your TWs
}}}
The only issue is as long as you use relative addresses, you have to place all your ~TWs in the same folder as "commons.html" (how to pass around this limitation, see below).

<html><h2>Launching plugins from included TiddlyWikis</h2>
</html>Plugin launching is done on startup, so just including external plugins is "too late" and they won't actually work. To launch a plugin from an included tiddler, use {{{eval}}} parameter of the {{{include}}} macro:
{{{
<<include "./commons.html" filters:"[[RearrangeTiddlersPlugin]]" eval>>
}}}
For many plugins, most likely, you will use both {{{improt:4}}} and {{{eval}}} parameters.

<html><h2>Reloading included stuff</h2>
</html>Sometimes it's desirable to reload included tiddlers without reloading the whole TW document. For this case, the {{{reloadIncluded}}} macro was introduced. It generates a link/button which reloads tiddlers from certain ~TWs on click:
{{{
<<reloadIncluded urls:'["node: node1", "included test nodes/node 2.html"]' reloadParams:'{"import":false}'>>
}}}
Also, this link can be found in the toolbar of included tiddlers (in the edit mode).

<html><h2>Avoiding excessive refreshing</h2>
</html>After including, the {{{include}}} macro refreshes your TW -- this is done for things like ~StyleSheets or ~ViewTemplate to get applied. However, multiple refreshing on startup can take a second or more, so it can be desirable to avoid refreshing. It is recommended to use the corresponding {{{noRefresh}}} parameter with all {{{include}}} macros that don't need it (usually those including content tiddlers, but not elements of themes, like ~ViewTemplate):
{{{
<<include "./references/holy writ.html" filters:"[[contents]] [tag[chapter]] [tag[verse]]" noRefresh>>
<<include "./references/Feuerbach.html" filters:"[[list of publications]] [tag[publication]]" noRefresh>>
<<include "./commons.html" filters:"[tag[theme parts]]" substitute substituteShadows>>
}}}

<html><h1>TwWeb</h1>
</html>Sometimes it is desirable to rename or move ~TiddlyWikis, and such changes can break many links/includes. Also, using relative paths in {{{include}}} macros can cause errors in the path calculation when the macro itself is contained in an tiddler included from "path/A.html", where "path" is not ".". To avoid these pesky issues and to enable further "merging" of ~TWs, ~TwWeb system was introduced.

<html><h2>Describing a node</h2>
</html>The idea is to describe "nodes" -- ~TWs with certain addresses and then use node names instead of addresses. The {{{describeNode}}} does the first part of the job:
{{{
<<describeNode "commons" "./commons.html">>
}}}
where the first argument is the name of the node and the second one is its address. It is recommended to give your nodes names without spaces (for compability with future features). Note that you can use {{{include}}} macro with {{{wikify}}} parameter to take node descriptions from another TW. This means that you can create a central TW with all node descriptions, include it, and use in all other ~TWs node names instead of addresses. After that, renaming a TW should be backed up by only changing the description in the central node.

<html><h2>Support of node names</h2>
</html>Node names are supported in the following mechanisms:
# {{{include}}} macro can get a special form of the url parameter:{{jD{
{{{
<<include "node: node_name" ...>>
<<include "node: commons" filters:"[tag[theme parts]]" substitute substituteShadows>>
}}}
}}} If the macro is wikified before the node was described, it "waits" for the description to appear.
# ImportIncluded allows this "form of url" too
# the {{{includedFrom}}} filter supports the {{{[includedFrom[node: nodeName]]}}} notation
# extended prettyLinks now work in the following syntaxes:
## {{{[[link text|target tiddler]]@nodeName}}} -- which includes the {{{target tiddler}}} and creates an ordinary {{{[[link text|target tiddler]]}}} prettyLink
## {{{[[link text|target tiddler]]@nodeName@options line@}}} which does the same but uses options from the {{{options line}}} as well: for instance, to substitute an existing tiddler {{{target tiddler}}}, just add the options line {{{substitute}}}.
** if the included TW is large so you're delayed waiting when the link get enabled, it can be an option to include the node with an empty filter ({{{filters:""}}}) using IncludeList (may be with the delay option, too)
* @@font-size:smaller;In the future versions of STP, some other engines may be supported: for instance, {{{<<tiddler [[tiddler name]]@nodeName>>}}}.@@

<html><h2>Describing self</h2>
</html>To avoid different side effects of transitive inclusion (like including a tiddler by TW "A" from the same TW "A" with substituting which makes it impossible to edit the tiddler) you can mark one nodeName as "self":
{{{
<<describeNode nodeName self>>
}}}
This prevents from including from {{{nodeName}}} at all; such self-description should be put into the IncludeList.

<html><h2>Propagation</h2>
</html>As included tiddlers can contain links, images, transclusions etc, STP takes care of those so that they are not broken (to some extent). See details in the "Detailed reference" section.

<html><h2>Inline management of included tiddlers</h2>
</html>In the edit mode an included (but not imported) tiddler has an additional panel with a link to its "original" in the included TW, a link which imports it and a refresh link that reloads the included TW. This is added by default, no changes to EditTemplate are needed.

!Detailed reference
<html><h2>IncludeList tiddler</h2>
</html>Special tiddler IncludeList is used to wikify macros within it on the startup of ~TiddlyWiki: it's implied that you write {{{<<include>>}}} and {{{<<describeNode>>}}} macros that you need to lauch (each time) there. For instance, if you write
{{{
<<include "./common TW elements.html" filters:"[[PageTemplate]]" substituteShadows>>
}}}
in there, the including will be done each time the TW is opened.

<html><h2>The "include" macro</h2>
</html>The {{{<<include>>}}} macro has the following syntax (@@font-size:smaller;[...] parts are optional@@):
{{{
<<include [url:]url [{filter|filters}:filterLine] [substitute] [substituteShadows]
  [import:importMode] [importOnly:checkType] [askBeforeImport:askFlag] [eval] [wikify] [noRefresh] [hide[:hideFlag]] [delay:delayDuration]>>
}}}
|The parameters of the {{{<<include>>}}} macro|c
| name			 | demanded?	 | value | effect | comments |h
| ''url''			 | demanded	 | a url line in quotes | defines the path to the ~TiddlyWiki from which stuff is included | by "url line" a relative path, an absolute local file path, or a "file:" URL is meant |
| ''filter'' or ''filters''	 | optional	 | a line of TW filters in quotes | defines the set of tiddlers included from the TW;<br>if omitted, means "include all" (the ''filter'' variant was introduced in 2.5.0) | see "Filters" below |
| ''substitute''		 | optional	 | none | adds "substitute" priority to the included tiddlers | see "Name conflicts and priorities" below |
| ''substituteShadows''	 | optional	 | none | adds "substituteShadows" priority to the included tiddlers |~|
| ''import''			 | optional	 | an id of an import mode to use | tiddlers are imported instead of including | see "Import tools" below |
| ''importOnly''		 | optional	 | "all" or "newer" | when a tiddler with the same title is already present in current TW, import or not? |~|
| ''askBeforeImport''	 | optional	 | boolean | ask per tiddler whether to import |~|
| ''eval''			 | optional	 | none | treats tiddlers as plugins | see "Evaluating tiddlers" below |
| ''wikify''			 | optional	 | none | wikifies tiddlers after loading/importing | can be used to wikify {{{include}}} and other macros;<br>may also be useful with evaluated transclusions |
| ''noRefresh''		 | optional	 | none | prevents refreshing of TW after tiddlers are loaded | refreshing is used to apply included style sheets, elements of interface etc, but multiple refreshing can slow down the startup time; to avoid such effects, this option is to be used in macros that include only content (not parts of the interface) |
| ''hide''			 | optional	 | boolean | by default the macro is displayed as written; when {{{hideFlag}}} is {{{true}}}, it's hidden | can be useful when the macro is used outside ~IncludeList |
| ''delay''			 | optional	 | number (integer) | defines the number of milliseconds (thousands of a second) to wait before actually including the ~TiddlyWiki ||
Some examples of how the ''url'' line can be written:
{{{
<<include "C:\TiddlyWiki\shared\TiddlyWikiHelp.html" hide:true>>
<<include "file://C:/Private/journals/2006-12.html" delay:8000>>
<<include "../tests/STP/sample33.html" hide>>
<<include "tests/main_sample.html">>
}}}
__Note__: some browsers forbid including from outside the folder where the including TW is placed. See details in the "Installation, configuring and troubleshooting" section.

<html><h2>Filters</h2>
</html>See main documentation [[at tiddlywiki.org|http://tiddlywiki.org/#Filters]]. Note: when the {{{tiddler}}} filter is used, if tiddler with {{{tiddlerName}}} doesn't exist, the filter creates a new empty tiddler and adds it to the set. To avoid problems like blank ~PageTemplate etc, tiddlers which don't exist are not included (or imported) even if the {{{tiddler}}} filter would cause otherwise.

STP introduces 4 new filters:
* {{{all}}} (mostly for inner purposes) which brings all the tiddlers of a store. Usage:
** {{{[all[with included]]}}} fetches ordinary and included tiddlers (with regard to "substituting")
** {{{[all[-]]}}} (with any non-empty argument other than "with included") fetches only ordinary tiddlers (without regard to "substituting")
** Example: {{{[all[-]] [sort[modified]]}}}.
* {{{includedFrom}}} which retains only tiddlers from a certain included store. Examples: {{{[tag[ToDo]] [includedFrom[project.html]], [tag[ToDo]] [includedFrom[node: project]]}}}.
* {{{internal}}} which filters out included tiddlers. Example: {{{[tag[ToDo]] [internal[-]]}}}.
* {{{external}}} which leaves only included tiddlers. Example: {{{[all[with included]] [external[-]]}}}.

Example of usage with the {{{include}}} macro:
{{{
<<include "./biology.html" filters:"[tag[Mammals]] [[Mammals]]">>
}}}

<html><h2>Name conflicts and priorities</h2>
</html>Sometimes there are tiddlers with a common name in the main and an included or multiple included ~TiddlyWikis -- this may occur "accidentally" or because one needs to substitute a tiddler in the main ~TiddlyWiki by an included one (like shared ~PageTemplate). In such cases the following rules work:

* each tiddler in each store has or doesn't have some priorities which is defined when the tiddler is included
* shadowed tiddlers are substituted only by tiddlers with the "substituteShadows" priority
* tiddlers inside the main ~TiddlyWiki substitute those in included ones, unless those have "substitute" priority, in which case it is otherwise
* ({{{sh ambiguity}}}) if there are multiple tiddlers with "substituteShadows" and the shadow presents, there's no specific rule that defines which one would be fetched instead of the shadow; if the shadow with such name doesn't exist, those are treated as included tiddlers without "substituteShadows"
* ({{{s ambiguity}}}) if there are multiple tiddlers with "substitute", the same thing applies: a "random" one is chosen (this actually depends on the order of the handling of {{{<<include>>}}} macros)
* ({{{ambiguity}}}) the same is true for tiddlers included with no added priorities

For tracking conflicts, a notification system is present:

* notifications appear if at least one of these parameters is set to {{{true}}} (see the "tweak" panel in the sidebar):
** {{{chkWarnOnSharedTiddlersConflicts}}} -- displays messages (this is usually interrupted by refreshing engines) and writes them to the browser console
** {{{chkAlertOnSharedTiddlersConflicts}}} -- alerts (in contrast to displaying messages, you won't lose this ones, but you have to click "ok" after each one, so this is to be used when setting up)
* for some reason (probably some page-refreshing called from out of the plugin) notifications are not displayed each time conflicts appear, or are removed too fast (when displaying fails logs and alerts can help)
* notifications are displayed in each case: {{{sh ambiguity}}}, {{{s ambiguity}}}, {{{ambiguity}}} and when there's a tiddler T in the main store and one tiddler with the same name in an included store without the "substitute" priority (in the last two cases the tiddler in the main store is also described as "conflicting" for the ease of understanding what's going on, despite the fact it is fetched for sure, not any included one)
* it is implied that shadows are not added after {{{<<include>>}}} macros are handled (otherwise some notifications will appear as in the {{{ambiguity}}} case while after a shadow is added it can become the {{{sh ambiguity}}})

<html><h2>The "reloadIncluded" macro and reloading</h2>
</html>The {{{reloadIncluded}}} macro creates a "link" which causes reloading of the corresponding ~TWs: the content is unloaded and then previously wikified {{{include}}} macros are handled again. Syntax:
{{{
<<reloadIncluded [urls:urlsJSON] [reloadParams:otherReloadParamsJSON]
		[label:labelText] [tooltip:tooltipText] [class:className]>>
}}}
The {{{label}}} and {{{tooltip}}} parameters are sefl-explaining; {{{class}}} is html class added to the link (it's worth mentioning the {{{button}}} class which is used in macros like {{{tag}}} and {{{slider}}}). The other two parameters should be in the JSON format, like this (note the double quotes, esp. around {{{import}}}):
{{{
urls:'["node: node1", "included test nodes/node 2.html"]' reloadParams:'{"import":false}'
}}}
The {{{urls}}} defines the ~TWs to reload (if not present, means "reload all"). The {{{reloadParams}}} part defines whether to wikify again {{{include}}} macros with the {{{import}}}/{{{wikify}}}/{{{eval}}} params, by default only {{{eval}}} is set to false to avoid repeated evaluation of shared plugins (and in this example {{{import}}} is set to {{{false}}} as well).

<html><h2>The "includeState" macro</h2>
</html>The {{{<<includeState>>}}} macro can be used to see the progress of inclusion of ~TiddlyWikis (e.g. "included" for those already loaded, or a text of an error for others etc). There's a shadow IncludeState where you can see it in work.

<html><h2>Import tools</h2>
</html>As some plugins and other tiddlers should be present inside each TW rather than be "shared" (like [[NestedSlidersPlugin|http://www.TiddlyTools.com/#NestedSlidersPlugin]], without which some content will be "spoiled"), STP provides tools to import/autoimport tiddlers from other ~TiddlyWikis.

{{{<<include>>}}} macro has the following params to support importing in different ways:
* {{{importOnly}}}: when a tiddler with the same title is already present in current TW, import or not? {{{all}}} = always import, {{{newer}}} = import only if the included one is newer than the present one ('modified' dates are compared)
* {{{askBeforeImport}}}: ask per tiddler whether to import (or import silently)? ({{{true}}} or {{{false}}})
* {{{import}}} [mode]: a short notation for the above options, one number to set both:
|{{{askBeforeImport}}} →	|{{{false}}}	 |{{{true}}}	 |
|{{{importOnly = all}}}	| 	1	 | 	3	 |
|{{{importOnly = newer}}}	| 	2	 | 	4	 |
* all params are optional, import is done if at least one of these params is used; default for {{{importOnly}}} is {{{all}}}, for {{{askBeforeImport}}} – {{{false}}}; if specified, {{{importOnly}}} and {{{askBeforeImport}}} overwrite their value defined by import mode
* mode {{{4}}} may be useful for autoupdating plugins from a central TW
The results of import are currently logged only in browser's console.

There are 3 ways to import:
* autoimport via the {{{include}}} macro (with one of the params above, import is done instead of including)
* to import a single included tiddler manually, press "view" in toolbar and then press "import"
* ImportIncluded shadow is a tool for manual batch import (allows to set a filter and import params)
Note: import doesn't cause autosaving, so you may want to save changes afterwards.

An example:
{{{
<<include "./commons/plugins.html" filter:"[tag[commonInPlacePlugins]]" import:4>>
}}}

<html><h2>Evaluating tiddlers</h2>
</html>The {{{eval}}} parameter of the {{{<<include>>}}} macro allows to use plugins included from other ~TWs. For instance,
{{{
<<include "commonPlugins.html" filters:"[[CollapseTiddlersPlugin]] [[RearrangeTiddlersPlugin]]" eval>>
}}}
will load two plugins and evaluate them as ~JavaScript (they can be without {{{systemConfig}}} tag). In current implementation, some differences from the conventional way to launch plugins are present: plugins are not registered (no entries in the backstage), no dedicated reaction on errors; also, there's no check preventing some plugin to launch twice or more. Note: if evaluated, tiddlers still will be included or imported.

<html><h2>"include" macros outside the IncludeList and transitive inclusion</h2>
</html>While {{{<<include>>}}} macros inside the ~IncludeList tiddler are handled at the startup, one can also place them in other tiddlers so that new parts are included when the tiddlers are displayed (the ''hide'' option can be useful here). This can save some time at startup; {{{<<include>>}}} macros outside ~IncludeList also provide the possibility of transitive inclusion (see below). However, sometimes opening a tiddler with an {{{<<include>>}}} macro can take several (mili)seconds.

When ~TiddlyWiki B is included to ~TiddlyWiki A, even if ~IncludeList is included with substitution, this won't bring tiddlers included to B in A, because the startup action is already done (see {{{wikifyIncluded}}} macro, though). However, it's possible to get "transitive inclusion" in the following meaning: add some tiddler with {{{<<include>>}}} in B (for instance, a tiddler "Fruits" with the follwing content:
{{{
All fruits: <<include "./food.html" filters:"[tag[Fruit]]" hide>>
<<tag [[Fruit]]>>
}}}
where "./food.html" is a third ~TiddlyWiki), then if you include this tiddler to A, you will get all the "Fruit"-tagged tiddlers included in A and the tiddler "Fruits" will be displayed as in B (*if* A and B are in the same directory -- otherwise the "./food.html" path will be incorrect in A).

<html><h2>Including remote TiddlyWikis</h2>
</html>Although the documentation of the ~IncludePlugin sais that it's possible to include some remote ~TiddlyWikis into a local one, in modern browsers this seemingly no longer works (tested in IP 1.0.1 and STP 1.3 + Opera 12.0-16.0 and ~FireFox 13.0.1). On the other hand, when running a ~TiddlyWiki on a webserver, one can include ~TWs from the same domain, but can't include any TW from a different website (because of so-called "~Cross-Site Scripting" security issue). @@font-size:smaller;Including remote ~TiddlyWikis into a local one may be reintroduced in the future, but this requires changing the load engine which means some extensive search. Any feedback or ideas regarding this issue are particularly appreciated.@@

<html><h2>Making secondary TiddlyWikis smaller</h2>
</html>In some cases included ~TWs can be supposed not to get changed (like archived pieces of journal or news) and be desired to be smaller (especially when placed at a web-site) at the same time. In such cases included ~TiddlyWikis can be reduced to the [[PureStore|https://yakovl.github.io/TiddlyWiki_SharedTiddlersPlugin/#PureStore]] format.

<html><h2>The TwWeb and the describeNode macro</h2>
</html>The {{{describeNode}}} macro addes a description of a node (a ~TiddlyWiki) to the ~TwWeb. Minimal description consists of the name of the node and its address:
{{{
<<describeNode "nodeName" "path to the node/file.html">>
}}}
Once a node is described, its name can be used instead of its url. This is supported in the {{{include}}} macro:
{{{
<<include "node: nodeName" ...>>
}}}
If such macro is wikified before the node was described, it "waits" for the description to appear. This syntax also can be used in the ImportIncluded.

Also, this is supported in the extended form of prettyLinks:
{{{
[[link text|target tiddler]]@nodeName
}}}
where {{{nodeName}}} contains alphanumeric symbols (latin letters, numbers and {{{_}}} symbols), is equivalent to
{{{
<<include "node: nodeName" filters:"[[target tiddler]]" hide noRefresh>>
[[link text|target tiddler]]
}}}
(except no linebreak is added) and
{{{
[[link text|target tiddler]]@nodeName@param string@
}}}
is equivalent to
{{{
<<include "node: nodeName" filters:"[[target tiddler]]" hide noRefresh param string>>
[[link text|target tiddler]]
}}}
where {{{param string}}} is copied "as is" (to get {{{import:4}}} option of the macro, write param string {{{import:4}}} etc). There's a limitation: {{{param string}}} is only recognized when consists of alphanumeric symbols, space symbols and {{{:}}} (so evaluated parameters are not allowed).

There's another function of the {{{describeNode}}} macro: when used like this
{{{
<<describeNode nodeName self>>
}}}
it sets the name {{{nodeName}}} as the name of the main ~TiddlyWiki. Any including from the node {{{nodeName}}} (which may be caused by an included tiddler) won't work. This only works once meaning that the following markup
{{{
<<describeNode nodeName1 self>>
<<describeNode nodeName2 self>>
}}}
will result in setting {{{nodeName1}}} as the name of the main TW and the second macro will alert about itseft but do nothing else.
----
By ~TwWeb a system that handles all the nodes stuff is meant (not to confuse with ~TiddlyWeb). ~TwWeb is a part of STP.

<html><h2>Propagation</h2>
</html>STP prevents some parts of included tiddlers to get broken because they are in the context of the including TW, not the included one. What currently STP does:

* pretty links without {{{@nodeName}}} in included tiddlers, when displayed, cause including of corresponding tiddlers (so links are not broken). This is another part of the hijacking the "prettyLink" formatter and is optional (see "Installation, configuring and troubleshooting" section)
* image formatter ({{{[img[path][link]]}}} syntax) now takes care of relative links ({{{path}}} part is recalced from the including path). This is also optional, "Installation, configuring and troubleshooting" section.

What is not currently implemented:

* no macros are taken care of -- even a transclusion won't work if the corresponding tiddler is not explicitly included (and, of course, more complex macros like {{{tag}}} or {{{list}}})
* name conflicts are not handled: pretty links just cause including, and if there's a tiddler with the same name inside including TW, the priority system applies (deciding which one will be displayed on click)
* (auto)import doesn't account any of these things, including pretty links

Within these docs, such mechanisms are called "propagation" (of links, images etc).

<html><h2>Inline management of included tiddlers</h2>
</html>In the edit mode an included tiddler has an additional panel to manage it. This is implemented by hijacking the {{{edit}}} macro, no changes to EditTemplate are needed. The panel has {{{manageIncludedPanel}}} that can be used for style settings.

!Installation, configuring and troubleshooting
<html><h2>Installation</h2>
</html>First, put the plugin inside your ~TiddlyWiki. This is done as always: import the SharedTiddlersPlugin tiddler (using ImportTiddlers or another engine) or copy it (don't forget the {{{systemConfig}}} tag). You'll need to restart your ~TiddlyWiki (refresh the page) to get it working -- then you may check if it's installed properly in the PluginManager. You can also import or copy this documentation to have it at hand when needed.

If your TW has version below 2.6.2, you also have to install [[UpToDateFiltersPlugin|https://yakovl.github.io/TiddlyWiki_ExtraFilters/#UpToDateFiltersPlugin]] in the same fashion. Open TW source or use the {{{<<version>>}}} macro to reveal the version of your TW.

Second, add {{{<<include>>}}} macros to IncludeList and wherever you need them. As IncludeList is wikified when you view it, you don't need to restart the "main" ~TiddlyWiki, despite the fact that IncludeList is processed on startup. Add links, transclusions and other "connections" with included tiddlers, if necessary. Search, timeline, {{{<<tag>>}}} and other macros can be used as well.

Now you're ready to go. Remember that included tiddlers are readonly in the "main" ~TiddlyWiki, so you have to go to "original" ~TiddlyWikis to edit them.

<html><h2>Settings</h2>
</html>You may need to change one of these settings:
* <<option chkUseInclude>> {{{chkUseInclude}}} option -- uncheck this and reload your ~TiddlyWiki to stop all inclusions
* <<option chkWarnOnSharedTiddlersConflicts>> {{{chkWarnOnSharedTiddlersConflicts}}} option -- defines whether notifications of conflicts should be displayed and logged
* <<option chkAlertOnSharedTiddlersConflicts>> {{{chkAlertOnSharedTiddlersConflicts}}} option -- defines whether alerting shoud be used for notifying about conflicts
* extending prettyLinks is optional, too; because the hijacking is done at startup, the option is hardcoded: to change it, go to SharedTiddlersPlugin and in the {{{config.options.STP_hijackPrettyLink = true;}}} set {{{false}}} instead
* such is extending of the image formatter ({{{[img[path][link]]}}}): it's governed by the {{{config.options.STP_hijackImageFormatter = ...}}} line in SharedTiddlersPlugin
These along with links to IncludeList, IncludeState and these documentation in the web can be found in AdvancedOptions.

<html><h2>Troubleshooting</h2>
</html>If something goes wrong, you should check:
* core version of your TW: it must be no less than the ~CoreVersion value in the [[SharedTiddlersPlugin]]'s header. You can check it using the {{{<<version>>}}} macro. Also, if [[UpToDateFiltersPlugin|https://yakovl.github.io/TiddlyWiki_ExtraFilters/#UpToDateFiltersPlugin]] is not installed, it must be 2.6.2 or greater
* the PluginManager -- ~SharedTiddlersPlugin should be present there, be not Disabled, have no error log (if all of these is true, than the plugin is installed correctly); also, only one copy of ~SharedTiddlersPlugin or ~IncludePlugin should be installed
* if the plugin is installed correctly, inspect the {{{chkUseInclude}}} option -- should be checked for the plugin to work
* if the problem is not because of {{{chkUseInclude}}}, go to the IncludeState and see if any problems are reported there
** in some browsers there are additional security settings which can forbid loading other ~TWs, see [[Known Problems with Importing in TiddlyWiki|http://classic.tiddlywiki.com/#%5B%5BTiddlyWiki%20Browser%20Compatibility%5D%5D]] section at classic.tiddlywiki.com (it is about importing, but applies to "including" as well). Problems with ~FireFox seem to be solved by either updating to STP v1.5.0+ or TW v2.7.0+
* some browsers forbid including from outside the folder where the including TW is placed. According to tests, addresses containing ".." (container folder) work in Opera (12.15), Safari (5.0.3), IE (10.0) and don't work in ~FireFox (20.0), Chrome (26.0). In ~FireFox, this can be "fixed" by changing a security option: to do this, in the address bar type {{{about:config}}}, press enter, search for the {{{security.fileuri.strict_origin_policy}}} option and set it to {{{false}}} (fortunately, this works even in Android).
If the problem remains, you can search or post your issue in the [[community newsgroup|http://groups.google.com/group/tiddlywiki]] and if it's not solved, you can also notify the maintainer by email (don't forget to add the link to the thread).

!More details on possible applications
In general, ~SharedTiddlersPlugin can help with the following:
* reducing sizes of ~TiddlyWikis which can speed up saving TW and loading from the web, when used as a web-page/site
** examples: old journal/news tiddlers can "archived" into a separate TW monthly so that your diary/blog/site remains approximately the same size but old entries are easily accessible
* using common content in several ~TiddlyWikis
** like some glossary, or help texts about ~TiddlyWiki or some plugins (like ~SharedTiddlersPlugin which has this extensive documentation)
** in this case it's usually easy to avoid name conflicts -- just try to make sure that in the shared document tiddler names are specific enough
* using common interface
** ~PageTemplate, style sheets and other parts of ~TiddlyWiki theme can be shared (don't forget "substitute"/"substituteShadows" priorities, depending on what is present in a document you include those into)
*** all ~PageTemplate, ~StyleSheet, ~ViewTemplate, ~EditTemplate and ~ToolbarCommands are applied as expected; however, it is done by extra refreshing which causes already displayed messages to disappear (on handling of the {{{<<include>>}}} macro)
** included elements can also be used as parts of a custom theme (instead of substituting the default ones); style sheets can be included in the StyleSheet tiddler as well (by adding lines like {{{[[IncludedStyleSheet]]}}} into it)
** evaluated transclusions can be shared as well (and other stuff which is rendered as it shows, like {{{<html>}}}-insertions)
** finally, included plugins can be evaluated (see the "Detailed reference" part of this docs)
*** keep in mind that for some plugins it's more suitable to import them rather than include and evaluate
* aggregating content from other ~TWs
** ~SharedTiddlersPlugin can be used to get all tiddlers with "~ToDo" tag from all ~TiddlyWikis in a separate TW and other things like that
** usually this wouldn't require extra efforts, but if you expect name conflicts and need to get access to all the tiddlers (including different ones with the same name), check "API changes and coding with ~SharedTiddlersPlugin" section for details
** @@font-size:smaller;[currently unavailable, see "Detailed reference" section for details]@@ it's also can be useful to aggregate tiddlers from web (from online ~TiddlyWikis, like http://classic.tiddlywiki.com/index.html), which can bring you news from tiddly world or just from people you know who use ~TiddlyWiki; but remember the cross-site restriction
* finally, ~SharedTiddlersPlugin can be used to "merge" content of several ~TWs
** for instance, if you have a TW dedicated to science you're doing and a TW created for learning (at university or anyhow else), there definitely can appear some topics that belong to both wikis; it's rather weird thing to create new ~TiddlyWikis for each such topic, so you can keep tiddlers in one of them and include them to another for smoother workflow
** however, because included tiddlers are read-only, "default" workflow is not absolutely smooth as you'll need to go to the wiki containing tiddlers "originally" to change them

!API changes and coding with SharedTiddlersPlugin
<html><h2>Accessing stores</h2>
</html>Each included ~TiddlyWiki is represented as a {{{TiddlyWiki}}} object, like the main one is. While for main ~TiddlyWiki it's the global {{{store}}} instance of {{{TiddlyWiki}}}, included ones can be accessed as following:
{{{
  var includedStore = window.sharedTiddlersAPI.getStore(tiddyWikiURL);
}}}
@@font-size:smaller;For backward compability, there's still {{{abego.TiddlyWikiIncluder.getStore(tiddyWikiURL)}}} method which is not recomended to use (see below).@@
Those included stores have only those tiddlers which are included (taking account of the ''filter'' parameters of {{{<<include>>}}} macros). Each of them has an additional property,
{{{
  var fullStore = includedStore.orig_store;
}}}
which is another {{{TiddlyWiki}}} that contains ''all'' the tiddlers of the included TW document.

The list of urls of all included ~TiddlyWikis can be accessed using the
{{{
  window.sharedTiddlersAPI.getIncludes()
}}}
method (it returns an array of strings – urls). Currently, this array contains urls exactly as they were written in {{{<<include>>}}} macros and, for instance, two macros with "example included.html" and "example%20included.html" urls create two different included stores.
@@font-size:smaller;For backward compability, there's also {{{abego.TiddlyWikiIncluder.getIncludes()}}} method which is not recomended to use (see below).@@

To get the state of a {{{store}}} (loaded, or some error occured when loading, etc), the
{{{
  window.sharedTiddlersAPI.getState(tiddyWikiURL)
}}}
method can be used. It returns {{{null}}} when the store is already loaded or a a state/error text otherwise.
@@font-size:smaller;For backward compability, there's also {{{abego.TiddlyWikiIncluder.getState(tiddyWikiURL)}}} method which is not recomended to use (see below).@@

<html><h2>Accessing tiddlers</h2>
</html>As {{{TiddlyWiki}}} instances, both {{{includedStore}}} and {{{fullStore}}} in these examples have corresponding methods, like {{{fetchTiddler}}} etc.

Normally, however, one wouldn't use these direct methods. Instead, there's hijacked
{{{
  store.fetchTiddler(title)
}}}
which fetches a tiddler from the set of "original" and "included" ones taking into account the "substituting". There's also
{{{
  window.sharedTiddlersAPI.forReallyEachTiddler(callback)
}}}
method which does the same thing as {{{store.forEachTiddler}}}, but "iterates" all the tiddlers taking into account the "substituting". Main {{{store}}} methods {{{reverseLookup}}}, {{{updateTiddlers}}}, {{{getTags}}}, {{{getMissingLinks}}}, {{{getOrphans}}} are hijacked in the same way. Finally, already existing functions that use {{{store.forEachTiddler}}} can be modified so that it works as {{{sharedTiddlersAPI.forReallyEachTiddler}}} (see the "Making other plugins "include-aware"" section of these docs).

All original tiddlers from the main store can be accessed via the
{{{
  window.sharedTiddlersAPI.orig_fetchTiddler(title)
}}}
and the original (not hijacked)
{{{
  store.forEachTiddler(callback)
}}}

Notes:
* normally, the {{{window.}}} prefix can be omitted
* methods of {{{abego.TiddlyWikiIncluder}}} are retained so that users of ~IncludePlugin don't need to change their scripts if moving to ~SharedTiddlersPlugin. However, it is recomended that those methods are substituted with those from the {{{sharedTiddlersAPI}}} "namespace".

<html><h2>Included tiddlers</h2>
</html>With SharedTiddlersPlugin, tiddlers get a new property, the url of the store they were included from. It can be got by the {{{getIncludeURL()}}} method of the {{{Tiddler}}} object: it returns the url if the tiddler was included and {{{null}}} otherwise (if it's from the main {{{store}}}).

<html><h2>Importing included tiddlers</h2>
</html>To easily import included tiddlers, the following function can be used:
{{{
window.sharedTiddlersAPI.importAndLog(tiddler, modeOrOptions)
}}}
It strips {{{includeURL}}} from the {{{tiddler}}}, imports it according to the mode/options (in the latter case {{{modeOrOptions.which}}} corresponds to {{{importOnly}}} param of {{{<<include>>}}}, {{{modeOrOptions.ask}}} – to {{{askBeforeImport}}}, also {{{modeOrOptions.mode}}} can be set) and logs the results in the browser console. If {{{modeOrOptions}}} is not passed, it defaults to {{{ { which: 'all', ask: false } }}}; other defaults and precedence are described in "Detailed reference" ("Import tools").

<html><h2>Examples</h2>
</html>(require "demo-included/example included.html" ~TiddlyWiki included):
<html><a href="javascript:;" onclick='
	url = "demo-included/example included.html";
	var twStore = sharedTiddlersAPI.getStore(url);
	if(!twStore) {
		displayMessage("The store is not loaded");
		return;
	}

	displayMessage("Tiddlers:");
	twStore.forEachTiddler(function(title,tiddler) {
		usedTiddler = store.fetchTiddler(title);
		if(usedTiddler.getIncludeURL() == url)
	        	displayMessage("- "+title);
	});
'>Show all tiddlers included from the "demo-included/example included.html" store (with regard to priorities)</a></html>
{{{
<html><a href="javascript:;" onclick='
	url = "demo-included/example included.html";
	var twStore = sharedTiddlersAPI.getStore(url);
	if(!twStore) {
		displayMessage("The store is not loaded");
		return;
	}

	displayMessage("Tiddlers:");
	twStore.forEachTiddler(function(title,tiddler) {
		usedTiddler = store.fetchTiddler(title);
		if(usedTiddler.getIncludeURL() == url)
	        	displayMessage("- "+title);
	});
'>Show all tiddlers included from the "demo-included/example included.html" store (with regard to priorities)</a></html>
}}}

<html><a href="javascript:;" onclick='
	var twStore = sharedTiddlersAPI.getStore("demo-included/example included.html");
	if(!twStore) {
		displayMessage("The store is not loaded");
		return;
	}
	displayMessage("Tiddlers:");
	twStore.forEachTiddler(function(title,tiddler) {
		displayMessage("- "+title);
	});
'>Show all tiddlers included from the "demo-included/example included.html" store, without regard to priorities</a></html>
{{{
<html><a href="javascript:;" onclick='
	var twStore = sharedTiddlersAPI.getStore("demo-included/example included.html");
	if(!twStore) {
		displayMessage("The store is not loaded");
		return;
	}
	displayMessage("Tiddlers:");
	twStore.forEachTiddler(function(title,tiddler) {
		displayMessage("- "+title);
	});
'>Show all tiddlers included from the "demo-included/example included.html" store, without regard to priorities</a></html>
}}}

<html><a href="javascript:;" onclick='
	var includedStore = sharedTiddlersAPI.getStore("demo-included/example included.html");
	if(!includedStore) {
		displayMessage("The store is not loaded");
		return;
	}
	var realStore = includedStore.orig_store;
	var list = [];
	realStore.forEachTiddler(function(title,tiddler) {
		if(tiddler.modified > new Date("July 1, 2007"))
        		list.push(title);
	});
	if(list.length > 0) {
		displayMessage("Tiddlers:");
		for(var i = 0; i < list.length; i++)
			displayMessage("- "+list[i]);
	} else
		displayMessage("No tiddlers changed after July 1st, 2007 were found");
'>Show all tiddlers in the "demo-included/example included.html" store changed after July 1st, 2007</a></html>
{{{
<html><a href="javascript:;" onclick='
	var includedStore = sharedTiddlersAPI.getStore("demo-included/example included.html");
	if(!includedStore) {
		displayMessage("The store is not loaded");
		return;
	}
	var realStore = includedStore.orig_store;
	var list = [];
	realStore.forEachTiddler(function(title,tiddler) {
		if(tiddler.modified > new Date("July 1, 2007"))
        		list.push(title);
	});
	if(list.length > 0) {
		displayMessage("Tiddlers:");
		for(var i = 0; i < list.length; i++)
			displayMessage("- "+list[i]);
	} else
		displayMessage("No tiddlers changed after July 1st, 2007 were found");
'>Show all tiddlers in the "demo-included/example included.html" store changed after July 1st, 2007</a></html>
}}}

<html><a href="javascript:;" onclick='
	displayMessage("Tiddlers:");
	store.forEachTiddler(function(title,tiddler) {
		displayMessage("- "+title);
	});
'>Show all tiddlers in the main store (including substituted ones)</a></html>
{{{
<html><a href="javascript:;" onclick='
	displayMessage("Tiddlers:");
	store.forEachTiddler(function(title,tiddler) {
		displayMessage("- "+title);
	});
'>Show all tiddlers in the main store (including substituted ones)</a></html>
}}}

[[Check an included tiddler|Example of a tiddler in the included tw-document]], <html><a href="javascript:;" onclick='
	var mode = 4,
	    tiddler = store.fetchTiddler("Example of a tiddler in the included tw-document");
	// the tiddler is supposed to be included already
	sharedTiddlersAPI.importAndLog(tiddler, mode);
'>import it</a></html>, then check it again.
{{{
<html><a href="javascript:;" onclick='
	var mode = 4,
	    tiddler = store.fetchTiddler("Example of a tiddler in the included tw-document");
	// the tiddler is supposed to be included already
	sharedTiddlersAPI.importAndLog(tiddler, mode);
'>import it</a></html>
}}}
See also ImportIncluded tiddler for another example of "importing" included tiddlers.

!Making other plugins include-(un)aware
In versions before 2.5.0, ~SharedTiddlersPlugin made some core methods "aware" of included stores while plugins that use {{{store.forEachTiddler}}} directly had to get certain patches to be "aware". ''Since 2.5.0, this is no longer needed'', {{{store.forEachTiddler}}} is changed globally. Old patches won't break anything since

* {{{config.extensions.SharedTiddlersPlugin.getFunctionUsingForReallyEachTiddler(myFunction)}}} now returns {{{myFunction}}} without changes
* {{{config.extensions.SharedTiddlersPlugin.useForReallyEachTiddler(myObject,method)}}} now just returns {{{myObject[method]}}} (doesn't modify anything)

If, for some reason, you need a function behave like there's no included tiddlers/stores (most likely you won't need this), you can apply a patch to implement this.

To understand the implementation, let's note that to make external tiddlers usable, STP basically does 3 things:

* hijackes the {{{fetchTiddler}}} method of the main {{{store}}} object
* hijackes the {{{forEachTiddler}}} method of the main {{{store}}} object
* "recalcs" slices by deleting them

So, you can provide a "context" to a function where the first 2 are undone:
{{{
var orig_myFunction = myFunction;
myFunction = function() {
	// undo changes by STP
	var updated_forEachTiddler = store.forEachTiddler;
	var updated_fetchTiddler = store.fetchTiddler;
	store.forEachTiddler = window.sharedTiddlersAPI.orig_forEachTiddler;
	store.fetchTiddler = window.sharedTiddlersAPI.orig_fetchTiddler;

	var result = orig_myFunction.apply(this,arguments);

	// restore changes by STP
	store.forEachTiddler = updated_forEachTiddler;
	store.fetchTiddler = updated_fetchTiddler;
}
}}}
Recalcing the slices is also possible (you can manipulate {{{store.slices}}} before and after calling {{{orig_myFunction}}}), but is rarely needed.

Finally, the patch will work correctly only if it is used after STP is launched and {{{myFunction}}} is defined, so you have to add it into your plugin after {{{myFunction}}} and add a {{{|Requires|SharedTiddlersPlugin|}}} slice.

!Versions history and quality issues
<html><h2>Version history</h2></html>
* 2.5.0 (1.05.2019)
** improved plugin installation (checks if already installed, shows in PluginManager/sidebar etc)
** removed the necessity of making plugins "include-aware"
** {{{include}}} macro: introduced {{{importOnly}}}, {{{askBeforeImport}}} params; {{{filter}}} param which is the same as {{{filters}}}
** added a button to show link to included tiddler in its origianl location (in the no-edit mode of the tiddler)
** dropped support of TW below 2.7.0, reduced code size using up-to-date helpers
** various fixes (including handling images wrapped into a link like {{{[img[path][link]]}}}, handling prettyLinks to tiddlers with {{{'}}} or {{{"}}} in title from other ~TWs like {{{[[tiddler having "]]@someNode}}}) and refactoring
* 2.4.0 (10.09.2013)
** introduced the {{{reloadIncluded}}} macro
** filters: added {{{external}}}, added {{{node: nodeName}}} syntax support to {{{includedFrom}}}, fixed a bug in {{{includedFrom}}} and {{{internal}}}
** fixed {{{hijackImageFormatter}}} for cases when the image is not inside a tiddler
** some code refactoring, including "internal" interfaces
** some minor quality issues in the conflict notification system are introduced (like doubling messages in rare cases), to be fixed in the next versions
** {{{wikifyIncluded}}} macro is ''completely removed'' (no notifications are now provided)
* 2.3.0 (15.06.2013)
** implemented new modes of import (2, 3)
** ImportIncluded now supports modes, "node: nodeName" syntax and got several fixes
** propagation of including is introduced for pretty links and images
** managing included tiddlers panel got the "import" button (link)
* 2.2.0 (30.05.2013)
** implemented the {{{<<describeNode nodeName self>>}}} syntax and ban of including from the node marked self
** added a panel for managing inluded tiddlers inside their edit mode (now contains a link to the tiddler in its "source" ~TiddlyWiki)
* 2.1.0 (13.05.2013)
** introduced the support of {{{[[text|tiddler]]@node}}} links
** removed functionality from the {{{wikifyIncluded}}} macro (only a notification remains)
** extended the {{{all}}} filter so that {{{[all[with included]]}}} filter brings all tiddlers accounting included ones
** fixed 'a.fetchTiddler is not a function' bug which appeared in FF, in TW 2.6.5, when a TW from outside the current folder (../some path) was tried to include (now {{{.getStore}}} method works correctly in such cases as well)
* 2.0.0 (1.05.2013)
** introduced ~TwWeb, {{{describeNode}}} macro, added support of node names to the {{{include}}} macro
** added {{{wikify}}} parameter to the {{{include}}} macro; deprecated {{{wikifyIncluded}}} macro and added a notification that pops when it is used
** some minor fixes and improvements
** major documentation update, added simplified "Functionality and examples" section, changed the structure of sections
* the 2.x.x series are dedicated to content managing and interaction, to ~TwWeb
* 1.6.1 (8.03.2013)
** added {{{noRefresh}}} parameter to the {{{include}}} macro
** added {{{internal}}} filter
** fixed a bug preventing ImportIncluded engine to work
** documentation improvements, added description of the {{{window.sharedTiddlersAPI.importAndLog(tiddler,mode)}}} method
* 1.6.0 (13.02.2013)
** added evaluation of tiddlers via the {{{include}}} macro with the new {{{eval}}} parameter
** added filters {{{all}}} and {{{includedFrom}}}; now in TW 2.6.1 or elder STP requires [[UpToDateFiltersPlugin|https://yakovl.github.io/TiddlyWiki_ExtraFilters/#UpToDateFiltersPlugin]]
** {{{allTiddlersAreLoaded}}} parameter is no longer added to stores, no need to check it (but old {{{if(allTiddlersAreLoaded)}}} code pieces to get all tiddlers should work)
** {{{hide}}} parameter of the {{{include}}} macro now can be used without trailing {{{:true}}}
** some fixes and code improvements, better API documentation
* 1.5.0 (11.01.2013)
** solved problems in ~FireFox, now including works in TW 2.6.0
** added autoimport via the {{{include}}} macro
** added import modes and setting the {{{store}}} as {{{dirty}}} on import
** added "protection" from including non-existing tiddlers (caused by the {{{tiddler}}} filter)
** some fixes, code improvments
* 1.4.4 (6.12.2012)
** slices are now "recalced", substituted ~ToolbarCommands is now applied as expected
** the {{{include}}} macro is now launched only once (per session) with each used exact "wording", so no loop because of refreshing is now possible
** substituted ~ViewTemplate is now refreshed on including
** {{{wikifyIncluded}}} now doesn't make infinite loops, control parameters are added
** making some abego plugins "include-aware" is removed from the code; howTo make any plugin "include-aware" is added to docs
** some minor fixes/enhancements, documentation improvments, added minified version of the plugin
* 1.4.3 (21.11.2012)
** alerting on conflicts controled by {{{chkAlertOnSharedTiddlersConflicts}}} parameter is introduced
** many improvments of code and update of documentation (including corrections in the "Name conflicts and priorities" section) are done
* 1.4.2 (wasn't published)
** introduced the {{{wikifyIncluded}}} macro
** introduced the "importing" engine (ImportIncluded)
* 1.4.1 (wasn't published)
** included ~PageTemplate is now applied
** the issue with the "orphans" list is fixed, the issue with the "missing" list is partially fixed
** {{{window.sharedTiddlersAPI.orig_forEachTiddler}}} is removed as the {{{store.forEachTiddler}}} is not actually hijacked
** documentation is updated
* 1.4.0 (29.09.2012)
** removed the {{{abego}}} namespace where possible, added {{{window.sharedTiddlersAPI}}} object and moved all (but some deprecated) API there, reduced the scope of some internal functions
* 1.3.0 (wasn't published)
** notifications of conflicts were added
** theme is refreshed when an inclusion is done so that included style sheets and templates are applied right away
* 1.2.0 (wasn't published)
** substitute and substituteShadows possibilities were added
* 1.1.0 (wasn't published)
** filtering was added
* forked from [[IncludePlugin|http://tiddlywiki.abego-software.de/#IncludePlugin]] v1.0.1, by Udo Borkowski
<html><h2>Current quality issues</h2></html>
* some tiddlers in the main store, referenced in included tiddlers, appear in the "missing" list
!%/<<tiddler {{setStylesheet('div[tiddler="SharedTiddlersPluginInfo"] .tabContents { background-color:'+store.getTiddlerText('ColorPalette::Background')+'; }', 'STPInfoCSS');'';}}>>
<<search>><<closeAll>><<permaview>><<slider chkSliderOptionsPanel SideBarOptions##OptionsPanel "options »" "Change TiddlyWiki advanced options">>/%
!OptionsPanel
<<option chkRegExpSearch>> [[RegExpSearch]]
<<option chkCaseSensitiveSearch>> [[CaseSensitiveSearch]]
<<option chkAnimate>> [[EnableAnimations]]
----
Also see [[AdvancedOptions]]
!%/
/***
|Description|Makes upgrading work ~correctly with (at least) Timimi or MTS 1.7.0 and above (tested on 2.6.5,2.9.2,2.9.3 → 2.9.3,2.9.4), adds optional upgrade autocheck on start; adds tiddlers and fields sorting so that the changes are easier to review|
|Source     |https://github.com/YakovL/TiddlyWiki_SimplifiedUpgradingPlugin/blob/master/SimplifiedUpgradingPlugin.js|
|Author     |Yakov Litvin|
|Version    |0.6.0|
|License    |[[MIT|https://github.com/YakovL/TiddlyWiki_YL_ExtensionsCollection/blob/master/Common%20License%20(MIT)]]|
Installation of this plugin is standard: create tiddler, paste this as text, tag with {{{systemConfig}}}, save, reload.

To start upgrading, use the usual way: open backstage, the "upgrade" tab and hit the "upgrade" button.

Configuration:
<<option txtWaitSavingSeconds>> "wait saving" interval (seconds) may need adjustments for big ~TWs (otherwise, you should check that after reloading the new version is opened: if not, try to reload again)
<<option chkReloadManually>> reload manually (don't reload automatically after saving upgraded TW)
<<option chkAutocheckUpgradeOnStart>> check for upgrades on start
***/
//{{{
config.options.txtWaitSavingSeconds = config.options.txtWaitSavingSeconds || "5"; // no handler for number options

// a fix for older TWs, like 2.7.1
if(config.macros.upgrade.source == 'http://tiddlywiki-releases.tiddlyspace.com/upgrade')
	config.macros.upgrade.source = 'https://classic.tiddlywiki.com/upgrade/'

var upgradingEventBus = {
	handlers: {},
	// no "off" method, no array of handlers for now
	on: function(name, handler) {
		this.handlers[name] = handler
	},
	fire: function(name, params) {
		if(this.handlers[name]) this.handlers[name](params)
	}
}

config.macros.simplifiedUpgrade = {
	lingo: {
		isBackupCreatedQuestion: "Have you made a backup?",
		makeBackupCall: "Please make sure you have a backup before upgrading",
		unsupportedMtsVersionMessage: "Simplified upgrading in MainTiddlySaver below 1.7.0 is not made to work properly, aborting now",
		failedToLoadCore: "Something went wrong when loading core!",
		simplifiedUpgradingDissallowed: "The new core indicates that simplified upgrading is dangerous, please use import of your TW into a new empty TW instead",
		versionNotNewer: "The available core is not newer than the current one",
		getUpgradeFinishedReloadMessage: function() {
			return "Upgrading finished, " + (config.options.chkReloadManually ?
				"reload page to have the changes applied" :
				"will reload page to have the changes applied")
		},
		upgradeMacro: {
			statusUpgrading: "building upgraded TW and saving...",
			statusUpgradedTwSaved: "upgraded TW saved, should reload now",
			getUpgradeAvailableMessage: function(version) {
				return "An upgrade to TiddlyWiki v" + formatVersion(version) + " is available"
			}
		}
	},
	start: function(newCoreString) {
		// don't upgrade without a backup
		if(!confirm(this.lingo.isBackupCreatedQuestion)) {
			alert(this.lingo.makeBackupCall)
			return
		}

		// once MTS supports upgrading, here we will check MTS version instead [or feature-detect]
		var isMainTiddlyServerUsed = !!window.saveOnlineChanges ||
			(window.tiddlyBackend && tiddlyBackend.version && tiddlyBackend.version.title == 'MainTiddlyServer')
		if(isMainTiddlyServerUsed) {
			// for now, we assume that 1.7.0 supports upgrading (this is a matter of testing), so we don't check tiddlyBackend.version.asString
			var doesMtsSupportUpgrading = !!window.tiddlyBackend
			if(!doesMtsSupportUpgrading) {
				alert(this.lingo.unsupportedMtsVersionMessage)
				return
			}
		}

		var me = this
		if(newCoreString) {
			this.proceedWithLoadedCore(newCoreString)
		}
		else this.getNewCore(function(newCoreString) {
			upgradingEventBus.fire("available-core-loaded")
			me.proceedWithLoadedCore(newCoreString)
		}, this.onCoreLoadFail)
	},
	// onSuccess(newCoreString), onProblem(jqXHR, textStatus, errorThrown)
	getNewCore: function(onSuccess, onProblem) {
		var up = config.macros.upgrade
		var url = up.getSourceURL ? up.getSourceURL() : config.options.txtUpgradeCoreURI || up.source
		ajaxReq({
			type: "GET",
			url: url,
			processData: false,
			success: onSuccess,
			error: onProblem
		})
	},
	onCoreLoadFail: function(jqXHR, textStatus, errorThrown) {
		upgradingEventBus.fire("available-core-loading-failed")
		alert(config.macros.simplifiedUpgrade.lingo.failedToLoadCore)
	},
	getSavingWaitMillisecondsInterval: function() {
		return 1000 * parseFloat(config.options.txtWaitSavingSeconds)
	},
	overrides: {},
	// main idea: make sure loadOriginal or its async analogs will return the new core, then just save
	proceedWithLoadedCore: function(newCoreString) {
		var me = config.macros.simplifiedUpgrade
		if(newCoreString.indexOf("simplifiedUpgradingDisallowed") != -1) {
			alert(me.lingo.simplifiedUpgradingDissallowed)
			return
		}
		var availableVersion = config.macros.upgrade.extractVersion(newCoreString)
		if(compareVersions(version, availableVersion) !== 1) {
			displayMessage(me.lingo.versionNotNewer)
			return
		}

		// MainTiddlyServer: avoid granulated saving (won't change core)
		me.overrides.chkAvoidGranulatedSaving = config.options.chkAvoidGranulatedSaving
		config.options.chkAvoidGranulatedSaving = true

		me.overrides.loadOriginal = loadOriginal
		loadOriginal = function loadOriginal(localPath, callback) {
			if(!callback) return newCoreString
			callback(newCoreString)
		}
		// MTS 1.7.0
		if(window.tiddlyBackend) {
			me.overrides.tiddlyBackend_loadOriginal = tiddlyBackend.loadOriginal
			tiddlyBackend.loadOriginal = function(onSuccess) {
				onSuccess(newCoreString)
			}
		}

		saveChanges()
		// restore overrides
		loadOriginal = me.overrides.loadOriginal
		if(me.overrides.tiddlyBackend_loadOriginal) tiddlyBackend.loadOriginal = me.overrides.tiddlyBackend_loadOriginal
		config.options.chkAvoidGranulatedSaving = me.overrides.chkAvoidGranulatedSaving

		// wait so that saving finishes
		setTimeout(function() {
			upgradingEventBus.fire("upgraded-tw-saved")
			me.finalize()
		}, me.getSavingWaitMillisecondsInterval())
	},
	finalize: function() {
		var me = config.macros.simplifiedUpgrade
		alert(me.lingo.getUpgradeFinishedReloadMessage())
		if(!config.options.chkReloadManually) {
			window.location.reload()
		}
	}
}

merge(config.macros.upgrade, config.macros.simplifiedUpgrade.lingo.upgradeMacro)

config.macros.upgrade.onLoadCore = function(status, params, responseText, url, xhr) {

	var me = config.macros.upgrade
	var w = params
	var errMsg = !status ? me.errorLoadingCore : undefined
	var newVer = me.extractVersion(responseText)
	if(!newVer) errMsg = me.errorCoreFormat
	if(errMsg) {
		w.setButtons([], errMsg)
		alert(errMsg)
		return
	}

	// the overridden bit
	var onStartUpgrade = function(e) {
		w.setButtons([], me.statusUpgrading)
		upgradingEventBus.on("upgraded-tw-saved", function() {
			w.setButtons([], me.statusUpgradedTwSaved)
		})
		config.macros.simplifiedUpgrade.start(responseText)
	}

	var step2 = [me.step2Html_downgrade, me.step2Html_restore, me.step2Html_upgrade][compareVersions(version, newVer) + 1];
	w.addStep(me.step2Title, step2.format([formatVersion(newVer), formatVersion(version)]));
	w.setButtons([
		{ caption: me.startLabel, tooltip: me.startPrompt, onClick: onStartUpgrade },
		{ caption: me.cancelLabel, tooltip: me.cancelPrompt, onClick: me.onCancel }
	])
}

var isBelow2_9_3 = compareVersions(version, { major: 2, minor: 9, revision: 3 }) === 1
var isAbove2_9_3 = compareVersions(version, { major: 2, minor: 9, revision: 3 }) === -1

// support upgrading regardless the whitespace after '{' (extra spaces were in 2.9._)
if(isBelow2_9_3) {
	config.macros.upgrade.extractVersion = function(upgradeFile) {
		var re = /version = \{\s*title: "([^"]+)", major: (\d+), minor: (\d+), revision: (\d+)(, beta: (\d+)){0,1}, date: new Date\("([^"]+)"\)/mg
		var m = re.exec(upgradeFile)
		return !m ? null : {
			title: m[1], major: m[2], minor: m[3], revision: m[4], beta: m[6], date: new Date(m[7])
		}
	}
}

// fix the bug introduced in 2.9.3 and fixed in 2.9.4 version
if(!isAbove2_9_3) {
	// not present before 2.9.2
	config.macros.upgrade.getSourceURL = function() {
		return config.options.txtUpgradeCoreURI || config.macros.upgrade.source
	}

	config.macros.upgrade.onClickUpgrade = function(e)
	{
		var me = config.macros.upgrade
		var w = new Wizard(this)
		if(window.allowSave && !window.allowSave()) {
			alert(me.errorCantUpgrade)
			return false
		}
		if(story.areAnyDirty() || store.isDirty()) {
			alert(me.errorNotSaved)
			return false
		}

		w.setButtons([], me.statusPreparingBackup)
		var localPath = getLocalPath(document.location.toString())
		var backupPath = getBackupPath(localPath, me.backupExtension)
		var original = loadOriginal(localPath)

		w.setButtons([], me.statusSavingBackup)
		var backupSuccess = copyFile(backupPath, localPath) || saveFile(backupPath, original)
		//# fails of backup saving with TF are not reported, resulting in empty TW after upgrade
		if(!backupSuccess) {
			w.setButtons([], me.errorSavingBackup)
			alert(me.errorSavingBackup)
			return false
		}
		w.setValue("backupPath", backupPath)

		w.setButtons([], me.statusLoadingCore)
		var sourceURL = me.getSourceURL()
		ajaxReq({
			type: "GET",
			url: sourceURL,
			processData: false,
			success: function(data, textStatus, jqXHR) {
				me.onLoadCore(true, w, jqXHR.responseText, sourceURL, jqXHR)
			},
			error: function(jqXHR, textStatus, errorThrown) {
				me.onLoadCore(false, w, null, sourceURL, jqXHR)
			}
		})
		return false
	}
}

// auto-checking available upgrade
config.macros.upgrade.init = function() {
	config.macros.simplifiedUpgrade.getNewCore(function(coreAsText) {
		var me = config.macros.upgrade
		var availableVersion = me.extractVersion(coreAsText)
		if(compareVersions(version, availableVersion) !== 1) return
		if(config.options.chkAutocheckUpgradeOnStart) {
			displayMessage(me.getUpgradeAvailableMessage(availableVersion))
		}
	})
}

if(!isAbove2_9_3) {
	SaverBase.prototype.externalize = function(store) {
		var results = [];
		var i, tiddlers = store.getTiddlers("title");
		if(!config.options.chkAvoidSortingAll) {
			tiddlers.sort(function(t1, t2) {
				return t1.title.localeCompare(t2.title)
			});
		}
		for(i = 0; i < tiddlers.length; i++) {
			if(!tiddlers[i].doNotSave())
				results.push(this.externalizeTiddler(store, tiddlers[i]));
		}
		return results.join("\n");
	};

	TW21Saver.prototype.externalizeTiddler = function(store, tiddler)
	{
		try {
			var usePre = config.options.chkUsePreForStorage;
			var created = tiddler.created;
			var modified = tiddler.modified;
			var tags = tiddler.getTags();
			var attributes =
				(tiddler.creator ? ' creator="' + tiddler.creator.htmlEncode() + '"' : "") +
				(tiddler.modifier ? ' modifier="' + tiddler.modifier.htmlEncode() + '"' : "") +
				((usePre && created == version.date) ? "" : ' created="' + created.convertToYYYYMMDDHHMM() + '"') +
				((usePre && modified == created) ? "" : ' modified="' + modified.convertToYYYYMMDDHHMM() + '"') +
				((!usePre || tags) ? ' tags="' + tags.htmlEncode() + '"' : "");
			//# todo: check if these changes (sort extended attributes so that the order is always the same) affect performance, commit
			var extendedAttributes = [];
			store.forEachField(tiddler, function(tiddler, fieldName, value) {
				if(typeof value != "string")
					value = "";
				// don't store fields from the temp namespace
				if(!fieldName.match(/^temp\./))
					extendedAttributes.push('%0="%1"'.format([fieldName, value.escapeLineBreaks().htmlEncode()]));
			}, true);
			if(!config.options.chkAvoidSortingAll) {
				extendedAttributes.sort();
			}
			//# avoid closing div tags for _
			return ('<div %0="%1"%2%3>%4</' + 'div>').format([
				usePre ? "title" : "tiddler",
				tiddler.title.htmlEncode(),
				attributes,
				' ' + extendedAttributes.join(' '),
				usePre ? "\n<pre>" + tiddler.text.htmlEncode() + "</pre>\n" : tiddler.text.escapeLineBreaks().htmlEncode()
			]);
		} catch (ex) {
			throw exceptionText(ex, config.messages.tiddlerSaveError.format([tiddler.title]));
		}
	};
}
//}}}
a tool for sharing tiddlers between ~TiddlyWikis
~SharedTiddlersPlugin
/*{{{*/
.viewer		{ margin: 0% 0% 15% 0%; }	/* separate tiddlers with some space;
						   also, this space allows to scroll page so that the bottom
						   thing would be on the level of eyes the of the reader */
table.tcenter	{ margin : 0 auto; }

/* make font monospace in the editor mode for tiddlers with code (CSS, JavaScript etc) */
div[tags~="code"]				/* usage: add tag "code" to the tiddler */
.editor		{ font-family: monospace; }
/*}}}*/
|~ViewToolbar|closeTiddler closeOthers +editTiddler  permalink jump > fields references deleteTiddler|
|~EditToolbar|+saveTiddler -cancelTiddler references deleteTiddler|
<<include "http://classic.tiddlywiki.com/index.html">>
"""<<include "http://tiddlywiki.abego-software.de/index.html">>"""

Можно ли включать содержимое удалённых tw-документов с помощью STP?
* Ситуация такая: вообще говоря, нет -- из-за проблем безопасности ([[Cross-Site Scripting|http://en.wikipedia.org/wiki/Cross-Site_Scripting]]); чтобы было можно, {{DDnc{нужно настраивать CORS, но и это не панацея}}}
* В документации написано, что не включаются "некоторые", в т.ч. если используемая TW находится на сайте (т.е. к ней обращаются по http/https), то нельзя включать tw-документы с других сайтов, но можно включать tw-страницы с других сайтов в локальном tw-документе или со своего сайта -- на своём же сайте.
* {{DDn{На практике не удалось включить ни одного удалённого tw-документа}}}. Пробовал:{{justDiv{
{{{ <<include "http://www.remotely-helpful.com/TiddlyWiki/TiddlerEncryptionPlugin.html">> }}} -- про него выдаётся сообщение, что всё не так
{{{ <<include "http://visualtw.ouvaton.org/VisualTW.html>> }}} -- сообщение не появляется
{{{ <<include "http://tiddlier.narod.ru/index.html">> }}} -- снова пишут сообщение об ошибке}}}
Yakov Litvin Public Licence Version 0.3
----
Copyright (c) 2013, Yakov Litvin

This software includes work of abego Software distributed under <<slider "" [[Yakov Litvin Public Licence##abego licence]] "the following license" "">>/%
!abego licence
{{{
abego Public Licence Version 1.0

Copyright (c) 2006, abego Software GmbH (http://www.abego-software.de)

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this
  list of conditions and the following disclaimer.

* Redistributions in binary form must reproduce the above copyright notice, this
  list of conditions and the following disclaimer in the documentation and/or other
  materials provided with the distribution.

* Neither the name of abego Software nor the names of its contributors may be
  used to endorse or promote products derived from this software without specific
  prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
}}}
!%/

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.