Sky of flatfish


Requires Javascript.
比目魚的天空 - 讓人藍藍的 AD !!! - flatfish@2008         powered by TWtBala - TiddlyWiki 2.3.0
<!--{{{-->
<link rel='alternate' type='application/rss+xml' title='RSS' href='index.xml'/>
<!--}}}-->
Background: #fff
Foreground: #000
PrimaryPale: #8cf
PrimaryLight: #18f
PrimaryMid: #04b
PrimaryDark: #014
SecondaryPale: #ffc
SecondaryLight: #fe8
SecondaryMid: #db4
SecondaryDark: #841
TertiaryPale: #eee
TertiaryLight: #ccc
TertiaryMid: #999
TertiaryDark: #666
Error: #f88
/*{{{*/
body {background:[[ColorPalette::Background]]; color:[[ColorPalette::Foreground]];}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

hr {height:1px;}

a {text-decoration:none;}

dt {font-weight:bold;}

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

.txtOptionInput {width:11em;}

#contentWrapper .chkOptionInput {border:0;}

.externalLink {text-decoration:underline;}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

.whenBackstage {display:none;}
.backstageVisible .whenBackstage {display:block;}
/*}}}*/
/***
StyleSheet for use when a translation requires any css style changes.
This StyleSheet can be used directly by languages such as Chinese, Japanese and Korean which need larger font sizes.
***/
/*{{{*/
body {font-size:0.8em;}
#sidebarOptions {font-size:1.05em;}
#sidebarOptions a {font-style:normal;}
#sidebarOptions .sliderPanel {font-size:0.95em;}
.subtitle {font-size:0.8em;}
.viewer table.listView {font-size:0.95em;}
/*}}}*/
/*{{{*/
@media print {
#mainMenu, #sidebar, #messageArea, .toolbar, #backstageButton, #backstageArea {display: none ! important;}
#displayArea {margin: 1em 1em 0em 1em;}
/* Fixes a feature in Firefox 1.5.0.2 where print preview displays the noscript content */
noscript {display:none;}
}
/*}}}*/
<!--{{{-->
<div class='header' macro='gradient vert [[ColorPalette::PrimaryLight]] [[ColorPalette::PrimaryMid]]'>
<div class='headerShadow'>
<span class='siteTitle' refresh='content' tiddler='SiteTitle'></span>&nbsp;
<span class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'></span>
</div>
<div class='headerForeground'>
<span class='siteTitle' refresh='content' tiddler='SiteTitle'></span>&nbsp;
<span class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'></span>
</div>
</div>
<div id='mainMenu' refresh='content' tiddler='MainMenu'></div>
<div id='sidebar'>
<div id='sidebarOptions' refresh='content' tiddler='SideBarOptions'></div>
<div id='sidebarTabs' refresh='content' force='true' tiddler='SideBarTabs'></div>
</div>
<div id='displayArea'>
<div id='messageArea'></div>
<div id='tiddlerDisplay'></div>
</div>
<!--}}}-->
<!--{{{-->
<div class='toolbar' macro='toolbar closeTiddler closeOthers +editTiddler > fields syncing permalink references jump'></div>
<div class='title' macro='view title'></div>
<div class='subtitle'><span macro='view modifier link'></span>, <span macro='view modified date'></span> (<span macro='message views.wikified.createdPrompt'></span> <span macro='view created date'></span>)</div>
<div class='tagging' macro='tagging'></div>
<div class='tagged' macro='tags'></div>
<div class='viewer' macro='view text wikified'></div>
<div class='tagClear'></div>
<!--}}}-->
<!--{{{-->
<div class='toolbar' macro='toolbar +saveTiddler -cancelTiddler deleteTiddler'></div>
<div class='title' macro='view title'></div>
<div class='editor' macro='edit title'></div>
<div macro='annotations'></div>
<div class='editor' macro='edit text'></div>
<div class='editor' macro='edit tags'></div><div class='editorFooter'><span macro='message views.editor.tagPrompt'></span><span macro='tagChooser'></span></div>
<!--}}}-->
To get started with this blank TiddlyWiki, you'll need to modify the following tiddlers:
* SiteTitle & SiteSubtitle: The title and subtitle of the site, as shown above (after saving, they will also appear in the browser title bar)
* MainMenu: The menu (usually on the left)
* DefaultTiddlers: Contains the names of the tiddlers that you want to appear when the TiddlyWiki is opened
You'll also need to enter your username for signing your edits: <<option txtUserName>>
These InterfaceOptions for customising TiddlyWiki are saved in your browser

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

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

----
Also see AdvancedOptions
<<importTiddlers>>
Revision 3497
<<toBalaManager>>



























































///%

比目魚的天空 - 讓人藍藍的 AD !!!

''flatfish''@2008 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;powered by TWtBala - TiddlyWiki 2.3.0

<<tagsTree domain "" 2 4 index label>>
<<tagsTree 2279 "" 2 4 index label>>
<<tagsTree supplement "" 1 4 index label>>
<<tagsTree twcms "" 1 4 index label>>
<<tagsTree KMKConfig "" 1 4 index label>>
<<tabs txtMainTab "最近更新" "依更新日期排序" SideBarTabs/Timeline "分類" "所有標籤" TabTags "設定文章" "說所有設定文章" TabMoreShadowed>>

<<search>> | [[首頁]] | [[土芭樂 3.0 - 數位新思路|http://tbala.net/]]  | [[TiddlyWiki 練功坊|http://tiddlywiki.tbala.net/]] | [[匯入文章]]  | <<newTiddler label:"新增文章">>  <<saveChanges>> 
//%/
<<list shadowed>>
<<forEachTiddler
    script '
        window.fetItemsPerPage = 15;

        function getHeader(context,count) {
            if (!window.fetStartIndex || window.fetStartIndex < 0) 
                window.fetStartIndex = 0;

            // ensure not to page behind the last page
            if (window.fetStartIndex >= count)
                window.fetStartIndex = Math.min(Math.max(window.fetStartIndex-window.fetItemsPerPage,0),count-1);

            createTiddlyButton(context.place,"<",null,
                    function(e) {
                        window.fetStartIndex -= window.fetItemsPerPage;
                        story.refreshTiddler(context.viewerTiddler.title,null,true);
                    });
            createTiddlyButton(context.place,">",null,
                    function(e) {
                        window.fetStartIndex += window.fetItemsPerPage;
                        story.refreshTiddler(context.viewerTiddler.title,null,true);
                    });

            var startNo = window.fetStartIndex+1;
            var endNo = Math.min(count,window.fetStartIndex+window.fetItemsPerPage);

            return "("+startNo+" - "+endNo+ " of "+ count + " items)\n";
        }
    '

    write
            '(index >= window.fetStartIndex) && (index < window.fetStartIndex + 20) ? "* [["+tiddler.title+"]]\n" : ""'

        begin
            'getHeader(context,count)'
>>

// /%
With a little scripting you can use the ~ForEachTiddlerPlugin to display the result "by pages". I.e. you don't display the full result list, but (e.g.) 10 at a time. 
Using a "pagewise" display may be useful when the result may get very large. This way you avoid scrolling the window to see the result. It also speeds up things since less items need to be display at a time.

''Code''
{{{
<<forEachTiddler
    script '
        window.fetItemsPerPage = 10;

        function getHeader(context,count) {
            if (!window.fetStartIndex || window.fetStartIndex < 0) 
                window.fetStartIndex = 0;

            // ensure not to page behind the last page
            if (window.fetStartIndex >= count)
                window.fetStartIndex = Math.min(Math.max(window.fetStartIndex-window.fetItemsPerPage,0),count-1);

            createTiddlyButton(context.place,"<",null,
                    function(e) {
                        window.fetStartIndex -= window.fetItemsPerPage;
                        story.refreshTiddler(context.viewerTiddler.title,null,true);
                    });
            createTiddlyButton(context.place,">",null,
                    function(e) {
                        window.fetStartIndex += window.fetItemsPerPage;
                        story.refreshTiddler(context.viewerTiddler.title,null,true);
                    });

            var startNo = window.fetStartIndex+1;
            var endNo = Math.min(count,window.fetStartIndex+window.fetItemsPerPage);

            return "("+startNo+" - "+endNo+ " of "+ count + " items)\n";
        }
    '

    write
            '(index >= window.fetStartIndex) && (index < window.fetStartIndex + 10) ? "* [["+tiddler.title+"]]\n" : ""'

        begin
            'getHeader(context,count)'
>>
}}}
// %/
<<forEachTiddler 
 where
   'tiddler.tags.contains("plugin")'
>>
<<timeline>>
<<forEachTiddler 
 where
   'tiddler.tags.contains("macro")'
>>
<<forEachTiddler 
 where
 'tiddler.tags.length == 0'
>>
*支援指令檔:登出/登入、開機/關機
*支援檔案類型:bat、cmd、vbs、js
#撰寫指令檔
#透過群組原則編輯器中的指定碼,點選『顯示檔案』開啟要放置指令碼的資料夾,將撰寫好的指令檔拖放至開啟的資料夾內
#點選『新增』加入複製的指令檔

{{item1{__GPO 中加入指令碼__}}}  <<toBalaFlashPlayer "flash/10.1-GPO_script.swf" "有影片有真相" "800" "620">> 
*參考羅老師課本 11 章

!軟體管過程
 1. Preparation 準備  <<toBalaFlashPlayer "flash/10.2-software_preparation.swf" "有影片有真相" "800" "620">> 
**必須取得微軟視窗安裝格式檔案 (.MSI) ,在將檔案複製到軟體分送點 (File server)
**軟體發佈點要求:share 有讀取與執行的權限,但不能有寫入及其他權限
 2. Deployment 調配 (軟體佈署)  <<toBalaFlashPlayer "flash/10.2-software_deployment.swf" "有影片有真相" "800" "620">> 
**管理員創造一個安裝軟體的群組原則物件,並將此 GPO 連結至 Container object
**選擇佈署方式
***發行 (Publish method):軟體將為可用狀態(become available),使用者可依據需求自行決定要不要裝,因此沒有強制性
****僅能針對使用者為對象,不能針對電腦
***指派 (Assign method):軟體將為總是可用狀態(always available),具備強制性,但事實上還沒有真正安裝,只有在使用者第一次點擊的時候才會真正安裝
****可針對電腦或是使用者
****當指派給電腦時,必須經過完整測試,若 MSI 打包有問題,使用者將會看不到登入輸入帳號的畫面,因電腦必須要在軟體安裝完成才能登入
||發行給使用者|指派給使用者|指派給電腦|
|使用者登入後如何安裝|1.透過新增移除程式<br>2.開啟軟體關聯文件(Document Activation)|1.按下開始功能表內的捷徑、桌面上的捷徑<br>2.新增移除程式<br>3.開啟軟體關聯文件(Document Activation)|軟體直接安裝|
|使用者是否可以移除|可透過新增移除程式移除|可,但捷徑仍然存在,使用者可以按捷徑再次安裝|否,只有本機管理員可以移除|
{{item1{__經過 GPO 軟體佈署的用戶端電腦__}}}  <<toBalaFlashPlayer "flash/10.2-software_after_deployment.swf" "有影片有真相" "800" "620">> 
 3. Maintain 維護
**軟體升級 (Upgrade)
***強制升級 (Mandatory Upgrade):拿到新版的 MSI 檔,下次登入時舊版將不能使用,需到新增移除程式自行安裝新版  <<toBalaFlashPlayer "flash/10.2-software_mandatory_upgrade.swf" "有影片有真相" "800" "620">> 
***選擇升級 (Optional Upgrade):使用者可自行決定使用新版或是舊版
**重新佈署 (Redeployment):適合用在安裝 Service Pack,將新的 service pack 取代既有的軟體發佈點內的封裝檔  <<toBalaFlashPlayer "flash/10.2-software_redeployment.swf" "有影片有真相" "800" "620">>
**修復 (Repair):需原始 MSI 檔提供修復功能  <<toBalaFlashPlayer "flash/10.2-software_repair.swf" "有影片有真相" "800" "620">> 
***比對已安裝程式與原始 MSI 檔是否有不同,若沒有問題則會重新安裝一次,一般使用者即可使用的功能
 4. Remove 移除 <<toBalaFlashPlayer "flash/10.2-software_remove.swf" "有影片有真相" "800" "620">> 
**立即解除使用者及電腦軟體的安裝
**允許使用者繼續使用軟體,但避免新的安裝

!建立軟體類別(Optional)
*在公司內安裝的軟體眾多時,建議建立軟體類別,以提供使用者尋找 <<toBalaFlashPlayer "flash/10.2-software_create_class.swf" "有影片有真相" "800" "620">> 
*AD系統內''一定至少''有一台DC(Directory Controller)
**微軟:  AD內強烈建議至少兩台DC(因DC十分脆弱, 且兩台必須同時開機並完成資料庫同步)
***若兩台同步的DC其中一台處於關機狀態, 則AD無法作用, 且若關機時間超過45天, 再度開機時, 兩台DC內的資料庫將會進入墓碑狀態(Tombstone)
*AD技術至今仍然沒有與工作群組網路脫鉤, 當host與DC之間點對點連線失敗時, 仍然會以網芳廣播方式詢問DC
*AD特色:
##命名採用DNS格式, ex: it100.org
##使用者帳號密碼審核採用Kerberos協定, 不再利用NTLM將帳號以明碼方式傳送, 安全性大增
##使用者資料庫統一集中管理、提供網路服務
##減少廣播封包數量:
***傳統工作群組網路在使用網路資源透過廣播尋找Master_browser主機名稱
***AD系統透過Join Domain動作在DC中註冊, 使用網路資源改用點對點方式, 透過與DC之間點對點方式詢問主機位址, 再與欲使用之網路服務主機建立點對點連線
##微軟強烈建議在AD中同時建立兩部DC, 並使其同步, 因為AD資料庫非常脆弱, 也因此''事先的完善規劃''顯得格外重要, 前端電腦也只有在新增主機時會Join Domain, 電腦退役時才會Quit Domain, 實際使用VM測試時, 反覆的進進出出會造成AD資料庫大亂
##使用者可以透過Roaming(漫遊)將使用者自訂環境在不同的前端電腦使用

!工作群組網路 與 AD系統比較
|比較項目|Workgroup|Active Directoary|
|特色|各自為政的網路架構|集中管理、提供服務|
|建置難度|○○○○○|●●●○○|
|管理難度|●●●●●|●●●○○|
|安全管制|●○○○○|●●●●○|
|網路頻寬使用|●●●●●|●○○○○|
|系統維護難度|●○○○○○|●●●●●|
|核心成員|Master/Backup Browser|Domain Controller|
|核心成員如何決定|Master Browser 選舉|透過架設DC決定|
|核心成員數量|每個工作群組網路僅一個MS, 每32台host則增加一個Backup Browser|微軟強烈建議至少兩台DC、視網路環境增加|
|使用者資料庫|各Host間使用各自的SAM資料庫審核使用者資料|使用AD資料庫審核|
|成員系統|自Windows 95即可加入工作群組|至少需NT4.0 serverpack4以上才可加入Domain|
|成員命名規則|工作群組內電腦名稱不能重複, 不得與所處工作群組名稱相同|採DNS階層式命名架構, 電腦名稱.網域名稱|
|成員名稱限制|群組名稱與電腦名稱不能超過15個字元|FQDN不能超過256個字元|
!定義
*也是一個網路服務,一個特殊的網路服務
*目錄:一個資料庫的功能,用來集中管理網路上的資源或是物件
**網路上的使用者、群組、檔案、目錄印表機......網路管理者能快速的佈署及管理這些資源
*服務:提供一個安全又有效的機制,讓使用者能查詢存取資源,並使網路管理者能快速的佈署及管理這些資源
*自 Windows 2000 加入目錄服務
*X.500:最主要的目錄服務標準
**需要強力的伺服器支援
**必須基於 OSI ,並不適用於目前主流的 TCP/IP
*LDAP:早期為 X.500 的簡化版本,微軟的 AD 即為 LDAP 的 implement
*AD 就是微軟於 Windows 2000 網路環境中推出的一個符合 LDAP 協定的目錄服務

!優點 (官方說法)
*SSO(單一簽入):不管企業規模有多大,每一個員工都只需要維護一份使用者帳號,只要登入一次,在登出之前都不需要再次驗證即可使用網路上的資源
*有效率而且安全的集中(群組原則)或分散(Delegation)管理網路
*提升網路安全性
*擴充微軟視窗環境與不同平台的互通性 (interoperable)
**LDAP
**DNS
**Kerberos

!缺點 (神的說法)
*複雜
*需要額外的管理負荷
*因此適合用在中大型管理規模的網路架構,越大的網路架構越適合使用微軟的目錄服務

!特性
*階層式的架構 (Hierarchical Structure) → 樹狀結構,易於擴充
*採用 DNS 為查詢服務 (Locate Service)
**提供各種伺服器的查詢服務
***透過 srv record
**Internet 的 DNS server 與 AD 的 DNS server 不應該使用同一個
*採用階層式可擴充的命名方式 (Scalable Namespace)
*多主機伺服器複製模式 (Multi-master Replication Model)
**每一部 DC 都允許成為其他 DC 的複製來源
**DNS server 為 Single-master
*採用 Kerberos 的安全性驗證協定,Internet 標準,且效率較佳
**UDP:88
**未採用 AD 架構前,驗證使用 NTLMv2
*動態可擴充、自行定義的架構(Schema)
**Schema 定義允許存放在 AD 資料庫的類別 (Classes)、屬性 (Attributes)
***使用者即為一種常用的類別
**只能創造不能刪除
*採用 LDAP,UDP:389

!Active Directory 的結構
!!邏輯結構
*與地理區域無關的結構 (location independent)
*樹狀、階層的結構,透過4個邏輯元件鉤勒出這個結構
**樹系
**樹
**網域
**組織單元
!!實體結構
*與地理區域有相關

!!網域 (Domain)
*第一個網域:Root Domain
*命名:DNS 命名方式,最少兩層,例如 abc.local
*AD 邏輯結構下的核心單位、基本管理單位、複製單位
*網域控制站(DC):
*成員伺服器(MS):在網域內提供特定服務的伺服器
*工作站(WS):加入網域的客戶端機器
!!組織單元
*允許包含其他務件的網域容器物件
*基於管理上的需求,沒有一定的建構方式
**以部門為基礎建構的組織單元架構
**以地理區域為基礎建構的組織單元架構
*允許創造巢狀 OU
**原則上不限,但實務上不建議超過三層,因難以管理
*組織單元無法包括其他網域的物件
*利用 OU 可儘量達成單一網域的目錄服務,以簡化 AD 的維護與管理網域
!!樹 (Tree)
*由一個或一個以上的網域所組成的__連續__且__階層式__所排列的名稱空間
*特性
**連續階層的名稱空間
**共用一個 Schem、通用目錄 (Global)
**上下層網域會__自動建立__一個__雙向__可__移轉__(Transitive) 的 Kerberos 信任關係 (Trust Relation)
***數學上的可移轉性:A → B & B → C 則 A → C
*只要隸屬於同一個 AD tree 的任兩個 AD domain,透過適當的權限設計,將可以相互存取
!!樹系 (Forest)
*一個或一個以上的 AD Tree 所組成的不連續名稱空間
**不同的樹,擁有不同的根網域名稱
**使用相同的 Schema,通用類別目錄,結構組態
**所有的網域樹均會與第一個網域樹自動在根網域建立雙向可組織單元移轉性的 Kerberos 信任關係
***第2棵以後的樹僅會與第1棵樹建立起信任關係
*只要隸屬於同一個 forest,透過適當的權限設計,將可相互存取

!!站台
*一個站台是由樹個 IP 子網路經由高速且穩定的網路連結所形成的區域
*目的
**控制不同站台間 AD 資料庫複製的網路流量
**提供使用者登入及查詢網路服務的效率
!!網域控制站
*基於容錯及效能考量通常會架設一部以上並透過複製維護目錄資料的一致性
*功能
**儲存一份可變更可寫入的 AD 目錄資料庫
**執行資料庫的變更,並將這些變動複製至其他的控制機器以維護彼此資料庫的一致性
**提供使用者登入時的身份驗證及目錄搜尋服
**扮演 AD 環境內特殊角色:單一操作主機 (Single Master Operator),用來執行依些特殊的目錄變更工作,而這些工作通常只允許在某部指派的控制機器上執行
***操作主機一定是 DC,但 DC 並不一定是操作主機

!!信任關係
*一種 Domain 對 Domain 的關係,不是電腦對電腦的關係
*微軟的 AD 服務有單向及雙向的新任關係
**A → B:Domain A 信任 Domain B,A trusts B;A 為 trusting domain,B 為 trusted domain
**被信任的網域提供人,信任的網域提供資源,
**透過適當的權限設計,被信任網域的使用者可以使用信任網域的資源,被信任網域的管理者可以管理信任網域的資源,反之則不然

!!AD 資料庫
*c:\windows\NTDS\NTDS.DIT
|複製範圍|Partition|內容|
|樹系|Schema|建立與管理 AD 類別與屬性的定義和規則|
|~|Configuration|AD 結構性資料|
|網域|Domain|維護 Domain 內各種物件|
|自訂|Application|儲存某一些允許 AD 中執行的應用程式資料,預設只有 DNS|
*Application 僅在 windows server 2003 以上版本支援

!!操作主機
*負責執行某些特殊資訊變更的網域控制站主機

!!Schema
*定義允許儲存在 AD 資料庫中的物件類別與屬性 (Object classes and attributes)
**An object is an intance of specific class
*一個樹系只有一個 Schema,即樹系下的任何網域共用相同的 Schema
*AD 架構內的類別或屬性只能新增不能刪除
*支援 AD 的應用程式 (如 exchange server 或 ISA),安裝前均要先擴充 AD 架構

!!通用目錄 (Global Catalog)
*儲存整個 AD 樹系下每個物件的部份屬性
**通常為用戶端比較常用到的屬性
*主要設計目的
**提供 AD 樹系內網路資源的查詢服務
**提供使用者登入時身份驗證的必要訊息 (萬用群組、UPN尾碼(suffix))
***Access token
****User SID
****Group SID
****Userright (privilege):特定系統工作的執行權利
***UPN 尾碼:administrator@abc.local,建議的登入方式
*預設上只有樹系內的第一部 DC 會是通用目錄伺服器 (Global Catalog server),但日後可以變更或是新增通用目錄伺服器

!!AD 物件命名:DN
*可辨別的名稱 (Distinguished Name, DN)
**DN 用來作為物件的唯一辨識名稱
**包含足夠的資訊讓使用者可以查詢,同時也確認其在 AD 樹狀結構中的位置及路徑
**微軟 AD 物件命名規則並不與 LDAP 相容
|DN & RDN 命名屬性類型|說明|
|DC=Domain Componets|網域元件名稱|
|OU=Organization Unit|組織單元|
|CN=Common Name|通用名稱|
*LDAP DN 中,提供 O (Organization) 屬性,而 AD 環境中以 DC 取代
*標準的 LDAP DN 中還提供的 C(Country) 的命名屬性,不過 AD 並不支援
*一個典型的 DN 包含了容納物件的網域名稱,以及經由目錄階層到達務件的完整路徑
**CN=David Yeh, OU=MIS, DC=pagebook, DC=COM, DC=TW

!!相對可辨別的名稱 (Relative Distinguished Name, RDN)
*是 DN 的一部份,也是物件的屬性
*RDN 可以在包含他的上層父容器中唯一的識別他,David Yeh 為父容區物件 MIS 的一個 RDN
*DN 相當於檔案系統中的絕對路徑,RDN 則類同於相對路徑

!!Windows Server 2003 AD 的功能等級
*功能等級 (Functional Level)
*樹系功能等級
|樹系功能等級|支援的 DC|
|Windows 2000 (default)|NT4.0(BDC)<br>Windows 2000 Server<br>Windows Server 2003|
|Windows Server 2003 過度版(Interim)|NT4.0<br>Windows Server 2003|
|Windows Server 2003|Windows Server 2003|
**越上面相容性越高,功能性越低
*網域功能等級
|網域功能等級|支援的 DC|
|Windows 混合模式 (Mixed, default)|NT4.0<br>Windows 2000 Server<br>Windows Server 2003|
|Window 2000 純粹模式 (Native)|Windows 2000 Server<br>Windows Server 2003|
|Windows 2003 過渡版(Interim)|NT4.0<br>Windows Server 2003|
|Windows Server 2003|Windows Server 2003|
**Functional level 只與 DC 有關,與用戶端無關,因此在 Windows Server 2003 的功能等級下,仍可有 NT4.0 的 Member server 與 Workstation
*一旦升級功能等級後就無法還原
*建立 1st. Forest, 1st. Tree, Root Domain, 1st. DC

!需求
*Windows server 2003 standard、enterprise、datacenter
*TCP/IP,要手動指定 IP
**DNS 指到自己
*NTFS 檔案系統,至少要 250MB可用空間
*支援 Service Resource (SRV) 紀錄和動態更新 (Dynamic Update)功能的 DNS 伺服器
**Windows 2000 server 以上、或 BIND 8.2.1 以上版本
*正確無誤的時間與時區
**AD 內時間差距超過 5 分鐘會無法驗證

!建立第一部控制站
*工具:AD 安裝精靈 (dcpromo)
|MS<br>Standalone Server|dcpromo<br>→<br>←|DC|
*老舊的系統 (Windows 95、NT4.0 SP3↓),不支援Signature,將無法連線
**需安裝 AD client extension (Windows 2000 原版光碟內叫 DS client)
*效能考量,儘量將資料庫資料夾與紀錄檔資料夾放在不同的『硬碟』,避免磁碟競爭
**NTDS 可放在 FAT32,雖不建議,但 SYSVOL 僅能存放在 NTFS
**NTDS 資料庫目錄、紀錄檔目錄事後可以搬移,但 SYSVOL 一旦建立將無法搬移
*SYSVOL
**提供網域運作中各種需要的指令檔
**群組原則的組態資料
*使用權限
**使用權限和前版 Windows 2000 server 作業系統相容:支援 Null Session
***若存在 NT4.0 server 作為 member server,則必須選擇此項,但安全性降低
**預設不支援 Null Session
*還原模式密碼:
**開機 F8 系統還原使用
**修復主控台,原版光碟開機選 R 進入

!安裝後檢查與確認
*確認 NTDS 資料夾建立,ntds.dit 資料庫檔案、日誌檔
*確認 SYSVOL 資料夾
*確認兩個共享資料夾:sysvol、netlogon
*兩個服務不能關閉:netlogon、server
*DNS server 是否有動態更新的網域資料

!建立複本控制佔 (Replication DC)
*直接由網路上其他 DC 複製整個目錄資料庫
**若是需要透過緩慢或不穩定的連線,則拷貝流量可會成為問題
*由以還原的備份媒體安裝 (Windows server 2003 起提供)
**使用備份工具備份系統狀態資料
**將備份檔案還原至特定位置
**將已還原資料儲存至特定媒體
**dcpromo /adv
*DNS 指向第一部 DC
**微軟只會在每個 Domain 第一部 DC 詢問是否裝 DNS 服務
**要建立提供容錯的 DNS 服務,只要安裝 DNS service,裝好後不久即會透過 Replication 將 DNS AD 整合區域複製過來
*要建立複本 DC:網域管理員身份
*要建立子網域與額外的樹:Enterprie admins 群組成員

!建立子網域控制站、樹系內其他的樹
*DNS 指向 parent domain 的 DNS
*依序選擇 1-2
*輸入 enterprise admins 群組的管理員帳號密碼
*輸入父系網域名稱,子網域相對名稱

!考慮升級網域功能等級
*預設為 Windows 2000 mixed mode
*相容於 Windows NT 的 BDC 作為網域控制站
*決策考量:
**AD 網域內目前及未來均不可能再有 Windows NT 的 BDC 作為網域內的控制機器

!變更樹系功能等級
*必須先提升網域功能等級才能提升樹系功能等級
*正常移除
**dcpromo
*強迫移除
**dcpromo /forceremoval
**適用於無法連上 DNS 上的 DC 資料庫時,仍可移除
**未公開 (undocument)
**再透過其他上線中的 DC 將已移除的 DC 物件
{{{
ntdsutil
metadata cleanup
connetcions
connect to server dc11.lin.local
quit
select operation target
list sites
select site 0
list servers in site
select server 0
quit
remove selected server
quit
}}}

*手動移除
<<<
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\ProductOptions
將 ProductType's 由 LanmanNT 轉換為 ServerNT (case sensitive)
重新啟動電腦
手動刪除 NTDS 與 SYSZVOL 目錄
手動移除 DNS SRV 紀錄
手動移除 DC物件
手動移除站台內的 server object
<<<

*網域中其中一部 DC 移除,將會成為網域中的 MS,
*要移除父網域,必須先移除子網域

!Windows Server 2003 R2 問題
*使用 adprep 工具升級 AD 架構 (Schema)
**d:\cmpnents\r2\adprep> adprep /forcestprep
*完成架構升級後,再安裝 R2

!Windows server 2008 加入 DC
*需先執行下面指令
**source\adprep
**domainprep (??)
*或是找一台現有的DC 直接透過升級 2008
!定義
*信任關係是一種建立於網域間的安全性邏輯連結關係
*在微軟的網域模式下,建立信任關係將可以讓不同網域的使用者安全性的互用溝通,執行跨網域的身份驗證及管理工作,並用以存取不同網域的資訊或資源

!!單向與雙向的信任關係

!!信任關係的可移轉性

!!信任關係的類型
*父子信任關係(Parent-Child Trust)
**在同一個樹的網域樹中,上層與下層網域會自動建立雙向且可移轉的信任關係,且無法被刪除
*樹系根目錄信任關係 (Tree Root Trust)
**在同一個樹系中每個根網域會與樹系內__第一個__根網域自動建立雙向且可移轉的信任關係,且無法被刪除
*捷徑 (Shortcut) 信任關係
**為了提升樹系內跨網域作業的效率,管理員基於樹系內手動的替不同的網域建立信任關系,具備被信任網域向下部份可移轉性,日後可被刪除信任關係
**僅能在樹系內
*外部信任關係 (External Trust)
**管理員和一個並不隸屬於相同樹系內的網域或是為了與 Windows NT 網域基於互用溝通需要所手動建立的信任關係,@@color:red;此種外部信任關係並不具備可移轉性@@
*樹系信任關係 (Forest Trust)
**僅能在 Windows Server 2003 樹系功能等級下支援,通常管理員為了讓兩個樹系間可以安全性的互用溝通並在樹系之間共享資源,所手動建立且具備可移轉性的樹系間的信任關係
**僅能在緊鄰的樹系內,存取資源
*Realm Trust
**微軟網域為了與其他作業平台 LDAP 建立 Trust 的方式

!手動建立信任關係
*設定 DNS 服務
**兩端 DNS 服務彼此作為對方的 Stub 或 Secondary 區域,或是透過 Condition Forward
*新增信任精靈 → 透過 AD 網域及信任
**選擇信任關係
***不同樹系間選擇 External 或 Forest Trust
***同樹系內僅有 Shortcut Trust
**單向或雙向
**建立信任關係時,若建立者擁有雙方的管理權限,則可一次建立,否則需各自建立網域信任
***實務上建議『被信任網域』先建立 pre-share password,提供給『信任網域』的管理員
**一次建立一個方向以免混淆
*建立樹系單向信任步驟:
##AD 網域及信任中,點選網域內容
##
##輸入要建立信任關係的網域
##選擇樹系信任
##被信任區域選擇 『單向:連入』,
##若建立者擁有雙方管理權限選擇『同時建立於這個網域和指定網域』,若否則選擇『只建立這個網域』
##若前項選擇同時建立,則輸入對方網域的管理員帳號密碼,若選擇只建立這個網域,則輸入一個『共用密碼』,且需符合複雜密碼
##確認連入信任:信任網域(ing 方)需要一段時間才會生效,因此確認連入信任沒有用
***信任網域內容 → 選擇確認
{{item1{__一次建立單向信任 -1__}}}  <<toBalaFlashPlayer "flash/03_one-way_forest_trust_at_once.swf" "有影片有真相" "800" "620">>
{{item1{__一次建立單向信任 -2__}}}  <<toBalaFlashPlayer "flash/03_one-way_forest_trust_at_once-2.swf" "有影片有真相" "800" "620">> 
{{item1{__確認樹系信任__}}}  <<toBalaFlashPlayer "flash/03_verify_forest_trust.swf" "有影片有真相" "800" "620">> 

!!被信任網域使用者存取信任網域資源
*建立 DL 群組{{item1{__在信任網域上建立網域區域群組__}}}  <<toBalaFlashPlayer "flash/03_create_DL_group_at_trusting_domain.swf" "有影片有真相" "800" "620">> 
*抓取被信任網域的 Global 群組
!!讓被信任網域的管理員管理信任網域
*被信任網域的 Domain admins(G) 加入 信任網域 的 administrators (DL)
{{item1{__允許被信任網域管理員管理信任網域__}}}  <<toBalaFlashPlayer "flash/03_allow_trusted_domain_managing_trusting_domain.swf" "有影片有真相" "800" "620">> 

!撤銷信任關係(Revoke)
{{item1{__撤銷樹系信任__}}}  <<toBalaFlashPlayer "flash/03_revoke_forest_trust_at_once.swf" "有影片有真相" "800" "620">> 
!!DNS 提供 AD 的功能
*主機解析
*定義名稱空間,及各項 AD 伺服器服務資訊 (透過 SRV 紀錄)
*提供服務查詢功能 (Locate Service)

!!DC、DNS 與用戶端
*用戶端由 DHCP 指派 IP 時,用戶端電腦自行向 DNS 伺服器註冊 A 紀錄,DHCP 伺服器會向 DNS 伺服器註冊該用戶端的 PTR 紀錄
*網域控制站向 DNS 伺服器註冊 A、PTR、SRV 紀錄
*用戶端透過 SRV 紀錄查詢網域中的物件

!!支援 AD 的 DNS 服務
*支援 SRV 紀錄類型 (Require)
**非常特殊、複雜的類型
*支援動態更新 (實務上Require)
!!!以上 Windows 2000/2003 與 BIND 8.2.1 以上即有支援,但 BIND 設定不易
*使用 AD 整合區域
**複寫區域資料範圍
***整個樹系
***網域內所有 DNS
***網域內所有網域控制站
**只有 AD 整合區域有完整的容錯能力
***傳統的 Secondary 僅有查詢的容錯能力,而沒有管理區域的容錯能力
**僅在 AD 整合區域內有安全性的動態更新
***預設上Domain 內經過授權的使用者才能在 DNS 中動態更新
**AD 整合區域在做 Replication 時全程加密,而 DNS 的區域轉送使用明碼傳送

!SRV 資源紀錄
*Internet 標準紀錄類型
*用來定義網路上哪一部伺服器提供哪一項服務
**每一部 DC 在每一次開機的時候會利用 c:\windows\system32\config\netlogon.dns 向 DNS 伺服器註冊 SRV 紀錄
|服務名稱|協定|範圍|TTL|Class|SRV|優先權|權數|連接埠|主機名稱|
|_ldap.|_tcp.|flatfish.local.| 600 | IN | SRV | 0 | 100 | 389 | srv-cht-dc1.flatfish.local.|
*TTL 允許存放在用戶端的 Cache 長短
*優先權:0 ~ 65535,值越小優先權越高
*權數:0 ~ 65535,當優先權相同時,由權數決定如何回應
| P | W | server | 回應次數 |
|0|40|DC1| 40/160 |
|0|80|DC2| 80/160 |
|10|20|DC3| 0 |
|0|40|DC4| 40/160 |
*服務名稱
**_ldap:查詢服務
**gc:Global catalog,快速查詢服務
**_kerberos:驗證服務(AS)、票證管理服務
**_kpasswd:Kerberos 的票證(Ticket)管理服務

!!AD 如何使用 DNS
*網域內每部 Windows 2000 以上的機器開機時,會自動登錄 A 與 PTR 紀錄
**要註冊 PTR 紀錄需有反向區域,且允許動態更新
*網域控制站開機時會自動註冊約 20 個 SRV 紀錄與 A 紀錄
*使用者機器登入網域時需向 DNS 查詢 DC 的資訊
*使用者查詢樹系物件時需向 DNS 查詢 GC 的資訊

!!診斷 DNS 服務工具
*nslookup
{{{
ls -t srv flatfish.local
# ls 指令是做 zone transfer 動作,因此管理員的電腦必須加入允許 zone transfer 的清單內

set q=srv
_ldap._tcp.flatfish.local
#列出所需要的 AD 查詢主機
}}}
*dnslint,在原版光碟 support 內的 support.cab 內,需自行安裝
{{{
dnslint /ad /s 192.168.33.129 /v
}}}
** /ad:查詢 AD DNS
** /s 192.168.33.129:伺服器位址
** /v:詳細解釋

!檢查無法自動更新 DNS 問題
*檢查網路連線
*檢查 DC 或用戶端機器是否啟動動態更新 (TCP/IP 中 DNS 設定)
*檢查主要尾碼是否正確 (我的電腦右鍵)
*檢查 DNS 伺服器是否允許動態更新
*DHCP 環境,DHCP 是否執行動態更新

!!動態更新 DNS 問題
*資料過時問題
**啟動過時清除 (scanvaging)
*安全性問題

!!手動註冊 DNS 紀錄
*A 與 PTR紀錄:ipconfig /registerdns
*SRV 紀錄:重新啟動 netlogon
!管理工具
*嵌入式管理單元
**Active Directory Users and Computers
**Active Directory Domains and Trusts
**Active Directory Sites and Services
**Active Directory Schema (未註冊)
***執行 regsvr32 schmmgmt.dll,開啟 MMC 加入
**Active Directory Migration Tool:AD 遷移工具,光碟內的 \i386\ADMT
**Adsiedit (光碟內的 support tool)
**GPMC (Group Policy Management Console)
*命令列管裡工具
**dsadd:新增 AD 物件
**dsrm:刪除 AD 物件
**dsmod:修改一個既存的 AD 物件
**dsquery:查詢
**dsmove:搬移
**csvde:將 AD 物件 Import 或是 Export,適合用在不同的目錄服務環境下使用
**ldifde:將 AD 物件 Import 或是 Export,適合用在不同的目錄服務環境下使用
*其他:ldp (support tool)
*程式化管理:ADI + Windows Script Host
!使用者帳號
*DC 的本機使用者資料庫 (SAM) 被停用
**在還原模式、修復主控台還是會使用到
*為了方便、有效率、更安全的集中管理使用者帳戶,在 AD 服務環境下,管理員應該只替員工建構網域使用者帳戶
!!規劃使用者帳戶
*規劃使用者名稱:
**使用者全名 (Full Name):原則上由姓加上名
**User Principal Name(UPN):email 格式的登入方式
**Windows 2000 前版登入方式 (Down level logon name)
**建立 AD 使用者時,其顯示名稱 (Full name) 必須在所建立及包含的__網域或 OU__ 內必須唯一
**UPN 必須在整個__樹系__內唯一
**舊版登入名稱必須在__網域__範圍內唯一
*命名規則
**登入名稱最好小於 20 個字元
** "/\[]:;|=,+*?<> 不得用來作為帳戶名稱
**命名方式必須能夠處理同名並辨識臨時員工帳號
***例如 T_ 開頭為臨時員工
*使用者帳戶安全性管理
**密碼原則
**鎖定原則
**特殊帳戶管理:guest、administrator、service account
**其他限制:
***限制登入時間、有效期限等
*預先建立適當的 OU
**配合公司分散管理的政策
*建立使用者帳戶失敗的原因:
**權限不足
**使用者名稱的唯一性不符
**初始密碼不符合密碼原則的規定
*預設群組原則,新增的使用者帳戶若不擁有任何一個管理權限,則無法在 DC 本機登入

!建立使用者方式
*滑鼠搖一搖法
*命令列新增
{{{
dsadd user "cn=王大熊,ou=會計部,dc=flatfish,dc=local"  -ln 王 -fn 大熊 -display 王大熊 -upn bear@flatfish.local -samid bear -disabled no -mustchpwd yes -pwd *
}}}
*透過 csvde、ldifde 匯入匯出
**提供一次創造大批使用者
**兩者差異
***格式不同
***ldifde 為 Internet 標準,csvde 則是微軟獨有
***ldifde 提供較多的功能,除了新增外尚能刪除、修改
***csvde 則只能新增
##先創造一個文字匯入檔
***csvde 使用者的是逗號分格 (Comma-Separated Value)
***ldifde

!!csvde
*無法輸入密碼,因此在有密碼原則下,userAccountControl 必須給予 514 的值,代表停用
*第1行照抄,一個字都不能差,第2行開始依照第1行的欄位輸入
*若建立的帳號有中文資料,必須存成 unicode 格式的文字檔,並在 csvde 加上 -u 指定匯入 unicode 格式
{{{
DN,objectClass,sAMAccountName,userPrincipalName,displayName,userAccountControl
"cn=比目魚2,ou=工程部,dc=flatfish,dc=local",user,flatfish2,flatfish2@flatfish.local,比目魚2,512
"cn=王大熊2,ou=快計部,dc=flatfish,dc=local",user,bear2,bear2@flatfish.local,王大熊2,514
}}}
*csvde -i [-u] -f {//filename//}
**-i:input
**-u:unicode
**-f:filename
*匯出所有非管理性元件
**csvde -f {//filename//}
*匯出所有使用者帳號
**csvde -r "ObjectClass=user" -f {//filename//}

!ldifde
*新增
{{{
dn:cn=比目魚3,ou=工程部,dc=flatfih,dc=local
changetype:add
objectclass:user
sAMAccountName:flatfish3
userPrincipalName:flatfish3@flatfish.local
displayName:比目魚3
userAccountControl:514
}}}
*刪除
{{{
dn:
changetype:delete
}}}
*修改
**『 - 』代表接續上一個帳號繼續修改
{{{
dn:
changetype:modify
replace:userAccountControl
userAccountControl:512
-
replace:l
l:Taipei
}}}

!使用者登入
*NT4.0 登入方式:
**選擇登入到 網域
**flatfish\flatfish
*UPN:flatfish@flatfish.local
*微軟建議使用 UPN 登入方式
**日後變換網域時,登入名稱不需更改
**UPN 尾碼可自行設計,彈性高
**可與 Email 位址一樣,方便記憶
{{item1{__建立 UPN 自訂的尾碼__}}}  <<toBalaFlashPlayer "flash/05-1_create_a_customized_UPN_suffix.swf" "有影片有真相" "800" "620">> 


!使用不同於預設網域的 UPN 尾碼
*Enterprise Admins 管理者群組才有權限
*在 AD 網域及信任中新增替用的尾碼
*建立自訂的 UPN 尾碼後,在整個樹系中即可使用該 UPN 尾碼
*建議使用與企業 email address 相同的 UPN 尾碼

!刪除使用者帳戶
*刪除使用者帳戶並不會將使用者的主目錄及使用者設定檔移除
*命令列刪除使用者帳戶
{{{
dsrm cn=比目魚3,ou=工程部,dc=flatfish,dc=local
}}}

!設定或修改使用者帳戶內容
!!檢視開啟進階檢視
*一般、地址、電話、組織:建立查詢使用的資料
*設定使用者登入時間限制
**在登入時限內登入,但不限制已登入的使用者
**要在登入時限到達時,要強迫使用者登出,必須使用群組原則:電腦設定 → Windows設定 → 安全性設定 → 本機原則 → 安全性選項 → Microsoft網路伺服器:當登入時數過期時,中斷用戶端連線
*設定使用者限制登入的機器:只能輸入 NetBIOS Name
*微軟建議針對臨時員工、簽約員工設定到期日
*設定檔:設定使用者的工作環境
**設定擋路徑:使用者漫遊設定檔
**登入指定檔:.bat, .cmd, .vbs, .js
***存放在一台 DC 中的 NETLOGON (預設 %windir%\SYSVOL\sysvol\{\\網域名稱\\}}\SCRIPTS),一段時間後即會複製到所有的 DC
**主資料夾:可設定本機或是網路磁碟機
***建議選擇網路磁碟機,選擇 H 磁碟機代號,路徑 \\192.168.33.129\home\%username%
****不需預先建立使用者目錄,自動建立目錄時會設定好適合的權限
*撥入:使用者遠端存取的權限
*成員隸屬

!管理員帳號 (administrator)
*無法刪除
*可以停用
**但需先做好一切委派工作
*遠端可 lockout,本機不會 lockout
*強力建議改名
*密碼空白將無法做網路連線

!管理員修改使用者密碼
*管理員不需要知道使用者 (也不會知道) 即可修改使用者密碼
*使用者的密碼產生器
{{{
net user flatfish /random >> passwd.txt
}}}
*該程式在 NT4.0 時建立,並沒有因為 windows server 2003 改版而更新,但 NT 時代定義的複雜密碼與 2003 不同,若出現錯誤則再輸入同樣指令即可

!建立使用者範本及複製帳戶
|標籤|是否會被複製到新帳戶的內容設定|
|一般|不會|
|地址|全部,除了街道|
|帳戶|全部,但設定檔路徑和主資料夾將被變更微幅核心帳戶的登入名稱|
|電話|不會|
|組織|會,除了職稱|
|成員隸屬|會|
*其他不會被複製,使用預設的設定
*建議每個部門建立一個範本帳號
{{item1{__建立使用者範本帳號__}}}  <<toBalaFlashPlayer "flash/05-1_create_a_template_user_account.swf" "有影片有真相" "800" "620">> 

!搜尋使用者帳戶
*AD 提供一個資料庫,可提供管理員或使用者做查詢
!!圖形化介面搜尋
*選擇搜尋的類別
*輸入名稱 (最常搜尋的條件)
*選擇進階搜尋,選擇要搜尋的條件
*搜尋範圍:
**整個 目錄:透過 Global catalog
**{//網域名稱//}:透過最近的一部 DC 尋找
*透過搜尋結果窗格,在權限足夠的情況下,可直接對搜尋結果作內容修改
!!用戶端搜尋
*Windows 2000 以上支援
*網路上的芳鄰搜尋 active directory
**Windows server 2003 或是沒有左方的選項時,進工作選單,資料夾選項→一般標籤下方,啟用資料夾的一般工作
*用戶端需對查詢的物件有讀取以上的權限
*一般使用者對自己的帳號只能做『一般、地址、公司』內部份內容做修改,對其他僅有讀取權限的資料則不能修改

!!Shared folder publish
*針對經常被存取的共用資料夾資源可做共用資料夾發佈,使用者則能透過查詢 AD 而得知共用資料夾發佈
**手動發佈後,需設定適當的關鍵字讓用戶端做查詢
*AD 內任何一台 share 出來的印表機皆會被自動發佈
*要看到已發佈的印表機,需在 AD 使用者及電腦下,檢視選單內,點選『將使用者、群組及電腦當作容器』,接著在共享印表機的電腦物件內就可看到

!網域內搬移使用者帳戶
*使用時機:例如公司員工換部門
*條件:在同一個網域內,AD 使用者及電腦僅能在同一個 Domain 做搬移
*影響:使用者帳號
**要搬移的物件若有繼承自原來 Container 的權限時,會自動放棄,且套用新的 Container 的權限
**要搬移的物件原來所屬的 OU 若有套用的群組原則設定,則會放棄原來的群組原則,而改套用新 OU 的群組原則

!跨網域的搬移
*透過 movetree → 超級難用的命令列
*使用 ADMT
**安裝 \i386\admt\admigration.msi
**來源網域建立新的本機群組 source_domain$$$
**來源網域機碼資料庫新增下面的值
{{{
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Lsa\TcpipClienSupport
REG_DWORD 0x01
}}}
**上述的設定條件可由 ADMT2.0 的模擬測試階段,由 ADMT 自動設定,完成後需重新開機
**兩方網域的 Default Domain Controller GPO 啟用帳戶管理的稽核工作

!!SID
*SID=S - Domain ID - RID
*Security principal 才擁有 SID
**Security principal:可已被設定權限的對象,僅使用者、群組、電腦
*同一個網域內物件搬移 SID 不會改變
*不同網域間物件搬移,則 Domain ID 必須要修改,而原先針對該使用者的權限將會失效
**微軟想出的解決方案:透過維護一個特殊的欄位:sidhistory,存放先前的 SID,在比對存取所有的資源時,將會比對新的 SID 與 舊的 SID
***要使用此功能必需在 Windows 2000 native 功能等級以上

!!ADMT
*milkfish.local → flatfish.local,milkfish 信任 flatfish
**milkfish 的 administrators 必須加入 flatfish 的 domain admins
**將 milkfish.local 的使用者搬移至 flatfish.local
*建議在被信任網域上執行 ADMT,以方便檢視帳號是否搬移成功
*ADMT 無法將該帳號的原有密碼直接遷移,必須透過額外的軟體抓取雜湊值,因此建議由 ADMT 重新產生一個新的複雜密碼,並儲存在特定檔案
*將使用者 SID 遷移到目標網域:將舊的 SID 納入 SID 歷程紀錄中,以讓原使用者可以繼續使用原先既有的權限
*User profile 綁死 SID,因此若要該使用者能使用原先的 Roaming user profile 則需勾選 轉譯漫遊設定檔
*建議勾選更新使用者權利,
*勾選遷移關聯的使用者群組則會將原使用者所屬的群組一併搬移
**更新先前遷移的物件:將原有的隸屬關係維護
*修正使用者的群組成員資格:將該使用者原先所屬的內建群組,搬移後將自動加入目的網域的內建群組
{{item1{__ADMT 遷移測試精靈 -1__}}}  <<toBalaFlashPlayer "flash/05-1_ADMT_sim_1.swf" "有影片有真相" "800" "620">> 

{{item1{__ADMT 遷移測試精靈 -2__}}}  <<toBalaFlashPlayer "flash/05-1_ADMT_sim_2.swf" "有影片有真相" "800" "620">> 
{{item1{__ADMT 遷移 -1__}}}  <<toBalaFlashPlayer "flash/05-1_ADMT_1.swf" "有影片有真相" "800" "620">> 

{{item1{__ADMT 遷移後利用 AD users and computers 與 ldp 查詢遷移物件__}}}  <<toBalaFlashPlayer "flash/05-1_ADMT_2_verify.swf" "有影片有真相" "800" "620">> 

{{item1{__ADMT 遷移後新產生的複雜密碼__}}}  <<toBalaFlashPlayer "flash/05-1_ADMT_3_new_password.swf" "有影片有真相" "800" "620">>

!帳戶密碼管理
*密碼原則
**套用在 Defaut Domain Group Policy
**可還原的加密來存放密碼
***取代 MD4 改以 DES
***若要使用 MS CHAPv1 
***IIS 5.0 需要摘要式驗證
**密碼最長建議不超過 45 天,在最長期限內需改密碼
**密碼原則必須每個項目都啟用,不然會有安全性漏洞
*帳戶鎖定原則
**重設帳戶鎖定計數器的時間間隔:在設定的時間內輸入錯誤密碼的次數不得超過設定值,不然將會被鎖定
**帳戶鎖定時間:密碼輸入錯誤數次後,遭鎖定的時間,設為 0,則必須由管理員手動解除
**帳戶鎖定x值:設定密碼輸入錯誤的可容許值
**帳戶鎖定原則建議僅用於 Intranet 帳號,Internet 上的帳號不建議使用,因目前網路上有種攻擊專門針對此點,讓所有帳號被鎖定

!InetOrgPerson 類別
*若微軟的 AD 需與其他作業平台上的目錄服務互相溝通 (例如 Linux 上的 openLDAP),則使用者帳號不能使用預設的使用者類別,必須使用 InetOrgPerson 類別,與使用者類別設定方式相同,但 InetOrgPerson 為 Internet 標準
!何謂群組
*一個群組是由一些 AD 物件或本機內物件所組合而成
*群組內可以包含使用者、連絡人(contacts @Exchange)、電腦或其他群組物件
*
*群組的設計在於簡化各項帳戶的維護管理工作,特別是提供管理員透過群組來指定各項權限工作

!群組類型
*安全性群組
**主要為指定各項資源使用權限或特定的管理權限等安全性相關工作 (DACL, discretionary access control list)
**只有安全性群組能出現在 DACL 的清單中 (
*發佈群組
**發佈群組無法處理指定權限等安全性的相關工作
**無法出現在 DACL
**通常只能配合電子郵件應用程式 (如 Exchange) 像一群使用者傳送電子郵件

!群組領域 (Group Scope)
*原始設計目的、成員限制、使用可視 (viewable) 範圍不同
*與網域功能等級有關,
||通用群組<br>global group|網域區域群組<br>domain local|萬用群組<br>universal group|
|主要用途|集中有相同存取目的的使用者|指定網域內各項使用權限<br>1.Permission<br>2.userrights|彌補 DL、G 的不足<br>彈性的支援大型或複雜 AD 環境<br>集合多個網域的帳戶|
|Windows 2000 mix|只能包含這個網域的使用者帳戶|可以包含信任關係內任何網域的使用者帳戶及通用群組|無法使用|
|Windows 2000 native|可包含這個網域的使用者帳戶與其他通用群組|可以包含任何網域的使用者帳戶、萬用群組、通用群組<br>2.包含這個網域內的其他網域區域群組|可以包含樹系內任何網域的使用者帳戶、萬用群組與通用群組|
|允取被指定存取權限範圍|樹系內所有網域|本身隸屬的網域|樹系內所有的網域|
|群組轉換限制<br>只能在 Windows 2000 native 以上|可以轉換為萬用群組|可以轉換為萬用群組|只要符合群組領域的成員限制,則可轉換成通用或網域區域群組|
|缺點|群組成原僅限於這個網域內|創造出的群組僅能使用在這個網域|無法在 windows 2000 mix 功能等級下使用|

!網域功能等級與群組關係
||純粹模式(native mode)|混合模式(mix mode)|
|DC|不允取 NT 的 BDC|允許 NT 的 BDC|
|萬用群組|安全性及發佈群組皆可為萬用群組|僅發佈群組可為萬用群組|
|巢狀群組|可允許一層以上的巢狀群組設計|僅發佈群組可|
|變更群組類型與領域|可允許安全性及發佈群組轉換,萬用群組與通用群組及網域區域群組的轉換|不能轉換|
*巢狀群組的好處:可以減少權限的設定次數,但會提升後續追蹤權限的難度

!新增群組
*圖形介面
*命令列建立安全性通用群組
{{{
dsadd group cn=g1,ou=mis,dc=flatfish,dc=local -samid g1 -secgrp yes -scope g
}}}

!新增群組成員
*圖形介面
*命令列新增群組成員
{{{
dsmod group cn=g1,ou=mis,dc=flatfish,dc=local -addmbr cn=王大雄,ou=mis,dc=flatfish,dc=local
}}}

!變更群組類型與領域
*需在 Windows 2000 native 以上的網域功能等級

!指定群組的管理員
*Windows server 2003 提供的新功能
*易於追查誰負責管理這個群組
*委派值得信賴的使用者來控制群組的成員
*只能針對這個群組新增移除成員

!網域群組應用原則與策略
!!單一網域 - AGDLP
#將一群具備相同網路需求或目的的網域使用者帳戶建立一個通用群組,並將這些帳戶加入這個通用群組
#在資源所在的網域建立一個網域區域群組,用這個群組來指定這個網域內特定資源的適當權限
#最後將步驟 1 的通用群組加入步驟 2 的網域區域群組
*通用群組:管理資源使用的權力,誰可以使用,誰不可以使用
*網域區域群組:管理資源使用的存取等級
!!在多網域下 - AGUDLP
*在各網域建立 global group
*隨便在哪個網域建立 universal group,並加入各網域內的 global group
!!AGGUDLP
*就... global group 加入 global group
**例如:負責收款的會計與付款的會計分屬兩個 global group,另外一個 global group 包含前兩個 global group

!內建及事先定義的群組
*系統自動建立的群組

!!內建的網域區域群組 (Domain Local Group)
**通常放在 Builtin
**放在 Users 內的網域區域群組多是安裝某個應用程式增加的非必要群組
|內建網域區域群組|權限說明|
|Account Operators|管理網域內使用者、群組及電腦帳號<br>但不能變更 administrators 及 server operators 群組內容|
|Administrators|
|Backup Operators|備份、還原資料|
|Network Configuration Operators|可以替所有使用者電腦設定網路組態|
|Pre-Windows 2000 Compatible Access|若需要讓 NT4.0 的用戶端電腦存取特定的網路資源則將 authenticated users 加入|
|Print Operators|管理網域內印表機|
|Remote desktop users|允許遠端桌面連線的群組|
|Server Operators|可以執行大部份一般性的作業,管資源、管帳號等,僅部份與安全性及系統穩定性相關的設定無法執行:稽核定義、驅動程式更新等<br>(只在 DC)|
|Users|若有一個資源需要設定給整個網域內的所有使用者,則使用 Users 指定即可,Users 包含 Domain users 群組|

!!內建的通用群組
*存放在 Users
*DnsUpdateProxy(有裝 DNS 才有):
**DHCP 伺服器若有一部以上,必須將這些 DHCP 伺服器的電腦帳號加入這個群組內
*RAS and IAS Servers:RAS 安裝完,與經過授權的 IAS 伺服器會被加入這個群組中

!!內建的萬用群組
*存放在 Users
*Enterprise Admins:AD 環境中權限最高的群組,對 AD 內整個樹系中的每個網域內的每一部機器都是 Full controll
*Schema Admins:用來變更 Schema
*僅有上述兩個內建萬用群組可以執行 AD Schema

!!內建的系統群組 (System Group)
*並非 AD 的有形物件:只有在管理員設定權限的時候會自動出現
*無法由管理員新增或移除成員,成員來自網路上特定的行為
*圖像上有一個紅色向上的箭頭
*重要的內建系統群組
**CREATOR OWNER:檔案、目錄建立的擁有者
**DIALUP:透過撥號連線的使用者
**Authenticated Users:只要成功的通過身份驗證的使用者
**Everyone:阿貓阿狗只要連上 AD
**INTERACTIVE:本機登入的使用者
**NTLM Authentication:透過 NTLM 身份驗證的使用者
**TERMINAL SERVER USER:透過終端遠端連線的使用者
!建立電腦物件
*將電腦加入網域時,會自動的在 Computers 內建立電腦帳戶
**Computers 不是 OU,無法透過 GPO 管理
*管理員事先建立在規劃的 OU 下
**將這個電腦帳戶指派為 Windows 2000 前版電腦:若這台電腦 NT4.0 的作業系統則選擇此項
**將這個電腦帳戶指派為備份網域控制站:若這台電腦為 NT4.0 的 BDC 則必須選擇此項

!搬移電腦帳戶
!!網域內搬移
*圖形介面
!!跨網域搬移
*ADMT

!重設電腦帳戶
*電腦帳戶密碼
**XP / 2003 的機器每隔 30 天會自動重設密碼,2000 (七天?)
**存放於本機的 LSA 快取區及 DC 的資料庫
**當本機與 DC 的密碼更新同步產生問題時,會無法連線
***常發生在網域內某電腦太久沒啟動
!!使用時機
*機器毀損而重新安裝一部相同名稱的機器,可使用重設電腦帳戶
**執行重設電腦戶:清除密碼,重新設定
*使用 Ghost 還原系統時
*使用 XP 的系統還原功能時
*一部機器過久沒有啟動
**例如過年時
*DC 重設帳戶後,用戶端電腦必須退出網域再重新加入網域
*網域控制站不能透過重設帳戶直接 reset
**只能透過命令列
***netdom resetpwd /s:{//server_name//} /ud:{//domain_name//}\{//Username//} /pd:*

!停用電腦帳戶
*被停用的電腦帳戶將無法使用任何一個網域內的使用者帳號登入
**本機使用者帳號仍可登入
!委派管理 (Delegation)
*AD 環境下分散管理機制
*將 AD 物件的某些管理權限委託給他人來維護管理
*委派管理設定 AD 物件的 ACL
**AD 內的每個物件都維護一個 ACL
***在 AD 使用者及電腦下要檢視 ACL,必須開啟檢視 → 進階檢視 功能
*針對不同物件類型,ACL 的權限設計差異甚大,因此管理者無法透過直接修改 ACL 來委派管理

!設定委派管理
*利用『委派控制精靈』
**委派的對象建議 Container objects,而不針對某單一物件,最常見的 Container objects 為 Sites、Domain、OU,其中最常被委派管理的是 OU
*僅有 Container Objects(特別是 OU),可以只用委派控制精靈
!!委派控制精靈
*選擇要被委託的 OU
*選擇要委託的對象
*委派的工作
**委派下列的公用工作:微軟認為經常被委託的工作項目
**自訂的委派領域
*委派的使用權限
**刪除的權限需額外考慮
{{item1{__組織單元委派__}}}  <<toBalaFlashPlayer "flash/09-OU-delegation.swf" "有影片有真相" "800" "620">> 

{{item1{__刪除組織單元委派__}}}  <<toBalaFlashPlayer "flash/09-OU-delegation_delete.swf" "有影片有真相" "800" "620">> 

!收回委派管理權限
*沒有精靈可以使用,直接透過修改 DACL 回收
**刪除欲回收的 ACEs (Access Control Entry)

!設計自訂式的管理工具
*因為受委派的使用者可能委派的工作極為陽春,而 AD users and computers 為一個複雜的管理工具,且該使用者就算沒有權限仍可檢視所有 AD 內的物件,因此極不方便與不安全,因此要創造一個自訂且簡化的管理工具
*使用 MMC 的工作台檢視 (Taskpad)
##新工作台檢視
##設定新工作台外觀
##選擇『所選的樹狀工作項目』
***傳統 MMC 管理工具視窗左邊叫 樹狀目錄,右邊叫 詳細窗格
##設定工作建立精靈
##調整畫面
##改變主控台模式:使用者模式 - 限制存取,單一視窗
##取消『允許使用者自訂檢視』
{{item1{__建立自訂的工作台檢視__}}}  <<toBalaFlashPlayer "flash/09-create_customized_taskpad.swf" "有影片有真相" "800" "620">> 
!建置 VMWare 網路環境
[img[image/SBSNetwork.PNG]]
{{item1{__安裝ICS(Internet Connection Service__}}}  <<toBalaFlashPlayer "flash/3-1-InstallICS.swf" "有影片有真相" "800" "620">> 
*在NAT主機額外新增一張網路卡, 一張網卡指定 Host-only, 另外一張設定為 Bridged
*Bridged模式的網卡開啟ICS(__I__nternet __C__onnection __S__haring)功能, IP設定為實體主機相同網段的設定
**此主機視為網路設備, DNS不須指向 DC主機IP位址
*Bridged網卡開啟ICS之後, Host-only網卡會自動設定IP為''192.168.0.1'', 並提供簡易的DHCP功能
**在VMWare前端電腦設定自動取得IP之前必須將VMWare之VMnet1的DHCP功能關閉, 不然前端將會一直取得VMnet1所提供的IP, 而無法順利的加入網域

!Domain Controller 安裝準備
{{item1{__dcpromo安裝前 - 1__}}}  <<toBalaFlashPlayer "flash/3-1-ADsetup-1.swf" "有影片有真相" "800" "620">> 
{{item1{__dcpromo安裝前 - 2__}}}  <<toBalaFlashPlayer "flash/3-1-ADsetup-2.swf" "有影片有真相" "800" "620">> 
*DCpromo 安裝前先準備好DC主機的環境, 將固定IP、電腦名稱、網域名稱設定正確及DNS指向DC主機本身的IP

!Domain Controller 架設
{{item1{__dcpromo安裝過程__}}}  <<toBalaFlashPlayer "flash/3-1-DCinstallation.swf" "有影片有真相" "800" "620">> 
*''安裝過程須作業系統原版光碟, 或複製光碟內 i386\ 至硬碟內''
*''正式安裝前必須確認各項設定(IP、電腦名稱、網域名稱、群組名稱)正常''
*在步驟5時, dcpromo仍然在尋找目前的 Master_Browser, 亦即: 當Domain建立失敗時會再度退回工作群組網路環境。
*Database / Log folder預設皆為 C:\%windir%\NTDS\
**''NTDS\ntds.dit'' 存放的資料為AD資料庫
*SYSVOL預設為 c:\%windir%\SYSVOL\
**SYSVOL 資料夾存放的資料為system volume, 用來設定前端電腦的機碼資料庫
**''SYSVOL 內的資料一旦被破壞, 前端機器將全毀''
*NTDS/SYSVOL 資料庫建議使用Mirrored動態硬碟作為容錯
*步驟9 Permissions設定頁中, 若選擇上面的選項『Permissions compatible with pre-Windows 2000 server operating system』, 匿名者將能讀取AD資料庫內容, ''《資安零分》''
**若前端機器仍有少部分作業系統版本早於Windows 2000, 則依然選擇第二項Permissions compatible only with Windows 2000 or Windows Server 2003 Operating Systems』, 舊版windows則後續手動設定, 使其加入工作群組。
**若大部分前端電腦版本早於W2k, 選擇第一項即可, 反正如何設定資安都是零分。

!檢視 DC 功能
{{item1{__DC安裝完成後__}}}  <<toBalaFlashPlayer "flash/3-1-afterDCinstallation.swf" "有影片有真相" "800" "620">> 
*安裝過程重新開機後必須隨時點選事件檢視器, 以確認安裝過程沒有出現錯誤
*DC安裝完成後在事件檢視器(event viewer)中會多出三項:
##Directory Service : \NTDS\ AD資料庫服務
##DNS Server : AD必須依賴DNS service完成, 因此安裝DC同時也將DNS Server架設完成
##File Replication Service : \SYSVOL\ 機碼資料庫
***當DC不只一台時, AD資料庫同步依賴 Directory Service, system volume(機碼資料庫)依靠 File Replication Service

!DC 時間同步
{{item1{__手動指定時間伺服器IP__}}}  <<toBalaFlashPlayer "flash/3-1-setatimeserverIP.swf" "有影片有真相" "800" "620">> 
*DC 時間同步靠的是 Internet 上的一部''時間伺服器''
*AD系統中最重要的兩個因素: 時間同步伺服器、DNS Server
**兩台DC間時間不能同步: AD資料庫掛點
**DC與前端時間不同步: 前端電腦無法登入Domain
**憑證系統工作異常
*以下節錄自土芭樂老師講義
{{{
c:\>net time  /querysntp                     // 檢視系統所設定的 Time Server

c:\>net time  /setsntp:207.46.130.100

c:\>net time  /setsntp:                        // 取消設定 Time server

* 207.46.130.100 是 time.windows.com 的 IP address, 因 DC 在啟動時 W32time 服務比 DNS 服務先啟動, 以至於以 “time.windows.com” 名稱連接無法成功
}}}
!群組原則
*為了方便集中管理,且強制的集中管理
*讓管理員經由一次指定,即可將相同的工作環境組態或限制,強制的應用在多部電腦或使用者上
*僅能使用在 Windows 2000 以上的作業平台
*若有 Windows 2000 前版的機器需使用系統原則 (System Policy) - Config.pol 與 NTconfig.pol
**一旦設定,變更困難,需重新更改機碼資料庫
**沒有 autorefresh 的機制,因此只有在開機的時候與使用者登入的時候能套用新的設定
**可以設定的系統原則只有在機碼資料庫相關的組態,不是機碼資料庫的內容無法變更修改
*現行的 GPO 只存在某個機碼資料庫的特定 key

!管理範疇
*管理範本
*軟體安裝維護:可以透過 GPO 強迫軟體的安裝、移除、升級
*各項指令檔 (scripts):支援使用者登出登入的指令檔,以及機器開關雞所需要的指令檔
*安全性設定
*目錄重新導向 (Folder Redirection),將使用者經常使用的目錄重新導向到網路上特定位置,例如: My documents

!群組原則管理工具
*群組原則原始工具分散在 AD 使用者及電腦、AD 站台及服務
*安裝下載 gpmc.msi
*GPMC 優點:
**單一介面管理多個樹系、網域、站台下的 GPO
**支援額外的管理功能
***備份、還原群組原則物件
***匯入、出群組原則物件
***複製與貼上群組原則物件或 WMI 篩選
***產生 HTML 報表
****原始工具透過:MMC 原則結果組
***允許程式化管理
***提供搜尋 GPO 功能

!群組原則物件 (GPO)
*GPO 是一堆強制性應用在電腦或使用者的設定規則
*每個 GPO 會有一個唯一的名稱,這個名稱會以一個 128 位元的數字 (GUID) 表示
*GPO = GPC + GPT
*儲存位置
**GPC:是一個 AD 物件,儲存在 AD 資料庫中  <<toBalaFlashPlayer "flash/10-GPC.swf" "有影片有真相" "800" "620">> 
***儲存在 system → policies (開啟進階功能檢視)
***包含 GPO 的版本訊息,狀態資訊 (enable, disable),元件清單,WMI 篩選資訊
**GPT:放在 SYSVOL 內的階層式資料夾結構  <<toBalaFlashPlayer "flash/10-GPT.swf" "有影片有真相" "800" "620">>
***儲存所有相關設定的組態

!群組原則實務
*新增 GPO (create unlinked GPO) <<toBalaFlashPlayer "flash/10-create_unlinked_GPO.swf" "有影片有真相" "800" "620">> 
*編輯 GPO
*連結 GPO  <<toBalaFlashPlayer "flash/10-link_GPO.swf" "有影片有真相" "800" "620">> 
**對象:Container Objects (Sites、Domain、OU)
**套用後,在這個 Container Objects 內的機器或是使用者將被強制的套用這個 GPO 的設定
**GPO 套用可多對多,多個 GPO 套用在多個 Container Objects 中

!群組原則應用規則
*群組原則的套用順序 - LSDOU~~SOU~~
**L:Local → S:Site → D:Domain → OU → sub OU
**如果前後 Link 的 GPO 有衝突,後面會覆蓋前面的
*繼承原則 (Inheritance):上層 Container 連結的 GPO,將會自動套用到下層的 Subcontainer
**例外:套用在網域中的 GPO,將不會被子網域所套用
**管理員在必要的時候可以禁止繼承原則 (Block Inheritance) <<toBalaFlashPlayer "flash/10-block_Inheritance.swf" "有影片有真相" "800" "620">> 
***啟用後所有來自上層的所有 GPO 都會被阻擋,包含整個網域的 GPO 亦然
*累積原則 (Cumulative)
**只要上下層的 GPO 不衝突,則下層的使用者將呈現累積的效果
*內層的群組原則設定若與外層的群組原則產生衝突,則內層將會覆蓋外層的
*假設上層管理員要確保他的 GPO 一定生效,則必須啟動 不複寫 (No Override) 或 強制 (Enforce) 原則
**將會覆蓋 Block Inheritance 與衝突被下層覆蓋的原則
*排除原則 (Exclusion):過濾群組原則物件 (Filtering GPO)
**權限篩選:Windows 2000 時代僅有權限篩選可選擇
**WMI 篩選
***微軟設計的一組非常強悍的程式介面,可透過系統資訊篩選出所需要的物件

!!系統管理範本
*一個特殊的文字檔案『 *.adm 』,存放在 %systemroot%\inf 內
*系統管理範本中一個選項對應到登錄資料庫一項或是一項以上的 key 與 value
*新增系統管理範本:將應用程式提供的 adm 檔複製到『每一台』DC 的 %systemroot%\inf 內

!!GPO 設定
*尚未設定:這個 GPO 不設定此項設定,看其他 GPO 有沒有設定
*啟用
*套用
*控制台內每一個控制選項都是一個 Applet (.CPL) 檔案
**隱藏控制台小程式需指定要隱藏的 .cpl 檔案

!排除篩選
!!透過權限篩選 <<toBalaFlashPlayer "flash/10_GPO_exclusion_by_permission.swf" "有影片有真相" "800" "620">> 
*針對要排除的 GPO 的 ACL 做權限上的適當修改
*做法1:移除 authenticated users,並加入要套用這個 GPO 的使用者或群組,其他人則不會套用
*做法2:直接加入要排除的使用者或群組,並勾選『拒絕』套用群組原則
!!WMI 篩選器 <<toBalaFlashPlayer "flash/10-WMI.swf" "有影片有真相" "800" "620">> 
*Windows Management Instrumentation
{{{
select * from Win32_OperatingSystem where Caption = "Microsoft Windows XP Professional"
}}}
**大小寫不分,雙引號內大小寫區分

!了解並變更群組原則的預設處理方式
*重新整理間隔時間 (refresh interval)
*指定用來維護 GPO 的網域控制站
*回送處理 (loopback processing)
*低速連線處理

!!變更重新整理時間
*舊的 System policy 必須在使用者重新登入及系統重新開機時才會生效
*AD 環境下,DC 每隔 5 分鐘 refresh,Non-DC 為 90+Random(0~30) 分鐘
*變更 refresh 時間
**針對 Default Domain policy
***系統管理範本
****系統
*****群組原則
******電腦群組原則更新的間隔
*******網域控制站群組原則更新的間隔
*軟體安裝、目錄重新導向 @@color:red;不會 refresh@@

!!GPUPDATE
*用戶端指令
*/force:強制下載所有 GPO 重新套用
*/target:computer or user:指定套用機器原則或是使用者原則,不指定代表兩者

!!回送處理模式
*目的在確保電腦設定 GPO 的設定一定生效,而不會被使用者設定所取代
*當初設計的主要考量在軟體安裝功能
*範例
{{{
當電腦設定中軟體安裝,其中一項原則:老舊的電腦不安裝 Office 2007,而使用者設定中,會計部門的使用者要安裝 Excel 2007,因 GPO 套用原則為開機後套用電腦設定,登入後套用使用者設定,因此若有會計部門人員在老舊的登入,仍會執行 Excel 2007 的安裝,為了解決這個問題,則需啟用 Loopback processing 機制
}}}
*取代:只處理應用到電腦設定的 GPO
*合併:先處理使用者設定,再處理電腦設定的 GPO

!!低速連線 (slow link) 處理
*預設
*若開機時,開機的電腦與 DC 間的連線速率低於 500Kbps,則進入低速連線模式
*低速連線模式只下載套用兩個部份設定,且無法被取消:
**登錄資料庫設定 (管理範本)
**安全性設定
***EFS 修復設定
*變更、重新定義低速連線
**微軟的做法是在開機時會對 DC ping 10 次,來測量彼此間的連線速率
**針對 Default Domain policy
***系統管理範本
****系統
*****群組原則
******群組原則低速連結偵測
******《optional》指令碼原則處理、資料夾重新導向原則處理、......
{{item1{__變更低速連線處理__}}}  <<toBalaFlashPlayer "flash/10-change_slow_link_handle.swf" "有影片有真相" "800" "620">> 

!指定管理群組原則的網域控制站  <<toBalaFlashPlayer "flash/10-change_GPO_PDC.swf" "有影片有真相" "800" "620">> 
*預設使用 PDC 模擬器,通常為網域中第1台 DC
**避免兩個具有相同權限的管理員針對同一個 GPO 做修改
*建議修改為與 GPO 管理員最接近的 DC

!管理 GPO
*複製 / 貼上  <<toBalaFlashPlayer "flash/10-GPO_copy_and_paste.swf" "有影片有真相" "800" "620">> 
*備份 / 還原:僅能在同一個網域才能還原  <<toBalaFlashPlayer "flash/10-GPO_backup_and_restore.swf" "有影片有真相" "800" "620">> 
*備份 / 匯入:可以匯入到不同網域,但僅能匯入到一個已存在的 GPO(不會建立 GPO)  <<toBalaFlashPlayer "flash/10-GPO_backup_and_import.swf" "有影片有真相" "800" "620">> 
**匯入至不同樹系時,管理者必須有目標樹系的管理權限,必須建立信任關係,方向為何,實驗中...

!!刪除 GPO
*永久刪除:在群組原則物件中刪除
*刪除連結關係:在 Container object 刪除,原有的 GPC 與 GPT 仍然存在
!!停用 GPO
**啟用
**停用所有設定
**停用電腦組態設定
**停用使用者組態設定
*若該 GPO 沒有電腦或使用者組態設定,可將其停用
*或是有特殊情況需要暫時停用 GPO 設定時 <<toBalaFlashPlayer "flash/10-GPO_temp_disable.swf" "有影片有真相" "800" "620">>

!搜尋 GPO
{{item1{__搜尋 GPO__}}}  <<toBalaFlashPlayer "flash/10-GPO_search.swf" "有影片有真相" "800" "620">> 

!GPO 的委派工作
*創造 GPO  <<toBalaFlashPlayer "flash/10-GPO_create_delegation.swf" "有影片有真相" "800" "620">> 
**委派對象需加入 Group Policy Creator Owners
*連結 GPO  <<toBalaFlashPlayer "flash/10-GPO_link_delegation.swf" "有影片有真相-1" "800" "620">>  <<toBalaFlashPlayer "flash/10-GPO_link_delegation-2.swf" "有影片有真相-2" "800" "620">> 
**要針對已存在的 GPO 對 Container object 套用,委派對象必須對於 Container object 擁有進階中的內容:gPLink、gPOptions 給予 讀取 及 寫入 的權限
**透過委派控制精靈較簡單
*編輯 GPO  <<toBalaFlashPlayer "flash/10-GPO_edit_delegation.swf" "有影片有真相" "800" "620">> 
**針對特定 GPO 給予委派對象 讀取 及 寫入 的權限
*WMI 篩選器委派  <<toBalaFlashPlayer "flash/10-WMI_create_delegation.swf" "有影片有真相" "800" "620">> 
**創造 WMI 篩選器的委派權限:完全控制(可針對所有 WMI 修改、刪除)、創造者擁有(僅能針對自己創造的修改、刪除)
**特定的 WMI 篩選器的委派權限:編輯(只能編輯不能刪除)、完全控制(可編輯可刪除)

!群組原則診斷工具
*MMC 嵌入式管理工具 - Result Set of Policy (RSOP) 原則結果組  <<toBalaFlashPlayer "flash/10-GPO_troubleshooting_RSOP.swf" "有影片有真相" "800" "620">> 
**Logging mode 紀錄模式 (gpmc.msc 中的群組原則結果)
***實際連上機器,列出目前執行 GPO 的結果為何
**計劃模式 (gpmc.msc 中的群組原則模型)
***找 DC 來模擬,並未實際偵測機器
!!群組原則結果  <<toBalaFlashPlayer "flash/10-GPO_group_policy_result.swf" "有影片有真相" "800" "620">> 
*目標電腦必須開機狀態
*gpmc.msc 中群組原則結果的設定頁面僅顯示有效的設定
**RSOP 則顯示所有的設定
*針對已經查詢過的電腦,如果有更新的 GPO,不需要再次啟動精靈,直接重新查詢即可
!!群組原則模型 <<toBalaFlashPlayer "flash/10-GPO_group_policy_module.swf" "有影片有真相" "800" "620">> 
*根據所選擇的使用者所屬的 container object 與所選擇的電腦所屬的 container object,推算出套用的群組原則,並非實際找這部機器
!!命令列指令
*gpresult /v:verbose
*Windows 2000 以後的機器,win2000 在 support tool 內, winXP 及 2003 預設安裝即有
*用戶端指令
*gpresult /z:包含值裏面的二進位資料
*AD 資料庫與交易紀錄檔
**ntds.dit:AD 資料庫檔案、儲存所有 AD 物件
**edb*.log:交易紀錄檔
**edb.chk:檢查點紀錄檔,紀錄目前有幾筆資料尚未寫入至資料庫中,(檢查交易紀錄檔有哪些動作尚未寫入資料庫檔案)
**res1.log、res2.log:保留做在交易紀錄檔尚未寫入資料庫時,空間不足但物件卻已修改刪除新增時的窘境

!AD 資料修改流程
#修改要求
#起始交易
#寫入交易暫存區 → 寫入交易紀錄檔 (edb.log)
#修改資料庫檔案 (ntds.dit)
#確認交易
#更新檢查點 (edb.chk)

!DC 間的複寫機制
*Multi-Master replication with loose convergence model
**Multi-Master:多台 DC 皆可為複製來源
**Loose convergence:寬鬆收斂機制,有時間的延遲
*收斂時間與網路流量的取捨
**收斂時間越短越好
**網路流量越小越好
!!目錄複製
*複製 AD 內物件
!!檔案複寫服務 (FRS, File Replication Service)
*複製 SYSVOL

!!站台內複寫(Intrasite replication)與站台間複寫(Intersite Replication)
*Replication within site 站台內,在同一個站台內的 DC 彼此互相複寫
**使用變更通知的方法 (change notification),300/30(@Windows 2000 mode),15/3(@Windows 2003 native mode)
***300 / 30:管理員新增一個物件後,300 秒後開始通知第1台 DC,間隔 30 秒後通知第2台,再間隔 30 秒後通知第3台
***15 / 3:管理員新增一個物件後,15 秒後開始通知第1台 DC,間隔 3 秒後通知第2台...
**假設為高速穩定的網路連線
**不會壓縮複寫流量
**支援緊急複製 (Urgent replication)
***當某一台發生安全性敏感度極高的事件時,會直接通知其他 DC,不用等待 300 或是 15 秒
****例如:某帳號被鎖定(lockout)、管理員變更使用者密碼、機器的重設帳戶、......
*Replication between sites 站台間,在不同的站台間的 DC 彼此互相複寫
**假設站台間有限頻寬且不穩定
**自訂複寫排程 (custom schedule)
***最短 15 分鐘,最長 10080 分鐘(七天)
**當複寫流量超過 32K,將會壓縮
**不支援緊急複製
*站台內複寫的機制:減少收斂時間
*站台間複寫的機制:減少網路流量
*改變變更通知的預設間隔時間
**每一部 DC 都需要變更
{{{
KKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\NTDS\Parameters
}}}

!!資料庫複寫衝突問題
*由於 Multi-Master,每一部 DC 皆為可複製來源因此有可能兩個管理員分別在兩台 DC 修改相同內容,則變更通知時可能產生複寫衝突
*常見的資料庫衝突:
**屬性值產生的衝突
**刪除容區產生的衝突
***例如,管理員A 在 OU-A 中新增一個使用者帳戶,而管理員B同時刪除 OU-A
**RID 名稱的衝突
***例如,在 RD OU有一個顯示名稱為張三的使用者,而管理員A 將張三移動至 MIS OU,則此時管理員B 在 MIS OU 新增了另外一個張三的使用者帳戶,則在 MIS OU 內的張三將代表誰?
*解決方法
**AD 資料庫複製基本單位為屬性而非物件
**維護 Globally unique stamp (版本數version、timestamp時間戳記、伺服器的 GUID)
***先比較版本數、再比較時間戳記、最後比較 GUID
**LostAndFound:提供解決刪除容區產生的衝突問題,前面的例子當新增的使用者帳戶所屬的 OU 同時被刪除,則創造的使用者會出現在 LostAndFound 中 (需開啟進階檢視)

!AD 的複製拓樸
*不同的資料庫 Partition 產生不同的複製拓樸,4個 Partition 都有不同的複製拓樸
*每一部 DC 開機執行第一次 KCC,開機後每 15 分鐘再執行一次 KCC,
*雙向環狀
**雙向:當變更通知發出時,收到通知的 DC 也會在 300(windows 2000) / 15(Windows 2003 秒後通知原先發出變更通知的 DC
*不能超過3個轉送站

*因為複製拓樸三個轉送站限制
**Windows 2000 模式下,重大變更可能在 15 分鐘後生效 (300 秒 X 3 台 DC)
**Windows 2003 模式下,僅需 15 秒 X 3 = 45 秒
!站台規劃與實務管理步驟
*管理員需事先蒐集企業內所有子網段,及網路資訊(頻寬、擁塞與否等等)
#規劃並建立所有站台名稱  <<toBalaFlashPlayer "flash/12-create_sites-1.swf" "有影片有真相" "800" "620">> 
**建立站台僅 Enterprise Admins 群組有權限
**依據高速且穩定與否的網路決定站台設計
**預設一個站台:Default-First-Site-Name,大部份都會刪除重新創造或是重新命名
#定義站台(創造子網路物件並連結至特定的站台)  <<toBalaFlashPlayer "flash/12-define_sites-2.swf" "有影片有真相" "800" "620">> 
#(最重要)創造站台連結 (create site link)  <<toBalaFlashPlayer "flash/12-create_site_links-3.swf" "有影片有真相" "800" "620">>  
**定義不同站台間如何複製及各項參數
**5個重要參數
###Site member 站台成員
###通訊協定
****RPC ~~over~~ IP
****SMTP
###傳輸成本
****使用此連結的成本,為站台連結的相對比較值
****預設 100,(1 ~ 99999)
****主要線路成本需比備援線路成本低,內定上選擇成本低的線路使用,在成本低的線路不通才會使用成本高的線路
###@@color:red;複製間隔 (interval)@@
****預設 180 分鐘,15 分鐘 ~ 10080 分鐘 (七天)
###@@color:red;允許複製時段 (schedule)@@
****避開網路使用巔峰時段
****不同時區的站台間,經過時差換算後,兩邊至少要有一個小時允許複製才能處理站台間的複製
*****例如,若設定 台北-紐約 間的站台連結,不允許早上6點至下午6點的站台複製,則此兩個站台間將永遠都不會複製
**@@color:red;建立好連結後記得刪除預設的連結@@  <<toBalaFlashPlayer "flash/12-create_site_links-3-2.swf" "有影片有真相" "800" "620">> 
#如有必要可創造站台連結橋接器 (並非可自由轉送的網路環境,例如透過封包過濾的防火牆,無法使網路流量遶送)  <<toBalaFlashPlayer "flash/12-create_sitelink_bridge-4.swf" "有影片有真相" "800" "620">> 
**擁有相同站台及相同協定的多個站台連結會自動產生站台橋接
***站台成員中有共同的站台,且使用的通訊協定相同時,會自動產生站台連接橋接器 (sitelink bridge)
****成本:累加
****間隔:累加
****排程:sitelink1 與 sitelink2 排除的時段,在自動產生的站台連接橋接器會自動排除
##先取消橋接所有站台連結的功能(預設打勾)
#設定喜好的 BridgeHead 伺服器(preferred bridge head server)  <<toBalaFlashPlayer "flash/12-preferred_bridge_head_server-5.swf" "有影片有真相" "800" "620">> 
**站台內多部 DC 中一部(以上)特別的 DC
***一個 Domain 一部 Bridge Head server,因此若一個站台涵蓋多個網域,則每個網域都各自有一個 BHS
***專門負責執行跨站台的複寫工作
**無法直接指定橋頭伺服器,需透過 @@color:red;站台間拓樸產生器 (ISTG, Inter Site Topology Generator)@@
***ISTG 用來定義站台間的複寫拓樸與決定橋頭伺服器
***預設上每個站台內的第一部 DC 為 ISTG
***若一段時間內連絡不上,則透過自動的遴選機制選出新的 ISTG
***管理員無法手動指定,只能觀察目前哪部 DC 是 ISTG  <<toBalaFlashPlayer "flash/12-whois_ISTG.swf" "有影片有真相" "800" "620">> 
***檢查複寫拓樸
****檢查 KCC process 是否正常執行,必要時強制重新執行
**管理員選擇喜好的的 BH 伺服器條件
***本身效率較高的 DC
***容易通過防火牆 (例如:Proxy)
***本身無提供其他服務且負載較輕的 DC
**微軟說法:要選則選兩部以上,不然就不選
#搬移既有的伺服器物件至正確站台下
**若先完成了 AD 的邏輯結構才開始站台設計,則預設上所有的 DC 都落在 Default-First-Site-Name 內,因此需要將已存在的伺服器物件搬移至正確的站台下
**正確做法應該是,當第一台 DC 架設完成就開始做站台設計,後續加入的 DC 將依據其 IP 位址落在正確的站台下
#規劃伺服器 (DC、GC、DNS)數量與位置

| RPC~~over~~IP | SMTP |
|同步(Synchronious)傳送|非同步傳送<br> - Store and Forward|
|適用於穩定網路環境|適用於不穩定網路環境|
|使用上無限制,所有資料皆可傳送|使用上有限制<br> - 不能用在相同網域內或相同站台內的 DC 複製<br> - 只能用在 Schema、Configuration 和 Global catalog 三部份資料的複製|
|防火牆不易設定 (動態 Port)|通過防火牆設定較容易|
*當網路不通,或無法傳遞,SMTP 將會儲存在 Queue 中,過一段時間再送,而 RPC 則需等到下次同步的時候才會再送

!Connection Object 與 手動複製
*一個 Connection Object 就是兩部 DC 間 @@color:red;單向@@ 複製的途徑  <<toBalaFlashPlayer "flash/12-connection_object.swf" "有影片有真相" "800" "620">> 
**兩部 DC 之間應該會有兩個 Connection object
*Connection Object 通常會自動產生,在網路上的兩部 DC 曾經相互複製過,則一定會存在兩個 Connection Object
*Connection Object 可用來執行手動立即複製
*在目地端的伺服器物件下的 NTDS settings 執行複製動作

!全域群組成員快取功能
*使用者登入網域時,需依序向 DNC、DC、GC 連線,才能建立正確的 Access token
*內定第一部 DC 為 GC,因此使用者登入時,常會遇到連不到 GC 而無法登入的問題而無法產生 Access token
*解決方法: <<toBalaFlashPlayer "flash/12-global_group_membership_cache.swf" "有影片有真相" "800" "620">> 
**由 GC 維護一份資料,定期傳送至 DC 的快取區
**使用者只需向 DNS 查詢最近的 DC 位置,透過 DC 的快取區即可產生正確的 Access token,不再需要向 GC 查詢萬用群組成原的資訊
*需 Windows server 2003 網域功能等級
**預設不啟用
*啟用快取功能後,DC 每隔 8 個小時自動更新
!!Windows 2000 
*如存在 Win 2000 的 DC,需要停用使用者登入時需要 GC 伺服器這項功能需設定下列登錄資料庫
{{{
HKEY\System\CurrentControlSet\Control\Lsa
新增一個 Key 為 IgnoreGCFailures
重新開機
}}}
*但使用者登入後的 Access token 將沒有萬用群組的資料,需透過萬用群組存取的資源將會失敗

!伺服器 (DC、GC、DNS)數量與位置
*每個站台至少一部 DC、GC、DNS 伺服器
*若需要提供容錯能力架設一部以上的伺服器

!GC (Global Catalog) 通用目錄
*儲存整個 AD 樹系下每個物件的部份屬性
*提供樹系內資源的查詢服務
*提供使用者登入時身份驗證的必要資訊,因通用目錄負責儲存管理萬用群組,及 UPN 尾碼
*預設上只有樹系內第一部 DC 為 GC,爾後管理員可視需要增加  <<toBalaFlashPlayer "flash/12-create_2nd_GC_server.swf" "有影片有真相" "800" "620">> 
*若樹系內僅有一個網域,強烈建議所有 DC 都設為 GC

!DC
*佈署位置
**與使用者數量有關
**是否架設 @@color:red;站台認知的應用程式 (site-aware application)@@:如 exchange server 2003
**當 WAN 連線中斷時,仍可以存取到網路資源
***設定 DC 為 GC
***啟用萬用群組成員快取功能
*佈署數量
**與使用者數量有關
**效能
**容錯能力

!AD 複製診斷工具
*圖形介面
**Replication Monitor (replmon)
***Support tool 內
*命令指令
**Repadmin

!!Replication Monitor  <<toBalaFlashPlayer "flash/12-replication_monitor.swf" "有影片有真相" "800" "620">> 
*設定自動更新時間間隔
*加入要監控診斷的那一部 DC 或多部
*畫面表示目前 AD 資料庫的不同分割區的上一次複製結果
*可針對複製的對象直接同步處理資料庫 <<toBalaFlashPlayer "flash/12-manually_synchronize_with_replication_partner.swf" "有影片有真相" "800" "620">> 
*設定複製失敗超過門檻數後進行通知
**View → Options
***要使用 Notification Options:Send mail to AD 環境內必須架設 Exchange server
*顯示目前哪些物件尚未被複製
**show Retired Replication Partners、Show transitive replication partners 兩個選項必須打勾
**check USN & un-replicated objects
*顯示複製拓樸、複製伙伴、GPO
**四部以上才有意義
*顯示 Domain 目前的 GPO
*顯示樹系內的 GC server
*顯示 Bridge Head server:至少要 site-to-site replication 過才會顯示
*手動複製
**Disables transitive replication (站台內):手動立即複製到相鄰的
**Push mode (站台內):直接複製資料到其他機器
***全世界的資料庫複製都分為 Pull / Push,微軟 AD 資料庫採用 Pull mode:當自己的資料變更,通知其他機器來抓取資料
**Cross site boundaries:跨站台的複製
*檢查並觸發 KCC 是否正常執行
**Check Replicatin Topology:檢查這部 DC 是否正常執行

!設計 AD 複製通過防火牆
*問題
**AD 使用 RPC 協定進行複製,而 RPC 採用動態連接埠 (TCP 1024 ~ 65535
*解決方法
**在所有 DC 設定 RPC 與 FRS 使用固定連接埠
**購買支援 RPC 應用層篩選器的防火牆 (例如 ISA 2004 / 2006)
*做法:變更下變登錄值
 1. 設定 AD 複製使用靜態的 RPC 連接埠
>HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\NTDS\Parameters
>值名稱:TCP/IP Port
>資料類型:DWORD
 2. 設定 FRS 複製時使用靜態的 RPC 連接埠
>HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\NTFRS\Parameters
>值名稱:RPC TCP/IP Port Assignment
>資料類型:DWORD
 3. 重新啟動 DC
 4. 放行下列表格的連接埠
*操作主機
**一部被特別指定的網域控制站,專門用來變更資要庫內特殊的資料,以避免衝突現象的發生

!操作主機的角色
*每一樹系角色 (per-forest role)
**架構主機 (schema master)
**網域命名主機 (Domain Naming master)
*每一網域角色
**相關 ID 主機 (RID Master)
**PDC 模擬主機 (PDC Emulator)
**基礎結構主機 (Infrastructure master)

!!架構主機 (Schema master)
*架構 (Schema) 定義允許存放在 AD 資料庫的物件類別與屬性
*樹系內必須設置唯一的一部架構主機,管理員必須至少是 Schema Admins 群組成員
*工具 regsrv32 schmmgmt.dll:mmc 嵌入式管理單元
*僅能新增不能刪除
*範例:新增使用者帳戶一個屬性:薪資資料
**X.500 OID (Object ID):若要在 Internet 上使用需向 ISO 申請
***SNMP:網管協定
**決定是否複寫至 GC
*若架構主機損毀,則無法新增修改架構

!!網域命名主機 (Domain Naming master)
*負責執行 AD 樹系內的網域新增、刪除變更動作
*樹系內唯一一部網域命名主機
*若網域命名主機損毀,則無法新增、刪除網域

!!PDC 模擬主機 (PDC Emulator)
*五部操作主機中被視為最重要的一部
*用來扮演早期 NT 網域環境內的 PDC
*主要功能:
##降低使用者變更密碼的時間延遲
##可讓 Windows 9x 等老舊機器變更網域密碼
##在 Mixed Mode 下支援 NT 的 BDC 執行資料庫複製
##@@color:red;提供時間同步的對時服務:Time Service@@
***網域內所有非 PDC 模擬主機的機器 (DC、MS、WS) 皆會每隔固定時間向 PDC 模擬主機對時
***樹系內所有 PDC 模擬主機每隔固定時間皆會向第一個 PDC 模擬主機對時
***NTP 使用 UDP:123,防火牆需放行第一台 PDC 的 UDP:123
****UDP:123 全開有遭受攻擊的危險
***GPO Kerberos 原則中,設定最大時間容許的誤差,預設 5 分鐘
##扮演管理、變更 GPO 的主要機器
*當 PDC 模以主機損毀,將造成許多問題
**使用者變更密碼的套用時間延長
**Windows 9x 老舊機器將無法變更網域密碼
**Mixed Mode 下將不支援 NT 的 BDC
**樹系內機器的時間將開始有誤差
***導致使用者可能無法通過身份驗證
**GPO 原則變更時可能產生衝突

*手動對時
{{{
net time \\srv-cht-dc2
}}}

!!相關 ID 主機 (RID Master)
*SID = S - Domain ID - RID
*不同的安全性主體其 RID 必須唯一
*RID Master 分配 512 個 RID 的可用範圍給每一台 DC,使得各 DC 創造安全性主體的時候的 RID 不會有重複的現象
*短時間內 RID master 毀損不受影響

!!基礎結構主機 (Infrastructure master)
*主要用來維護本網域所參考到其他網域物件,其名稱或 ID 資訊的一致性
**例如:群組中加入的其他網域的成員,而該成員所屬的網域管理員將該成員重新命名並不會通知其他網域,而透過 基礎結構主機 維護其一致性
*基礎結構主機通常不會存在通用目錄伺服器,除非只有一個網域
**若基礎結構主機本身為 GC server,則基礎結構主機的功能將會失效

!預設操作主機
*樹系內第一部 DC 為預設架構主機及網域命名主機
**控制 網域命名主機 角色使用 AD domain and trust
**控制 架構主機 角色使用 AD schema
*網域內第一部 DC 為預設的相關 ID 主機、PDC 模擬主機、基礎結構主機
**控制 Domain Role 角色使用 AD users and computers

!移轉操作主機
*管理員基於效能或其他考量,可以移轉操作主機的角色
*移轉角色時,原操作主機則會停用其角色
*移轉不同操作主機角色所需權限
**移轉3個 Domain Role 角色:Domain admins 群組
**移轉架構主機:Schema admins 或 Enterprise admins 群組
**移轉網域命名主機:Enterprise admins 群組
*需先連線至要移轉目標的網域控制站才能進行移轉

!強制轉換 (seize, 捉拿;扣押) 操作主機角色
*若原操作主機當掉、發生意外且再也無法回到線上扮演其角色,則需執行強制轉換作業
*短期不在線上不需強制轉換
*ntdsutil
{{{
ntdsutil
roles
connetions
connect to server srv-en-dc2.itdep.flatfish.local
//連線到要當操作主機的機器
quit
seize RID master
seize PDC
seize infrastructure master
seize naming master
seize schema master
//選擇要強制轉換的操作主機
quit
quit
}}}
*備份 (Backup)
*還原 (Restore)
*搬移 (Move)
*離線重組 (Offline Defragment)

!!垃圾蒐集機制 (Garbage Collection)
*微軟幫 AD 資料庫自動維護的工作
#每 12 小時執行線上重組
**提升物件存取效率,將物件的屬性擺回連續的位置
#刪除超過一定天數的 tombstoned 紀錄,以便把先前刪除的資料真正的從 AD 資料庫刪除
**刪除物件只是在物件的 tombstoned 屬性上 enable
**避免殺不掉的物件
**維護一個足夠常的時間,在網路上通知其他 DC 該物件被刪除
*管理員透過 adsiedit 僅能變更上述兩個時間間隔
**GarbageCollPeriod:內定不設 12 (小時)
**tombstoneLifetime:180 (天) (Windows server 2003 service pack 2)

!!備份 AD 資料庫
*管理員並無單獨備份 DC 的 AD 資料庫
*需使用微軟的備份工具來備份整個 System state
*或透過 Third-party 備份工具

!!還原 AD 資料庫
*Primary 還原
**重建第一部 DC
**網域中僅有一部 DC,不會尋找網路中其他 DC 複製資料
*Normal 還原
**還原後重新開機,會與網路上其他 DC 進行複製
*@@color:red;Authoritrative 還原@@
**資料庫還原後,以還原的機器為資料庫主要來源,來覆蓋其他 DC 的資料庫
**通常用在管理員不小心刪除 AD 資料
#重新啟動電腦,開機後按下 F8 選擇進入目錄服務還原模式
**<<slider 強制修改目錄服務還原密碼 強制修改目錄服務還原密碼 強制修改目錄服務還原密碼 "">>
#使用備份還原工具
#預設為 Normal Restore
**當還原複寫資料組時,將還原資料標記為所有複寫的主資料:主要還原
**授權還原需先執行正常還原,再透過指定授權
***<<slider 授權還原 授權還原 授權還原 "">>

!!搬移資料庫
*基於效能與空間的考量
*<<slider 搬移資料庫 搬移資料庫 搬移資料庫 "">>

!!AD 資料庫重組
*線上重組
**由垃圾蒐集機制自動執行
**加速資料庫存取
*離線重組
**由目錄服務還原模式下執行 ntdsutil 工具手動執行
**加速資料庫存取
**降低資料庫大小
***只有離線重組可以回收沒用到的空間
{{{
ntdsutil
file
compact to c:\tmp
quit
quit
copy "c:\tmp\ntds.dit" "c:\windows\ntds\ntds.dit"
}}}

!資料庫維護原則
*適當規劃 AD 資料庫檔案與 SYSVOL 的位置
*定期檢查資料庫磁碟的可用空間
**若磁碟的可用空間不足,則 DC 會當機
*定期備份 AD 資料庫與 SYSVOL 資料夾
**每一部 DC 都需要單獨做
*定期重組資料庫,以降低資料庫的大小
*Root Domain 的 DNS forwarder 到 Internet DNS
*子網域 DNS forwarder 到上層
*上層網域 DNS 建議子網域委派給下層
*大原則:使用者所屬的 Domain 的 DNS 伺服器必須要能查詢的到整個樹系的 SRV 紀錄
!Client Join Domain (加入網域)
{{item1{__Client加入網域 - 1__}}}  <<toBalaFlashPlayer "flash/3-2-clientjoinDomain-1.swf" "有影片有真相" "800" "620">> 
{{item1{__確認前端系統是否在DNS上登錄註冊__}}}  <<toBalaFlashPlayer "flash/3-2-DNSregister.swf" "有影片有真相" "800" "620">> 
*設定前端電腦的DNS時, 也記得確定TCP/IP的''進階''設定中的DNS標籤頁, 下方的''在DNS中登錄這個連線網路的位址''是否有打勾, 如果沒有打勾將不會在DNS伺服器中登錄主機名稱與IP
{{item1{__Client加入網域 - 2__}}}  <<toBalaFlashPlayer "flash/3-2-clientjoinDomain-2.swf" "有影片有真相" "800" "620">> 
*加入網域時輸入的使用者名稱/密碼為 ''網域'' 內的使用者帳戶資料
**DNS設定正確時, 輸入完網域名稱後是''即刻''就會出現要求輸入使用者名稱密碼的畫面, 若過了很久才出現要求, 表示設定不正確, 又回到以工作群組網路的方式
*在Join Domain動作完成後, 會在AD資料庫中建立一個電腦帳號(Computer Account), 有帳號就有密碼, 該密碼由DC自己產生, 並通知該前端電腦, 因此在前端與DC中皆會儲存; 並且在固定時間後, DC會再次產生新的密碼並再度通知前端, 但是這中間過程仍有機率發生問題, DC產生新密碼, 但前端因關機等因素而沒收到新的密碼, 此後使用者無法再使用AD資料庫中的使用者帳號登入
**解決方法惟一: 前端電腦本機管理員登入, 退出Domain, 再度Join Domain
**或是事先取消密碼更新
*前端電腦Ghost還原必須注意Domain密碼更新問題
{{item1{__檢查前端是否已經完成加入網域__}}}  <<toBalaFlashPlayer "flash/3-1-checkclientregistertoDNSornot.swf" "有影片有真相" "800" "620">> 
*前端電腦加入網域後, 在登入畫面的選項開啟時, 畫面會在帳號/密碼欄位下方多出一個欄位: 登入網域或是本機登入
*整個網域中, 僅有DC在登入畫面時, 只有網域登入而沒有本機登入

!使用者將前端電腦加入網域的權限 → User Rights
*網域中的一般使用者與管理者帳號:
**一般使用者可以加入10台前端電腦
**管理者群組內的帳號沒有限制
{{item1{__限制一般使用者不能將Client加入網域__}}}  <<toBalaFlashPlayer "flash/3-2-limituserscanNOTaddworkstationstoDomain.swf" "有影片有真相" "800" "620">>
*取消一般使用者帳號將電腦加入網域的權限

!Pre-Staged Computer Account
{{item1{__預先建立電腦帳號__}}}  <<toBalaFlashPlayer "flash/3-2-Pre-stagedcomputeraccounts.swf" "有影片有真相" "800" "620">> 
*先建立一個管理電腦的 OU(__O__rganization __U__nit)
*企業內Domain的標準程序: 由管理者在DC預先建立的OU內新增''電腦帳號'', 再以管理者帳號將前端電腦加入網域
*因此, 在DC架設完成後內建的Computers container內是不會出現有其他''電腦帳號''的, 因為管理者該事先把要加入網域的電腦預先建立在自行規劃的OU內
**Pre-staged建立電腦帳號前端必須先退出網域
**若前端電腦沒有先退出Domain則會在該建立的電腦帳號上面出現紅標
**建立電腦帳號標準程序: 看到紅標先刪除該帳號, 重新產生新帳號, 重新加入網域

!退出網域 (回到工作群組網路)
{{item1{__退出網域__}}}  <<toBalaFlashPlayer "flash/3-2-quitaDomain.swf" "有影片有真相" "800" "620">> 
#本機管理者帳號登入
#我的電腦按右鍵選擇''內容''
#電腦名稱標籤頁選擇''變更''
#加入工作群組,再次輸入''網域''內的帳號/密碼
#重新開機, 完成退出網域動作
*俗稱''靠行''

!重設電腦帳號 (Reset Computer)
*''千萬不要執行 reset computer''
**[[微軟的兩光說明文件|http://support.microsoft.com/kb/216393]] 誰能告訴我這個功能到底是做什麼的啊啊啊啊!!!???
**不會重新設定密碼, 僅會中斷已加入Domain的前端電腦
**執行完只能再次退出/加入Domain
*以下摘錄自土芭樂老師講義
{{{
以 ''[IT 管理或對象觀點劃分]'' 當以管理的觀點來建立組織單位結構時,對所有擁有該組織單位的管理員來說是有利的。在 Active Directory 服務中,可以建立以對象觀點為基礎的組織單位,如使用者、電腦、應用程式、群組、印表機以及安全性原則等。

以 ''[地理觀點劃分]'' 該劃分方法可以建立一個包含每個地域的組織單位,它將形成一個永久、穩定的結構。但是,如果公司的組織結構出現重大變動時,就必須考慮其他多方面的因素來設定組織單位了。

以 ''[商業功能觀點劃分]'' 如果企業重視商業功能,可以按照不同的行政職能 (如市場部、IT 部以及行政部) 來劃分組織單位。即使該組織自身結構並不十分穩定,但它們對這些功能的需求卻是固定的。

以 ''[部門觀點劃分]'' 這種劃分方法的思路是建立一種能反映部門架構的組織單位。該方法能夠與當前組織相互對應,但是當組織重組時將非常不穩定。

以 ''[項目觀點劃分]'' 使用這一類型的組織單位模式是以項目為中心來考慮的。這種組織單位通常用來作為其他更穩定組織單位的下層結構。如果要採用這種類型,切記必須指定由誰來管理該組織單位。 
}}}

{{item1{__建立一個屬於taipei部門的OU__}}}  <<toBalaFlashPlayer "flash/3-4-createaOUforlaba-taipeidepart.swf" "有影片有真相" "800" "620">> 
!新增使用者帳號
{{item1{__在網域中新增一個使用者帳號__}}}  <<toBalaFlashPlayer "flash/3-4-createanewuserinDomain.swf" "有影片有真相" "800" "620">> 
*在網域中新增使用者:
##透過 ''Active Directory users and computers''
##透過 ''dsadd'' 指令
***''net user'' 指令仍然可以新增使用者, 但無法將使用者依照OU歸類
*網域中使用者帳號命名規則:
##名稱長度不可超過 20 個字元
##名稱中不能包含  “/\[]:;|=,+*?<>
##User Logon Name 及 Full Name 在網域中必須唯一
*網域中使用者密碼設定規則:
##最小長度''7''個字元
##複雜度:大寫英文、小寫英文、數字、符號四種包含三種以上
##不能沒有密碼
*密碼規則可用後面的群組原則修改
{{item1{__在網域中新增一個使用者帳號, 並勾選『User must change password at next logon』__}}}  <<toBalaFlashPlayer "flash/3-4-addanewuserinDomain.swf" "有影片有真相" "800" "620">> 
{{item1{__當新建帳號時勾選『User must change password at next logon』__}}}  <<toBalaFlashPlayer "flash/3-4-anewuserlogonwhen[]ischeck.swf" "有影片有真相" "800" "620">> 
*''User must change password at next logon'' 使用者必須在下次登入時變更密碼
*網域中預設42天內必須修改一次密碼, 最快修改密碼時間1天, 且舊密碼(系統預設紀錄24組)不能再設

!使用者環境設定漫遊 (Roaming)
{{item1{__在檔案伺服器幫使用者建立『家』資料夾__}}}  <<toBalaFlashPlayer "flash/3-4-makeafolderfortheuseronly.swf" "有影片有真相" "800" "620">> 
{{item1{__在DC上幫使用者設定『家』目錄__}}}  <<toBalaFlashPlayer "flash/3-4-givetheuserhisownhomefolder.swf" "有影片有真相" "800" "620">> 
{{item1{__確定是否已幫使用者建立『家』目錄磁碟__}}}  <<toBalaFlashPlayer "flash/3-4-checkthehomefolderoftheuser.swf" "有影片有真相" "800" "620">> 
{{item1{__將使用者的文件夾移動到『家』目錄__}}}  <<toBalaFlashPlayer "flash/3-4-movemydocumentstohomefolder.swf" "有影片有真相" "800" "620">> 
{{item1{__幫使用者設定漫遊環境__}}}  <<toBalaFlashPlayer "flash/3-4-roaming.swf" "有影片有真相" "800" "620">> 
{{item1{__一個使用者在001的電腦設定自己慣用的環境__}}}  <<toBalaFlashPlayer "flash/3-4-ausersetuphisownenvironment.swf" "有影片有真相" "800" "620">> 
{{item1{__該使用者從002電腦登入__}}}  <<toBalaFlashPlayer "flash/3-4-theuserlogonatanothercomputer.swf" "有影片有真相" "800" "620">> 
*提供使用者在不同電腦登入時仍可用原來的環境設定檔及文件夾 → 漫遊(Roaming)
**註: 桌布圖案不會跟著漫遊

!使用命令提示字元新增使用者
{{{
dsadd user "cn=test user, ou=laba-users, dc=laba, dc=com" -samid testuser -upn testuser@laba.com -pwd a$12345
}}}
*cn= test user, 第一個cn代表新增帳號的fullname
*ou=laba-users, 指定在''laba-users''OU中新增
**若在預設的users資料夾則改為 ''cn=users'' (cn代表container)
*dc=laba,dc=com, ''laba.com'' 網域名稱
*-samid, 使用者登入的帳號
*-upn, __U__ser __P__rincipal __N__ame, windows 2000以後的作業系統登入方式, 可省略
*-pwd, 密碼, 依然受網域中使用者密碼規定所限制
**註: 使用 ''dsadd'' 命令密碼可以不設, 但是該新增的帳號會被disable, 直到符合安全規則的密碼設定完成 <<toBalaFlashPlayer "flash/3-4-dsaddwithoutpassword.swf" "有影片有真相" "800" "620">> 
**註2: 使用 ''net user'' 命令在網域中新增使用者''必須要設定符合規則''的密碼, 也不能不設定

!帳號基本操作
{{{
停用帳號命令
C:\>dsmod user "cn=testuser, ou=laba-users,dc=laba, dc=com" -disabled yes

重設帳號密碼
C:\>dsmod  user  "cn=testuser, ou=laba-users,dc=laba, dc=com" -pwd a$1234567

刪除帳號
C:\>dsrm  "cn=testuser, ou=laba-users ,dc=laba, dc=com"
}}}
!網域操作模式 (Mixed, Native, Windows server 2003)
##''Windows 2000 mixed'': 網域中同時包含 Windows 2000 Server 、Windows Server 2003 之 DC , 以及 Windows NT 4.0 的備份網域控制站 (Backup Domain Controller, BDC)。
##''Windows 2000 native'':
***欲採用純粹模式 (Native Mode), 必須符合唯一的條件:所有的 DC 都必須安裝 Windows 2000 Server 或 Windows Server 2003 系統。至於其他非 DC 的電腦, 則無此限制。
***除了網域區域群組 (Domain local group) 和通用群組 (Global group) 外, 另外多了萬用群組 (Universal group)。
***支援更複雜, 且更多層次的群組巢接 (Group nesting) 功能。例如:網域區域群組可以包含同網域其他的網域區域群組或同樹系的通用群組和萬用群組。
##''Windows Server 2003''
{{item1{__提升網域功能等級__}}}  <<toBalaFlashPlayer "flash/3-5-raisedomainlevel.swf" "有影片有真相" "800" "620">> 
*此動作確認後將無法還原

!群組類別 (__D__omain __L__ocal, __G__lobal, __U__niversal)
{{{
網域區域 (Domain Local):使用範圍是本網域的群組, 這類群組簡稱為網域區域群組。
通用 (Global):指派權限時使用範圍可及於森林, 但只能含同網域的帳戶或通用群組, 這類群組簡稱為通用群組。
萬用 (Universal):使用範圍及於整個森林, 這類群組簡稱為萬用群組。
}}}
*Domain local 與 Universal 為網域操作模式 ''Native'' 以上才會提供
*簡單來說, Domain local 管理資源, Global 管理使用者帳戶, Universal 管理整個森林的 Global
**註:  Universal 在大型跨國企業比較實用

!群組的產生
*網域中新增群組方式與新增使用者類似, 亦有兩種方法新增:
##透過 ''Active Directory users and computers''
##透過 ''dsadd'' 指令
{{{
dsadd group "cn=DL-laba-test, ou=laba-groups, dc=laba, dc=com" -samid L-laba-test -secgrp yes -scope l
}}}
***-secgrp {yes | no}: 是否將這個群組設成安全性群組 (''Yes'' is by default)
***-scope {l | g | u}: 設定這個群組的領域: 本機(Domain local)、通用(Global)或萬用(Universal)。如果網域仍在混合模式(Windows 2000 mixed),萬用領域將不受支援。預設: 通用(Global)。
!群組使用策略 (ALP, AGLP, AGDLP,..)


!GPO 的系統組成
{{{
 Group policy Container (GPC) 
   GPC 是 AD 資料庫中的物件, 它主要包括 GPO 的名稱及屬性, 還有 GPO 的 GUID

 Group Policy Template (GPT)
   GPT 的內容存放在 %systemroot%\sysvol\sysvol\[domainname]\Policies\{guid}
}}}
{{item1{__GPC 存放位置__}}}  <<toBalaFlashPlayer "flash/3-6-GPC.swf" "有影片有真相" "800" "620">> 
{{item1{__GPT 存放位置__}}}  <<toBalaFlashPlayer "flash/3-6-GPT.swf" "有影片有真相" "800" "620">> 

!GPO 系統套用原則
*Computer configuration: 電腦開機尚未登入前即套用在系統
*User configuration: 使用者登入後才套用在使用者環境

!GPO 執行順序
*DC 安裝完成系統自動產生兩個 GPO
##Default Domain Policy: 自動套用在整個網域中(包含網域控制站) <<toBalaFlashPlayer "flash/3-6-defaultdomainpolicy.swf" "有影片有真相" "800" "620">> 
##Default Domain Controllers Policy: 自動套用在網域中的 ''網域控制站'' <<toBalaFlashPlayer "flash/3-6-defaultdomaincontrollerspolicy.swf" "有影片有真相" "800" "620">> 
***預設網域使用者不能登入DC  <<toBalaFlashPlayer "flash/3-6-domainuserswouldnologonlocallyatDC.swf" "有影片有真相" "800" "620">>
*執行順序:
{{{
DC:
Local computer policy → Default domain policy → Default Domain Controllers Policy

其他網域中電腦:
Local computer policy → Default domain policy → 第一層 OU 套用的 GPO → 第二層 OU 套用的 GPO → ......
}}}
*若有多個 GPO 套用在同一個 OU 上,看 Link Order → ''數字越小越晚執行''
**Link Order 請安裝 gpmc.msi → 微軟提供的 GPO 管理工具  <<toBalaFlashPlayer "flash/3-6-install_gpmc.msi.swf" "有影片有真相" "800" "620">> 

*__先執行的 GPO 設定會被後面執行的 GPO 所覆蓋__
 {{item1{__強制前端本機administrator帳號改名__}}}  <<toBalaFlashPlayer "flash/3-6-forcetheclient'sadministratoraccountrename.swf" "有影片有真相" "800" "620">> 
!委派授權   <<toBalaFlashPlayer "flash/3-7-delegation.swf" "有影片有真相" "800" "620">> 
*在要委派授權的 OU 上按右鍵,點選 ''Delegate Control'',選擇要委派的項目及委派對象,要全權委派則選擇 ''Create a custom task to delegate'',並勾選 ''Full Control''   <<toBalaFlashPlayer "flash/3-7-delegating_user_with_full_control.swf" "有影片有真相" "800" "620">> 
**選擇 ''Delegate the following common tasks'' 內的所有項目僅能使委派對象在委派的 OU 內新增 ''Group''、''InetOrgPerson''、''User'' 三項,無法新增 OU 或其他電腦帳號 <<toBalaFlashPlayer "flash/3-7-delegation_with_only_all_common_tasks.swf" "有影片有真相" "800" "620">> 
*前端已被委派授權的使用者必須在電腦安裝 ''adminpak.msi'' 管理工具,使用 mmc 加入 ''Active Directory users and computers'' 管理單元
**註: 在 DC 電腦中的 ''%systemroot%\system32\'' 裡
{{item1{__安裝 adminpak.msi__}}}  <<toBalaFlashPlayer "flash/3-7-install_adminpak.msi.swf" "有影片有真相" "800" "620">> 
{{item1{__使用 mmc 新增 ''Active directory users and computers'' 管理單元__}}}  <<toBalaFlashPlayer "flash/3-7-delegating_user_manage_the_domain.swf" "有影片有真相" "800" "620">> 

!移除授權 
#顯示 OU 組織單元的 ''NTFS Permission''  <<toBalaFlashPlayer "flash/3-7-display_NTFS_permission.swf" "有影片有真相" "800" "620">> 
**''View'' → 勾起 ''Advanced Features''
#選擇 OU 的內容 → Security 標籤頁 (NTFS Permission)
#移除該使用者的權限
*委派授權 / 移除授權 馬上生效!!
{{item1{__移除授權__}}}  <<toBalaFlashPlayer "flash/3-7-remove_delegation.swf" "有影片有真相" "800" "620">> 

!!委派授權的對象將不受 User Rights 中的 ''限制一般使用者不能將 Client 加入網域'' 限制,亦即不需要將委派授權的對象使用者帳號加入 Domain Admins 或是其他管理群組

Background: #fff
Foreground: #000
PrimaryPale: #fc8
PrimaryLight: #ccf
PrimaryMid: #03c
PrimaryDark: #55f
SecondaryPale: #ffc
SecondaryLight: #fe8
SecondaryMid: #db4
SecondaryDark: #841
TertiaryPale: #eee
TertiaryLight: #ccc
TertiaryMid: #999
TertiaryDark: #666
Error: #f88
/***
|''Name:''|CryptoFunctionsPlugin|
|''Description:''|Support for cryptographic functions|
***/
//{{{
if(!version.extensions.CryptoFunctionsPlugin) {
version.extensions.CryptoFunctionsPlugin = {installed:true};

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

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

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

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

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

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

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

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

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

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

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

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

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


}
//}}}
首頁
/***
|''Name:''|DeprecatedFunctionsPlugin|
|''Description:''|Support for deprecated functions removed from core|
***/
//{{{
if(!version.extensions.DeprecatedFunctionsPlugin) {
version.extensions.DeprecatedFunctionsPlugin = {installed:true};

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

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

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

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

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

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

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

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

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

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

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

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

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

}
//}}}
/***
|Name|DisableWikiLinksPlugin|
|Source|http://www.TiddlyTools.com/#DisableWikiLinksPlugin|
|Version|1.5.0|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|plugin|
|Requires||
|Overrides|Tiddler.prototype.autoLinkWikiWords, 'wikiLink' formatter|
|Options|##Configuration|
|Description|selectively disable TiddlyWiki's automatic ~WikiWord linking behavior|
This plugin allows you to disable TiddlyWiki's automatic ~WikiWord linking behavior, so that WikiWords embedded in tiddler content will be rendered as regular text, instead of being automatically converted to tiddler links.  To create a tiddler link when automatic linking is disabled, you must enclose the link text within {{{[[...]]}}}.
!!!!!Usage
<<<
You can block automatic WikiWord linking behavior for any specific tiddler by ''tagging it with<<tag excludeWikiWords>>'' (see configuration below) or, check a plugin option to disable automatic WikiWord links to non-existing tiddler titles, while still linking WikiWords that correspond to existing tiddlers titles or shadow tiddler titles.  You can also block specific selected WikiWords from being automatically linked by listing them in [[DisableWikiLinksList]] (see configuration below), separated by whitespace.  This tiddler is optional and, when present, causes the listed words to always be excluded, even if automatic linking of other WikiWords is being permitted.  

Note: WikiWords contained in default ''shadow'' tiddlers will be automatically linked unless you select an additional checkbox option lets you disable these automatic links as well, though this is not recommended, since it can make it more difficult to access some TiddlyWiki standard default content (such as AdvancedOptions or SideBarTabs)
<<<
!!!!!Configuration
<<<
<<option chkDisableWikiLinks>> Disable ALL automatic WikiWord tiddler links
<<option chkAllowLinksFromShadowTiddlers>> ... except for WikiWords //contained in// shadow tiddlers
<<option chkDisableNonExistingWikiLinks>> Disable automatic WikiWord links for non-existing tiddlers
Disable automatic WikiWord links for words listed in: <<option txtDisableWikiLinksList>>
Disable automatic WikiWord links for tiddlers tagged with: <<option txtDisableWikiLinksTag>>
<<<
!!!!!Revisions
<<<
2006.06.09 [1.5.0] added configurable txtDisableWikiLinksTag (default value: "excludeWikiWords") to allows selective disabling of automatic WikiWord links for any tiddler tagged with that value.
2006.12.31 [1.4.0] in formatter, test for chkDisableNonExistingWikiLinks
2006.12.09 [1.3.0] in formatter, test for excluded wiki words specified in DisableWikiLinksList
2006.12.09 [1.2.2] fix logic in autoLinkWikiWords() (was allowing links TO shadow tiddlers, even when chkDisableWikiLinks is TRUE).  
2006.12.09 [1.2.1] revised logic for handling links in shadow content
2006.12.08 [1.2.0] added hijack of Tiddler.prototype.autoLinkWikiWords so regular (non-bracketed) WikiWords won't be added to the missing list
2006.05.24 [1.1.0] added option to NOT bypass automatic wikiword links when displaying default shadow content (default is to auto-link shadow content)
2006.02.05 [1.0.1] wrapped wikifier hijack in init function to eliminate globals and avoid FireFox 1.5.0.1 crash bug when referencing globals
2005.12.09 [1.0.0] initial release
<<<
!!!!!Code
***/
//{{{
version.extensions.disableWikiLinks= {major: 1, minor: 5, revision: 0, date: new Date(2007,6,9)};

if (config.options.chkDisableNonExistingWikiLinks==undefined) config.options.chkDisableNonExistingWikiLinks= false;
if (config.options.chkDisableWikiLinks==undefined) config.options.chkDisableWikiLinks=false;
if (config.options.txtDisableWikiLinksList==undefined) config.options.txtDisableWikiLinksList="DisableWikiLinksList";
if (config.options.chkAllowLinksFromShadowTiddlers==undefined) config.options.chkAllowLinksFromShadowTiddlers=true;
if (config.options.txtDisableWikiLinksTag==undefined) config.options.txtDisableWikiLinksTag="excludeWikiWords";

// find the formatter for wikiLink and replace handler with 'pass-thru' rendering
initDisableWikiLinksFormatter();
function initDisableWikiLinksFormatter() {
	for (var i=0; i<config.formatters.length && config.formatters[i].name!="wikiLink"; i++);
	config.formatters[i].coreHandler=config.formatters[i].handler;
	config.formatters[i].handler=function(w) {
		// supress any leading "~" (if present)
		var skip=(w.matchText.substr(0,1)==config.textPrimitives.unWikiLink)?1:0;
		var title=w.matchText.substr(skip);
		var exists=store.tiddlerExists(title);
		var inShadow=w.tiddler && store.isShadowTiddler(w.tiddler.title);

		// check for excluded Tiddler
		if (w.tiddler && w.tiddler.isTagged(config.options.txtDisableWikiLinksTag))
			{ w.outputText(w.output,w.matchStart+skip,w.nextMatch); return; }
		
		// check for specific excluded wiki words
		var t=store.getTiddlerText(config.options.txtDisableWikiLinksList)
		if (t && t.length && t.indexOf(w.matchText)!=-1)
			{ w.outputText(w.output,w.matchStart+skip,w.nextMatch); return; }

		// if not disabling links from shadows (default setting)
		if (config.options.chkAllowLinksFromShadowTiddlers && inShadow)
			return this.coreHandler(w);

		// check for non-existing non-shadow tiddler
		if (config.options.chkDisableNonExistingWikiLinks && !exists)
			{ w.outputText(w.output,w.matchStart+skip,w.nextMatch); return; }

		// if not enabled, just do standard WikiWord link formatting
		if (!config.options.chkDisableWikiLinks)
			return this.coreHandler(w);

		// just return text without linking
		w.outputText(w.output,w.matchStart+skip,w.nextMatch)
	}
}

Tiddler.prototype.coreAutoLinkWikiWords = Tiddler.prototype.autoLinkWikiWords;
Tiddler.prototype.autoLinkWikiWords = function()
{
	// DEBUG alert("processing: "+this.title);
	// if all automatic links are not disabled, just return results from core function
	if (!config.options.chkDisableWikiLinks)
		return this.coreAutoLinkWikiWords.apply(this,arguments);
	return false;
}
//}}}
/*{{{*/
 
/*}}}*/
/*{{{*/
a {color:#0044BB;font-weight:bold}
/*}}}*/
<!--{{{-->
<div class='toolbar' macro='toolbar +saveTiddler -cancelTiddler deleteTiddler'></div>
<div class='title' macro='view title'></div>
<div class='editor' macro='edit title'></div>
<div macro='annotations'></div>
<div class='editor' macro='easyEdit text'></div>
<div class='editor' macro='edit tags'></div><div class='editorFooter'><span macro='message views.editor.tagPrompt'></span><span macro='tagChooser'></span></div>
<!--}}}-->
<!--{{{-->
<div class='toolbar' macro='toolbar +saveTiddler -cancelTiddler deleteTiddler'></div>
<div class='title' macro='view title'></div>
<div class='editor' macro='edit title'></div>
<div macro='annotations'></div>
<div class='editor' macro='edit text'></div>
<div class='editor' macro='edit tags'></div><div class='editorFooter'><span macro='message views.editor.tagPrompt'></span><span macro='tagChooser'></span></div>
<!--}}}-->
/***
|''Name:''|FieldsEditorPlugin|
|''Description:''|//create//, //edit//, //view// and //delete// commands in toolbar <<toolbar fields>>.|
|''Version:''|1.0.2|
|''Date:''|Dec 21,2007|
|''Source:''|http://visualtw.ouvaton.org/VisualTW.html|
|''Author:''|Pascal Collin|
|''License:''|[[BSD open source license|License]]|
|''~CoreVersion:''|2.2.0|
|''Browser:''|Firefox 2.0; InternetExplorer 6.0, others|
!Demo:
On [[homepage|http://visualtw.ouvaton.org/VisualTW.html]], see [[FieldEditor example]]
!Installation:
*import this tiddler from [[homepage|http://visualtw.ouvaton.org/VisualTW.html]] (tagged as systemConfig)
*save and reload
*optionnaly : add the following css text in your StyleSheet : {{{#popup tr.fieldTableRow td {padding:1px 3px 1px 3px;}}}}
!Code
***/

//{{{

config.commands.fields.handlePopup = function(popup,title) {
	var tiddler = store.fetchTiddler(title);
	if(!tiddler)
		return;
	var fields = {};
	store.forEachField(tiddler,function(tiddler,fieldName,value) {fields[fieldName] = value;},true);
	var items = [];
	for(var t in fields) {
		var editCommand = "<<untiddledCall editFieldDialog "+escape(title)+" "+escape(t)+">>";
		var deleteCommand = "<<untiddledCall deleteField "+escape(title)+" "+escape(t)+">>";
		var renameCommand = "<<untiddledCall renameField "+escape(title)+" "+escape(t)+">>";
		items.push({field: t,value: fields[t], actions: editCommand+renameCommand+deleteCommand});
	}
	items.sort(function(a,b) {return a.field < b.field ? -1 : (a.field == b.field ? 0 : +1);});
	var createNewCommand = "<<untiddledCall createField "+escape(title)+">>";
	items.push({field : "", value : "", actions:createNewCommand });
	if(items.length > 0)
		ListView.create(popup,items,this.listViewTemplate);
	else
		createTiddlyElement(popup,"div",null,null,this.emptyText);
}

config.commands.fields.listViewTemplate = {
	columns: [
		{name: 'Field', field: 'field', title: "Field", type: 'String'},
		{name: 'Actions', field: 'actions', title: "Actions", type: 'WikiText'},
		{name: 'Value', field: 'value', title: "Value", type: 'WikiText'}
	],
	rowClasses: [
			{className: 'fieldTableRow', field: 'actions'}
	],
	buttons: [	//can't use button for selected then delete, because click on checkbox will hide the popup
	]
}

config.macros.untiddledCall = {  // when called from listview, tiddler is unset, so we need to pass tiddler as parameter
	handler : function(place,macroName,params,wikifier,paramString) {
		var macroName = params.shift();
		if (macroName) var macro = config.macros[macroName];
		var title = params.shift();
		if (title) var tiddler = store.getTiddler(unescape(title));
		if (macro) macro.handler(place,macroName,params,wikifier,paramString,tiddler);		
	}
}

config.macros.deleteField = {
	handler : function(place,macroName,params,wikifier,paramString,tiddler) {
		if(!readOnly && params[0]) {
			fieldName = unescape(params[0]);
			var btn = createTiddlyButton(place,"delete", "delete "+fieldName,this.onClickDeleteField);
			btn.setAttribute("title",tiddler.title);
			btn.setAttribute("fieldName", fieldName);
		}
	},
	onClickDeleteField : function() {
		var title=this.getAttribute("title");
		var fieldName=this.getAttribute("fieldName");
		var tiddler = store.getTiddler(title);
		if (tiddler && fieldName && confirm("delete field " + fieldName+" from " + title +" tiddler ?")) {
			delete tiddler.fields[fieldName];
			store.saveTiddler(tiddler.title,tiddler.title,tiddler.text,tiddler.modifier,tiddler.modified,tiddler.tags,tiddler.fields);
			story.refreshTiddler(title,"ViewTemplate",true);
		}
		return false;
	}
}

config.macros.createField = {
	handler : function(place,macroName,params,wikifier,paramString,tiddler) {
		if(!readOnly) {
			var btn = createTiddlyButton(place,"create new", "create a new field",this.onClickCreateField);
			btn.setAttribute("title",tiddler.title);
		}
	},
	onClickCreateField : function() {
		var title=this.getAttribute("title");
		var tiddler = store.getTiddler(title);
		if (tiddler) {
			var fieldName = prompt("Field name","");
			if (store.getValue(tiddler,fieldName)) {
				window.alert("This field already exists.");
			}
			else if (fieldName) {
				var v = prompt("Field value","");
				tiddler.fields[fieldName]=v;
				store.saveTiddler(tiddler.title,tiddler.title,tiddler.text,tiddler.modifier,tiddler.modified,tiddler.tags,tiddler.fields);
				story.refreshTiddler(title,"ViewTemplate",true);
			}
		}
		return false;
	}
}

config.macros.editFieldDialog = {
	handler : function(place,macroName,params,wikifier,paramString,tiddler) {
		if(!readOnly && params[0]) {
			fieldName = unescape(params[0]);
			var btn = createTiddlyButton(place,"edit", "edit this field",this.onClickEditFieldDialog);
			btn.setAttribute("title",tiddler.title);
			btn.setAttribute("fieldName", fieldName);
		}
	},
	onClickEditFieldDialog : function() {
		var title=this.getAttribute("title");
		var tiddler = store.getTiddler(title);
		var fieldName=this.getAttribute("fieldName");
		if (tiddler && fieldName) {
			var value = tiddler.fields[fieldName];
			value = value ? value : "";
			var lines = value.match(/\n/mg);
			lines = lines ? true : false;
			if (!lines || confirm("This field contains more than one line. Only the first line will be kept if you edit it here. Proceed ?")) {
				var v = prompt("Field value",value);
				tiddler.fields[fieldName]=v;
				store.saveTiddler(tiddler.title,tiddler.title,tiddler.text,tiddler.modifier,tiddler.modified,tiddler.tags,tiddler.fields);
				story.refreshTiddler(title,"ViewTemplate",true);
			}
		}
		return false;
	}
}

config.macros.renameField = {
	handler : function(place,macroName,params,wikifier,paramString,tiddler) {
		if(!readOnly && params[0]) {
			fieldName = unescape(params[0]);
			var btn = createTiddlyButton(place,"rename", "rename "+fieldName,this.onClickRenameField);
			btn.setAttribute("title",tiddler.title);
			btn.setAttribute("fieldName", fieldName);
		}
	},
	onClickRenameField : function() {
		var title=this.getAttribute("title");
		var fieldName=this.getAttribute("fieldName");
		var tiddler = store.getTiddler(title);
		if (tiddler && fieldName) {
			var newName = prompt("Rename " + fieldName + " as ?", fieldName);
			if (newName) {
				tiddler.fields[newName]=tiddler.fields[fieldName];
				delete tiddler.fields[fieldName];
				store.saveTiddler(tiddler.title,tiddler.title,tiddler.text,tiddler.modifier,tiddler.modified,tiddler.tags,tiddler.fields);
				story.refreshTiddler(title,"ViewTemplate",true);
			}
		}
		return false;
	}
}

config.shadowTiddlers.StyleSheetFieldsEditor = "/*{{{*/\n";
config.shadowTiddlers.StyleSheetFieldsEditor += ".fieldTableRow td {padding : 1px 3px}\n";
config.shadowTiddlers.StyleSheetFieldsEditor += ".fieldTableRow .button {border:0; padding : 0 0.2em}\n";
config.shadowTiddlers.StyleSheetFieldsEditor +="/*}}}*/";
store.addNotification("StyleSheetFieldsEditor", refreshStyles);

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

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

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

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

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

!Code
***/
//{{{

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


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

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

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

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

	return tiddlyWiki;
};


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

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

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

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

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

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

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

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


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

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


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

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

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

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

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

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


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



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


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

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

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

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


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


} // of "install only once"

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


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

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

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

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

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

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
***/
使用此 TiddlyWiki 的空白範本之前,請先修改以下預設文章:
* SiteTitle 及 SiteSubtitle:網站的標題和副標題,顯示於頁面上方<br />(在儲存變更後,將顯示於瀏覽器視窗的標題列)。
* MainMenu:主選單(通常在頁面左側)。
* DefaultTiddlers:內含一些文章的標題,可於載入TiddlyWiki 後的預設開啟。
請輸入您的大名,作為所建立/ 編輯的文章署名:<<option txtUserName>>
<!--{{{-->
<div class='toolbar' macro='toolbar +saveTiddler  -cancelTiddler deleteTiddler'></div>
<div class='title' macro='view title'></div>
<div class='editor' macro='edit title'></div>
<div macro='annotations'></div>
<div class='editor' macro='easyEdit text'></div>
<div class='editor' macro='edit tags'></div><div class='editorFooter'><span macro='message views.editor.tagPrompt'></span><span macro='tagChooser'></span></div>
<!--}}}-->
/***
|Name|HTMLFormattingPlugin|
|Source|http://www.TiddlyTools.com/#HTMLFormattingPlugin|
|Documentation|http://www.TiddlyTools.com/#HTMLFormattingPluginInfo|
|Version|2.1.5|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|plugin|
|Requires||
|Overrides|'HTML' formatter|
|Description|embed wiki syntax formatting inside of HTML content|
The shorthand Wiki-style formatting syntax of ~TiddlyWiki is very convenient and enables most content to be reasonably well presented. However, there are times when tried-and-true HTML formatting syntax allows more more precise control of the content display.  When HTML formatting syntax is embedded within a tiddler (in between {{{<}}}{{{html>}}} and {{{<}}}{{{/html>}}} markers) TiddlyWiki passes this content to the browser for processing as 'native' HTML.  However, TiddlyWiki does not also process the HTML source content for any embedded wiki-formatting syntax it may contain.  This means that while you can use HTML formatted content, you cannot mix wiki-formatted content within the HTML formatting.

The ~HTMLFormatting plugin allows you to freely ''mix wiki-style formatting syntax within HTML formatted content'' by extending the action of the standard TiddlyWiki formatting handler.
!!!!!Documentation
>see [[HTMLFormattingPluginInfo]]
!!!!!Revisions
<<<
2008.01.08 [*.*.*] plugin size reduction: documentation moved to HTMLFormattingInfo
2007.12.04 [*.*.*] update for TW2.3.0: replaced deprecated core functions, regexps, and macros
2007.06.14 [2.1.5] in formatter, removed call to e.normalize().  Creates an INFINITE RECURSION error in Safari!!!!
2006.09.10 [2.1.4] update formatter for 2.1 compatibility (use this.lookaheadRegExp instead of temp variable)
2006.05.28 [2.1.3] in wikifyTextNodes(), decode the *value* of TEXTAREA nodes, but don't wikify() its children.  (thanks to "ayj" for bug report)
2006.02.19 [2.1.2] in wikifyTextNodes(), put SPAN element into tiddler DOM (replacing text node), BEFORE wikifying the text content.  This ensures that the 'place' passed to any macros is correctly defined when the macro is evaluated, so that calls to story.findContainingTiddler(place) will work as expected. (Thanks for bug report from GeoffSlocock)
2006.02.05 [2.1.1] wrapped wikifier hijack in init function to eliminate globals and avoid FireFox 1.5.0.1 crash bug when referencing globals
2005.12.01 [2.1.0] don't wikify #TEXT nodes inside SELECT and TEXTAREA elements
2005.11.06 [2.0.1] code cleanup
2005.10.31 [2.0.0] replaced hijack wikify() with hijack config.formatters["html"] and simplified recursive WikifyTextNodes() code
2005.10.09 [1.0.2] combined documentation and code into a single tiddler
2005.08.05 [1.0.1] moved HTML and CSS definitions into plugin code instead of using separate tiddlers
2005.07.26 [1.0.1] Re-released as a plugin. Added <{{{html}}}>...</{{{nohtml}}}> and <{{{hide newlines}}}> handling
2005.06.26 [1.0.0] Initial Release (as code adaptation - pre-dates TiddlyWiki plugin architecture!!)
<<<
!!!!!Code
***/
//{{{
version.extensions.HTMLFormatting = {major: 2, minor: 1, revision: 5, date: new Date(2007,6,14)};

// find the formatter for HTML and replace the handler
initHTMLFormatter();
function initHTMLFormatter()
{
	for (var i=0; i<config.formatters.length && config.formatters[i].name!="html"; i++);
	if (i<config.formatters.length)	config.formatters[i].handler=function(w) {
		if (!this.lookaheadRegExp)  // fixup for TW2.0.x
			this.lookaheadRegExp = new RegExp(this.lookahead,"mg");
		this.lookaheadRegExp.lastIndex = w.matchStart;
		var lookaheadMatch = this.lookaheadRegExp.exec(w.source)
		if(lookaheadMatch && lookaheadMatch.index == w.matchStart) {
			var html=lookaheadMatch[1];
			// optionally suppress wiki-style literal handling of newlines
			// strip any carriage returns added by Internet Explorer's textarea edit field
			// encode newlines as \n so Internet Explorer's HTML parser won't eat them
			// encode macro brackets (<< and >>) so HTML parser won't eat them
			if (html.indexOf('<hide linebreaks>')!=-1) html=html.replace(/\n/g,' ');
			html=html.replace(/\r/g,'');
			html=html.replace(/\n/g,'\\n');
			html=html.replace(/<</g,'%%(').replace(/>>/g,')%%');
			// create span to hold HTML
			// parse HTML and normalize the results
			// walk node tree and call wikify() on each text node
			var e = createTiddlyElement(w.output,"span");
			e.innerHTML=html;
			// REMOVED: e.normalize();  // THIS CAUSED INFINITE RECURSION IN SAFARI
			wikifyTextNodes(e);
			// advance to next parse position
			w.nextMatch = this.lookaheadRegExp.lastIndex;
		}
	}
}

// wikify text nodes remaining after HTML content is processed (pre-order recursion)
function wikifyTextNodes(theNode)
{
	// textarea node doesn't get wikified, just decoded... 
	if (theNode.nodeName.toLowerCase()=='textarea')
		theNode.value=theNode.value.replace(/\%%\(/g,'<<').replace(/\)\%%/g,'>>').replace(/\\n/g,'\n');
	else for (var i=0;i<theNode.childNodes.length;i++) {
		var theChild=theNode.childNodes.item(i);
		if (theChild.nodeName.toLowerCase()=='option') continue;
		if (theChild.nodeName.toLowerCase()=='select') continue;
		wikifyTextNodes(theChild);
		if (theChild.nodeName=='#text') {
			var txt=theChild.nodeValue;
			// decode macro brackets and newlines
			txt=txt.replace(/\%%\(/g,'<<').replace(/\)\%%/g,'>>').replace(/\\n/g,'\n');
			// replace text node with wikified() span
			var newNode=createTiddlyElement(null,"span");
			theNode.replaceChild(newNode,theChild);
			wikify(txt,newNode);
		}
	}
}
//}}}
<!--{{{-->
<div class='toolbar' macro='toolbar closeTiddler closeOthers +easyEdit > fields syncing permalink references jump'></div>
<div class='title' macro='view title'></div>
<div class='subtitle'><span macro='view modifier link'></span>, <span macro='view modified date'></span> (<span macro='message views.wikified.createdPrompt'></span> <span macro='view created date'></span>)</div>

<!--
<div class='tagging' macro='tagging'></div>
-->
<div class='tagged' macro='tags'></div>
<div class='viewer' macro='view text wikified'></div>
<div class='tagClear'></div>
<!--}}}-->
*寫一支 adm 檔,擴充系統管理範本,限制 usb 儲存裝置存取
<<importTiddlers inline>>
/***
|Name|ImportTiddlersPlugin|
|Source|http://www.TiddlyTools.com/#ImportTiddlersPlugin|
|Documentation|http://www.TiddlyTools.com/#ImportTiddlersPluginInfo|
|Version|4.3.1|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|plugin|
|Requires||
|Overrides|config.macros.importTiddlers.handler|
|Options|##Configuration|
|Description|interactive controls for import/export with filtering.|
This plugin lets you selectively combine tiddlers from any two TiddlyWiki documents.  An interactive control panel lets you pick a document to import from, and then select which tiddlers to import, with prompting for skip, rename, merge or replace actions when importing tiddlers that match existing titles.  Automatically add tags to imported tiddlers so they are easy to find later on.  Generates a detailed report of import 'history' in ImportedTiddlers.
!!!!!Documentation
<<<
see [[ImportTiddlersPluginInfo]] for details
<<<
!!!!!interactive control panel:
<<<
<<tiddler ImportTiddlers>>
^^(see [[ImportTiddlers]] shadow tiddler)^^
<<<
!!!!!Installation Notes
<<<
* As of 6/27/2007, "patch" functions that provide backward-compatibility with TW2.1.x and earlier have been split into a separate [[ImportTiddlersPluginPatch]] tiddler to reduce installation overhead for //this// plugin.  You only need to install the additional plugin tiddler when using ImportTiddlersPlugin in documents using TW2.1.x or earlier.
* As of 3/21/2007, the interactive {{{<<importTiddlers>>}}} and non-interactive {{{<<loadTiddlers>>}}} macro definitions and related code have been split into separate [[ImportTiddlersPlugin]] and [[LoadTiddlersPlugin]] to permit selective installation of either the interactive and/or non-interactive macro functions.
* Quick Installation Tip: If you are using an unmodified version of TiddlyWiki (core release version <<version>>), you can get a new, empty TiddlyWiki with the Import Tiddlers plugin pre-installed (''[[download from here|TW+ImportExport.html]]''), and then simply import all your content from your old document into this new, empty document.
<<<
!!!!!Revisions
<<<
2008.06.29 [4.3.1] More layout/animation work for simpler sequential interaction.  Code reduction/cleanup
|please see [[ImportTiddlersPluginInfo]] for additional revision details|
2005.07.20 [1.0.0] Initial Release
<<<
!!!!!Code
***/
// // ''MACRO DEFINITION''
//{{{
// Version
version.extensions.importTiddlers = {major: 4, minor: 3, revision: 0, date: new Date(2008,6,28)};

// add ImportTiddlerPlugin controls to built-in backstage import task
if (config.tasks) { // TW2.2 or above
	config.tasks.importTask.content="Use ~TiddlyWiki built-in importer (below) or, ";
	config.tasks.importTask.content+="<<importTiddlers link 'Use ImportTiddlersPlugin control panel...'>>\n";
	config.tasks.importTask.content+="<<importTiddlers core>>"
}

// IE needs explicit global scoping for functions/vars called from browser events
window.onClickImportButton=onClickImportButton;
window.refreshImportList=refreshImportList;

// default cookie/option values
if (!config.options.chkImportReport) config.options.chkImportReport=true;

// default shadow definition
config.shadowTiddlers.ImportTiddlers="<<importTiddlers inline>>";

merge(config.macros.importTiddlers,{
	label: "import tiddlers",
	prompt: "Copy tiddlers from another document",
	openMsg: "Opening %0",
	openErrMsg: "Could not open %0 - error=%1",
	readMsg: "Read %0 bytes from %1",
	foundMsg: "Found %0 tiddlers in %1",
	filterMsg: "Filtered %0 tiddlers matching '%1'",
	summaryMsg: "%0 tiddler%1 in the list",
	summaryFilteredMsg: "%0 of %1 tiddler%2 in the list",
	plural: "s are",
	single: " is",
	countMsg: "%0 tiddlers selected for import",
	processedMsg: "Processed %0 tiddlers",
	importedMsg: "Imported %0 of %1 tiddlers from %2",
	loadText: "please load a document...",
	closeText: "close",	// text for close button when file is loaded
	doneText: "done",	// text for close button when file is not loaded
	startText: "import",	// text for import button
	stopText: "stop",	// text for import button while importing
	local: true,		// default to import from local file
	src: "",		// path/filename or URL of document to import (retrieved from SiteUrl tiddler)
	proxy: "",		// URL for remote proxy script (retrieved from SiteProxy tiddler)
	useProxy: false,	// use specific proxy script in front of remote URL
	inbound: null,		// hash-indexed array of tiddlers from other document
	newTags: "",		// text of tags added to imported tiddlers
	addTags: true,		// add new tags to imported tiddlers
	listsize: 10,		// # of lines to show in imported tiddler list
	importTags: true,	// include tags from remote source document when importing a tiddler
	keepTags: true,		// retain existing tags when replacing a tiddler
	sync: false,		// add 'server' fields to imported tiddlers (for sync function)
	lastFilter: "",		// most recent filter (URL hash) applied
	lastAction: null,	// most recent collision button performed
	index: 0,		// current processing index in import list
	sort: ""		// sort order for imported tiddler listbox
});

if (config.macros.importTiddlers.coreHandler==undefined)
	config.macros.importTiddlers.coreHandler=config.macros.importTiddlers.handler; // save built-in handler
config.macros.importTiddlers.handler = function(place,macroName,params,wikifier,paramString,tiddler) {
	if (!params[0] || params[0].toLowerCase()=='core') { // default to built in
		if (config.macros.importTiddlers.coreHandler)
			config.macros.importTiddlers.coreHandler.apply(this,arguments);
		else 
			createTiddlyButton(place,this.label,this.prompt,onClickImportMenu);
	} else if (params[0]=='link') { // show link to floating panel
		createTiddlyButton(place,params[1]||this.label,params[2]||this.prompt,onClickImportMenu);
	} else if (params[0]=='inline') {// show panel as INLINE tiddler content
		createImportPanel(place);
		document.getElementById("importPanel").style.position="static";
		document.getElementById("importPanel").style.display="block";
	} else if (config.macros.loadTiddlers)
		config.macros.loadTiddlers.handler(place,macroName,params); // any other params: loadtiddlers
}

// // ''INTERFACE DEFINITION''
// // Handle link click to create/show/hide control panel
//{{{
function onClickImportMenu(e)
{
	if (!e) var e = window.event;
	var parent=resolveTarget(e).parentNode;
	var panel = document.getElementById("importPanel");
	if (panel==undefined || panel.parentNode!=parent)
		panel=createImportPanel(parent);
	var isOpen = panel.style.display=="block";
	if(config.options.chkAnimate)
		anim.startAnimating(new Slider(panel,!isOpen,e.shiftKey || e.altKey,"none"));
	else
		panel.style.display = isOpen ? "none" : "block" ;
	e.cancelBubble = true;
	if (e.stopPropagation) e.stopPropagation();
	return(false);
}
//}}}

// // Create control panel: HTML, CSS
//{{{
function createImportPanel(place) {
	var cmi=config.macros.importTiddlers; // abbreviation
	var panel=document.getElementById("importPanel");
	if (panel) { panel.parentNode.removeChild(panel); }
	setStylesheet(cmi.css,"importTiddlers");
	panel=createTiddlyElement(place,"span","importPanel",null,null)
	panel.innerHTML=cmi.html;
	refreshImportList();
	var siteURL=store.getTiddlerText("SiteUrl"); if (!siteURL) siteURL="";
	document.getElementById("importSourceURL").value=siteURL;
	cmi.src=siteURL;
	var siteProxy=store.getTiddlerText("SiteProxy"); if (!siteProxy) siteProxy="SiteProxy";
	document.getElementById("importSiteProxy").value=siteProxy;
	cmi.proxy=siteProxy;
	if (config.browser.isGecko) { // FF3 FIXUP
		document.getElementById("fileImportSource").style.display="none";
		document.getElementById("importLocalPanelFix").style.display="block";
	}
	return panel;
}
//}}}

// // CSS
//{{{
config.macros.importTiddlers.css = '\
#importPanel {\
	display: none; position:absolute; z-index:11; width:35em; right:105%; top:3em;\
	background-color: #eee; color:#000; font-size: 8pt; line-height:110%;\
	border:1px solid black; border-bottom-width: 3px; border-right-width: 3px;\
	padding: 0.5em; margin:0em; -moz-border-radius:1em;\
}\
#importPanel a, #importPanel td a { color:#009; display:inline; margin:0px; padding:1px; }\
#importPanel table { width:100%; border:0px; padding:0px; margin:0px; font-size:8pt; line-height:110%; background:transparent; }\
#importPanel tr { border:0px;padding:0px;margin:0px; background:transparent; }\
#importPanel td { color:#000; border:0px;padding:0px;margin:0px; background:transparent; }\
#importPanel select { width:100%;margin:0px;font-size:8pt;line-height:110%;}\
#importPanel input  { width:98%;padding:0px;margin:0px;font-size:8pt;line-height:110%}\
#importPanel .box { border:1px solid #000; background-color:#eee; padding:3px 5px; margin-bottom:5px; -moz-border-radius:5px;}\
#importPanel .topline { border-top:1px solid #999; padding-top:2px; margin-top:2px; }\
#importPanel .rad { width:auto; }\
#importPanel .chk { width:auto; margin:1px;border:0; }\
#importPanel .btn { width:auto; }\
#importPanel .btn1 { width:98%; }\
#importPanel .btn2 { width:48%; }\
#importPanel .btn3 { width:32%; }\
#importPanel .btn4 { width:23%; }\
#importPanel .btn5 { width:19%; }\
#importPanel .importButton { padding: 0em; margin: 0px; font-size:8pt; }\
#importPanel .importListButton { padding:0em 0.25em 0em 0.25em; color: #000000; display:inline }\
#importCollisionPanel { display:none; margin:0.5em 0em 0em 0em; }\
#backstagePanel #importPanel { left:10%; right:auto; }\
';
//}}}

// // HTML 
//{{{
config.macros.importTiddlers.html = '\
<!-- source and report -->\
<table><tr><td align=left>\
	import from\
	<input type="radio" class="rad" name="importFrom" id="importFromFile" value="file" CHECKED\
		onclick="onClickImportButton(this,event)" title="show file controls"> local file\
	<input type="radio" class="rad" name="importFrom" id="importFromWeb"  value="http"\
		onclick="onClickImportButton(this,event)" title="show web controls"> web server\
</td><td align=right>\
	<input type=checkbox class="chk" id="chkImportReport" checked\
		onClick="config.options[\'chkImportReport\']=this.checked;"> create report\
</td></tr></table>\
\
<div class="box" id="importSourcePanel" style="margin:.5em">\
<div id="importLocalPanel" style="display:block;margin-bottom:2px;"><!-- import from local file  -->\
enter or browse for source path/filename<br>\
<input type="file" id="fileImportSource" size=57 style="width:100%"\
	onKeyUp="config.macros.importTiddlers.src=this.value"\
	onChange="config.macros.importTiddlers.src=this.value;document.getElementById(\'importLoad\').onclick()">\
<div id="importLocalPanelFix" style="display:none"><!-- FF3 FIXUP -->\
	<input type="text" id="fileImportSourceFix" style="width:90%"\
		title="Enter a path/file to import"\
		onKeyUp="config.macros.importTiddlers.src=this.value"\
		onChange="config.macros.importTiddlers.src=this.value; document.getElementById(\'importLoad\').onclick()">\
	<input type="button" id="fileImportSourceFixButton" style="width:7%" value="..."\
		title="Select a path/file to import"\
		onClick="var r=config.macros.importTiddlers.askForFilename(this); if (!r||!r.length) return;\
			document.getElementById(\'fileImportSourceFix\').value=r;\
			config.macros.importTiddlers.src=r;\
			document.getElementById(\'importLoad\').onclick()">\
</div><!--end FF3 FIXUP-->\
</div><!--end local-->\
<div id="importHTTPPanel" style="display:none;margin-bottom:2px;"><!-- import from http server -->\
<table><tr><td align=left>\
	enter a URL or <a href="javascript:;" id="importSelectFeed"\
		onclick="onClickImportButton(this,event)" title="select a pre-defined \'systemServer\' URL">\
		select a server</a><br>\
</td><td align=right>\
	<input type="checkbox" class="chk" id="importUsePassword"\
		onClick="config.macros.importTiddlers.usePassword=this.checked;\
			config.macros.importTiddlers.showPanel(\'importIDPWPanel\',this.checked);">password\
	<input type="checkbox" class="chk" id="importUseProxy"\
		onClick="config.macros.importTiddlers.useProxy=this.checked;\
			config.macros.importTiddlers.showPanel(\'importSiteProxy\',this.checked);">proxy\
</td></tr></table>\
<input type="text" id="importSiteProxy" style="display:none;margin-bottom:1px" onfocus="this.select()" value="SiteProxy"\
	onKeyUp="config.macros.importTiddlers.proxy=this.value"\
	onChange="config.macros.importTiddlers.proxy=this.value;">\
<input type="text" id="importSourceURL" onfocus="this.select()" value="SiteUrl"\
	onKeyUp="config.macros.importTiddlers.src=this.value"\
	onChange="config.macros.importTiddlers.src=this.value;">\
<div id="importIDPWPanel" style="text-align:center;margin-top:2px;display:none";>\
username: <input type=text id="txtImportID" style="width:25%" \
	onChange="config.options.txtRemoteUsername=this.value;">\
 password: <input type=password id="txtImportPW" style="width:25%" \
	onChange="config.options.txtRemotePassword=this.value;">\
</div><!--end idpw-->\
</div><!--end http-->\
</div><!--end source-->\
\
<div class="box" id="importSelectPanel" style="display:none;margin:.5em;">\
<table><tr><td align=left>\
select:\
<a href="javascript:;" id="importSelectAll"\
	onclick="onClickImportButton(this);return false;" title="SELECT all tiddlers">\
	all</a>\
&nbsp;<a href="javascript:;" id="importSelectNew"\
	onclick="onClickImportButton(this);return false;" title="SELECT tiddlers not already in destination document">\
	added</a>\
&nbsp;<a href="javascript:;" id="importSelectChanges"\
	onclick="onClickImportButton(this);return false;" title="SELECT tiddlers that have been updated in source document">\
	changes</a>\
&nbsp;<a href="javascript:;" id="importSelectDifferences"\
	onclick="onClickImportButton(this);return false;" title="SELECT tiddlers that have been added or are different from existing tiddlers">\
	differences</a>\
</td><td align=right>\
<a href="javascript:;" id="importListSmaller"\
	onclick="onClickImportButton(this);return false;" title="SHRINK list size">\
	&nbsp;&#150;&nbsp;</a>\
<a href="javascript:;" id="importListLarger"\
	onclick="onClickImportButton(this);return false;" title="GROW list size">\
	&nbsp;+&nbsp;</a>\
<a href="javascript:;" id="importListMaximize"\
	onclick="onClickImportButton(this);return false;" title="MAXIMIZE/RESTORE list size">\
	&nbsp;=&nbsp;</a>\
</td></tr></table>\
<select id="importList" size=8 multiple\
	onchange="setTimeout(\'refreshImportList(\'+this.selectedIndex+\')\',1)">\
	<!-- NOTE: delay refresh so list is updated AFTER onchange event is handled -->\
</select>\
<div style="text-align:center">\
	<a href="javascript:;"\
		title="click for help using filters..."\
		onclick="alert(\'A filter consists of one or more space-separated combinations of:\\n\\ntiddler titles\\ntag:[[tagvalue]]\\ntag:[[tag expression]] (requires MatchTagsPlugin)\\nstory:[[TiddlerName]]\\nsearch:[[searchtext]]\\n\\nUse a blank filter for all tiddlers.\')"\
	>filter</a>\
	<input type="text" id="importLastFilter" style="margin-bottom:1px; width:65%"\
		title="Enter a combination of one or more filters. Use a blank filter for all tiddlers."\
		onfocus="this.select()" value=""\
		onKeyUp="config.macros.importTiddlers.lastFilter=this.value"\
		onChange="config.macros.importTiddlers.lastFilter=this.value;">\
	<input type="button" id="importApplyFilter" style="width:20%" value="apply"\
		title="filter list of tiddlers to include only those that match certain criteria"\
		onclick="onClickImportButton(this)">\
	</div>\
</div><!--end select-->\
\
<div class="box" id="importOptionsPanel" style="text-align:center;margin:.5em;display:none;">\
	apply tags: <input type=checkbox class="chk" id="chkImportTags" checked\
		onClick="config.macros.importTiddlers.importTags=this.checked;">from source&nbsp;\
	<input type=checkbox class="chk" id="chkKeepTags" checked\
		onClick="config.macros.importTiddlers.keepTags=this.checked;">keep existing&nbsp;\
	<input type=checkbox class="chk" id="chkAddTags" \
		onClick="config.macros.importTiddlers.addTags=this.checked;\
		if (this.checked) document.getElementById(\'txtNewTags\').focus();">add new<br>\
	<input type=text id="txtNewTags" style="margin-top:4px;" size=15\ onfocus="this.select()" \
		title="enter tags to be added to imported tiddlers" \
		onKeyUp="config.macros.importTiddlers.newTags=this.value;\
		document.getElementById(\'chkAddTags\').checked=this.value.length>0;" autocomplete=off>\
	<nobr><input type=checkbox class="chk" id="chkSync" \
		onClick="config.macros.importTiddlers.sync=this.checked;">\
		link imported tiddlers to source document (for sync later)</nobr>\
</div><!--end options-->\
\
<div id="importButtonPanel" style="text-align:center">\
	<input type=button id="importLoad"	class="importButton btn3" value="open"\
		title="load listbox with tiddlers from source document"\
		onclick="onClickImportButton(this)">\
	<input type=button id="importOptions"	class="importButton btn3" value="options..."\
		title="set options for tags, sync, etc."\
		onclick="onClickImportButton(this)">\
	<input type=button id="importStart"	class="importButton btn3" value="import"\
		title="start/stop import of selected source tiddlers into current document"\
		onclick="onClickImportButton(this)">\
	<input type=button id="importClose"	class="importButton btn3" value="done"\
		title="clear listbox or hide control panel"\
		onclick="onClickImportButton(this)">\
</div>\
\
<div class="none" id="importCollisionPanel" style="text-align:left;margin:0 0 0 .5em">\
	<table><tr><td style="width:65%" align="left">\
		<table><tr>\
		<td align=left>\
			tiddler already exists:\
		</td><td align=right>\
			<input type=checkbox class="chk" id="importApplyToAll" \
			onclick="document.getElementById(\'importRename\').disabled=this.checked;"\
			checked>apply to all\
		</td></tr></table>\
		<input type=text id="importNewTitle" size=15 autocomplete=off">\
	</td><td style="width:34%" align="center">\
		<input type=button id="importMerge"\
			class="importButton" style="width:47%" value="merge"\
			title="append the incoming tiddler to the existing tiddler"\
			onclick="onClickImportButton(this)"><!--\
		--><input type=button id="importSkip"\
			class="importButton" style="width:47%" value="skip"\
			title="do not import this tiddler"\
			onclick="onClickImportButton(this)"><!--\
		--><br><input type=button id="importRename"\
			class="importButton" style="width:47%" value="rename"\
			title="rename the incoming tiddler"\
			onclick="onClickImportButton(this)"><!--\
		--><input type=button id="importReplace"\
			class="importButton" style="width:47%" value="replace"\
			title="discard the existing tiddler"\
			onclick="onClickImportButton(this)">\
	</td></tr></table>\
</div><!--end collision-->\
';
//}}}

// // Control interactions
//{{{
function onClickImportButton(which,event)
{
	var cmi=config.macros.importTiddlers; // abbreviation

	var list = document.getElementById('importList');
	if (!list) return;
	var thePanel = document.getElementById('importPanel');
	var theCollisionPanel = document.getElementById('importCollisionPanel');
	var theNewTitle = document.getElementById('importNewTitle');
	var count=0;
	switch (which.id)
		{
		case 'importFromFile':	// show local panel
		case 'importFromWeb':	// show HTTP panel
			cmi.local=(which.id=='importFromFile');
			cmi.showPanel('importLocalPanel',cmi.local);
			cmi.showPanel('importHTTPPanel',!cmi.local);
			break;
		case 'importOptions':	// show/hide options panel
			cmi.showPanel('importOptionsPanel',document.getElementById('importOptionsPanel').style.display=='none');
			break;
		case 'fileImportSource':
		case 'importLoad':		// load import source into hidden frame
			importReport();		// if an import was in progress, generate a report
			cmi.inbound=null;	// clear the imported tiddler buffer
			refreshImportList();	// reset/resize the listbox
			if (cmi.src=="") break;
			// Load document, read it's DOM and fill the list
			cmi.loadRemoteFile(cmi.src,cmi.filterTiddlerList);
			break;
		case 'importSelectFeed':	// select a pre-defined systemServer feed URL
			var p=Popup.create(which); if (!p) return;
			var tids=store.getTaggedTiddlers('systemServer');
			if (!tids.length)
				createTiddlyText(createTiddlyElement(p,'li'),'no pre-defined server feeds');
			for (var t=0; t<tids.length; t++) {
				var u=store.getTiddlerSlice(tids[t].title,"URL");
				var d=store.getTiddlerSlice(tids[t].title,"Description");
				if (!d||!d.length) d=store.getTiddlerSlice(tids[t].title,"description");
				if (!d||!d.length) d=u;
				createTiddlyButton(createTiddlyElement(p,'li'),tids[t].title,d,
					function(){
						var u=this.getAttribute('url');
						document.getElementById('importSourceURL').value=u;
						config.macros.importTiddlers.src=u;
						document.getElementById('importLoad').onclick();
					},
					null,null,null,{url:u});
			}
			Popup.show(p,false);
			event.cancelBubble = true;
			if (event.stopPropagation) event.stopPropagation();
			return(false);
			// create popup with feed list
			// onselect, insert feed URL into input field.
			break;
		case 'importSelectAll':		// select all tiddler list items (i.e., not headings)
			importReport();		// if an import was in progress, generate a report
			for (var t=0,count=0; t < list.options.length; t++) {
				if (list.options[t].value=="") continue;
				list.options[t].selected=true;
				count++;
			}
			clearMessage(); displayMessage(cmi.countMsg.format([count]));
			document.getElementById('importStart').disabled=!count;
			document.getElementById('importStart').style.visibility=count?"visible":"hidden";
			break;
		case 'importSelectNew':		// select tiddlers not in current document
			importReport();		// if an import was in progress, generate a report
			for (var t=0,count=0; t < list.options.length; t++) {
				list.options[t].selected=false;
				if (list.options[t].value=="") continue;
				list.options[t].selected=!store.tiddlerExists(list.options[t].value);
				count+=list.options[t].selected?1:0;
			}
			clearMessage(); displayMessage(cmi.countMsg.format([count]));
			document.getElementById('importStart').disabled=!count;
			document.getElementById('importStart').style.visibility=count?"visible":"hidden";
			break;
		case 'importSelectChanges':		// select tiddlers that are updated from existing tiddlers
			importReport();		// if an import was in progress, generate a report
			for (var t=0,count=0; t < list.options.length; t++) {
				list.options[t].selected=false;
				if (list.options[t].value==""||!store.tiddlerExists(list.options[t].value)) continue;
				for (var i=0; i<cmi.inbound.length; i++) // find matching inbound tiddler
					{ var inbound=cmi.inbound[i]; if (inbound.title==list.options[t].value) break; }
				list.options[t].selected=(inbound.modified-store.getTiddler(list.options[t].value).modified>0); // updated tiddler
				count+=list.options[t].selected?1:0;
			}
			clearMessage(); displayMessage(cmi.countMsg.format([count]));
			document.getElementById('importStart').disabled=!count;
			document.getElementById('importStart').style.visibility=count?"visible":"hidden";
			break;
		case 'importSelectDifferences':		// select tiddlers that are new or different from existing tiddlers
			importReport();		// if an import was in progress, generate a report
			for (var t=0,count=0; t < list.options.length; t++) {
				list.options[t].selected=false;
				if (list.options[t].value=="") continue;
				if (!store.tiddlerExists(list.options[t].value)) { list.options[t].selected=true; count++; continue; }
				for (var i=0; i<cmi.inbound.length; i++) // find matching inbound tiddler
					{ var inbound=cmi.inbound[i]; if (inbound.title==list.options[t].value) break; }
				list.options[t].selected=(inbound.modified-store.getTiddler(list.options[t].value).modified!=0); // changed tiddler
				count+=list.options[t].selected?1:0;
			}
			clearMessage(); displayMessage(cmi.countMsg.format([count]));
			document.getElementById('importStart').disabled=!count;
			document.getElementById('importStart').style.visibility=count?"visible":"hidden";
			break;
		case 'importApplyFilter':	// filter list to include only matching tiddlers
			importReport();		// if an import was in progress, generate a report
			clearMessage();
			if (!cmi.all) // no tiddlers loaded = "0 selected"
				{ displayMessage(cmi.countMsg.format([0])); return false; }
			var hash=document.getElementById('importLastFilter').value;
			cmi.inbound=cmi.filterByHash("#"+hash,cmi.all);
			refreshImportList();	// reset/resize the listbox
			break;
		case 'importStart':		// initiate the import processing
			importReport();		// if an import was in progress, generate a report
			document.getElementById('importApplyToAll').checked=false;
			document.getElementById('importStart').value=cmi.stopText;
			if (cmi.index>0) cmi.index=-1; // stop processing
			else cmi.index=importTiddlers(0); // or begin processing
			importStopped();
			break;
		case 'importClose':		// unload imported tiddlers or hide the import control panel
			// if imported tiddlers not loaded, close the import control panel
			if (!cmi.inbound) { thePanel.style.display='none'; break; }
			importReport();		// if an import was in progress, generate a report
			cmi.inbound=null;	// clear the imported tiddler buffer
			refreshImportList();	// reset/resize the listbox
			break;
		case 'importSkip':	// don't import the tiddler
			cmi.lastAction=which;
			var theItem	= list.options[cmi.index];
			for (var j=0;j<cmi.inbound.length;j++)
			if (cmi.inbound[j].title==theItem.value) break;
			var theImported = cmi.inbound[j];
			theImported.status='skipped after asking';			// mark item as skipped
			theCollisionPanel.style.display='none';
			cmi.index=importTiddlers(cmi.index+1);	// resume with NEXT item
			importStopped();
			break;
		case 'importRename':		// change name of imported tiddler
			cmi.lastAction=which;
			var theItem		= list.options[cmi.index];
			for (var j=0;j<cmi.inbound.length;j++)
			if (cmi.inbound[j].title==theItem.value) break;
			var theImported		= cmi.inbound[j];
			theImported.status	= 'renamed from '+theImported.title;	// mark item as renamed
			theImported.set(theNewTitle.value,null,null,null,null);		// change the tiddler title
			theItem.value		= theNewTitle.value;			// change the listbox item text
			theItem.text		= theNewTitle.value;			// change the listbox item text
			theCollisionPanel.style.display='none';
			cmi.index=importTiddlers(cmi.index);	// resume with THIS item
			importStopped();
			break;
		case 'importMerge':	// join existing and imported tiddler content
			cmi.lastAction=which;
			var theItem	= list.options[cmi.index];
			for (var j=0;j<cmi.inbound.length;j++)
			if (cmi.inbound[j].title==theItem.value) break;
			var theImported	= cmi.inbound[j];
			var theExisting	= store.getTiddler(theItem.value);
			var theText	= theExisting.text+'\n----\n^^merged from: ';
			theText		+='[['+cmi.src+'#'+theItem.value+'|'+cmi.src+'#'+theItem.value+']]^^\n';
			theText		+='^^'+theImported.modified.toLocaleString()+' by '+theImported.modifier+'^^\n'+theImported.text;
			var theDate	= new Date();
			var theTags	= theExisting.getTags()+' '+theImported.getTags();
			theImported.set(null,theText,null,theDate,theTags);
			theImported.status   = 'merged with '+theExisting.title;	// mark item as merged
			theImported.status  += ' - '+theExisting.modified.formatString("MM/DD/YYYY 0hh:0mm:0ss");
			theImported.status  += ' by '+theExisting.modifier;
			theCollisionPanel.style.display='none';
			cmi.index=importTiddlers(cmi.index);	// resume with this item
			importStopped();
			break;
		case 'importReplace':		// substitute imported tiddler for existing tiddler
			cmi.lastAction=which;
			var theItem		  = list.options[cmi.index];
			for (var j=0;j<cmi.inbound.length;j++)
			if (cmi.inbound[j].title==theItem.value) break;
			var theImported     = cmi.inbound[j];
			var theExisting	  = store.getTiddler(theItem.value);
			theImported.status  = 'replaces '+theExisting.title;		// mark item for replace
			theImported.status += ' - '+theExisting.modified.formatString("MM/DD/YYYY 0hh:0mm:0ss");
			theImported.status += ' by '+theExisting.modifier;
			theCollisionPanel.style.display='none';
			cmi.index=importTiddlers(cmi.index);	// resume with THIS item
			importStopped();
			break;
		case 'importListSmaller':		// decrease current listbox size, minimum=5
			if (list.options.length==1) break;
			list.size-=(list.size>5)?1:0;
			cmi.listsize=list.size;
			break;
		case 'importListLarger':		// increase current listbox size, maximum=number of items in list
			if (list.options.length==1) break;
			list.size+=(list.size<list.options.length)?1:0;
			cmi.listsize=list.size;
			break;
		case 'importListMaximize':	// toggle listbox size between current and maximum
			if (list.options.length==1) break;
			list.size=(list.size==list.options.length)?cmi.listsize:list.options.length;
			break;
		}
}
//}}}

// // toggle panel
//{{{
config.macros.importTiddlers.showPanel=function(place,show) {
	if (typeof place == "string") var place=document.getElementById(place);
	if (!place||!place.style) return;
	if(anim && config.options.chkAnimate) anim.startAnimating(new Slider(place,show,false,"none"));
	else place.style.display=show?"block":"none";
}
//}}}

// // refresh listbox
//{{{
function refreshImportList(selectedIndex)
{
	var cmi=config.macros.importTiddlers; // abbreviation

	var list  = document.getElementById("importList");
	if (!list) return;
	// if nothing to show, reset list content and size
	if (!cmi.inbound) 
	{
		while (list.length > 0) { list.options[0] = null; }
		list.options[0]=new Option(cmi.loadText,"",false,false);
		list.size=cmi.listsize;

		// toggle buttons and panels
		document.getElementById('importLoad').disabled=false;
		document.getElementById('importLoad').style.display='inline';
		document.getElementById('importStart').disabled=true;
		document.getElementById('importStart').style.visibility="hidden";
		document.getElementById('importOptions').disabled=true;
		document.getElementById('importOptions').style.display='none';
		document.getElementById('fileImportSource').disabled=false;
		document.getElementById('importFromFile').disabled=false;
		document.getElementById('importFromWeb').disabled=false;
		document.getElementById('importStart').value=cmi.startText;
		document.getElementById('importClose').value=cmi.doneText;
		document.getElementById('importSelectPanel').style.display='none';
		document.getElementById('importOptionsPanel').style.display='none';
		return;
	}
	// there are inbound tiddlers loaded...
	// toggle buttons and panels
	document.getElementById('importLoad').disabled=true;
	document.getElementById('importLoad').style.display='none';
	document.getElementById('importStart').style.visibility='visible';
	document.getElementById('importOptions').style.display='inline';
	document.getElementById('importOptions').disabled=false;
	document.getElementById('fileImportSource').disabled=true;
	document.getElementById('importFromFile').disabled=true;
	document.getElementById('importFromWeb').disabled=true;
	document.getElementById('importClose').value=cmi.closeText;
	if (document.getElementById('importSelectPanel').style.display=='none')
		cmi.showPanel('importSelectPanel',true);

	// get the sort order
	if (!selectedIndex)   selectedIndex=0;
	if (selectedIndex==0) cmi.sort='title';		// heading
	if (selectedIndex==1) cmi.sort='title';
	if (selectedIndex==2) cmi.sort='modified';
	if (selectedIndex==3) cmi.sort='tags';
	if (selectedIndex>3) {
		// display selected tiddler count
		for (var t=0,count=0; t < list.options.length; t++) {
			if (!list.options[t].selected) continue;
			if (list.options[t].value!="")
				count+=1;
			else { // if heading is selected, deselect it, and then select and count all in section
				list.options[t].selected=false;
				for ( t++; t<list.options.length && list.options[t].value!=""; t++) {
					list.options[t].selected=true;
					count++;
				}
			}
		}
		clearMessage(); displayMessage(cmi.countMsg.format([count]));
	}
	document.getElementById('importStart').disabled=!count;
	if (selectedIndex>3) return; // no refresh needed

	// get the alphasorted list of tiddlers
	var tiddlers=cmi.inbound;
	tiddlers.sort(function (a,b) {if(a['title'] == b['title']) return(0); else return (a['title'] < b['title']) ? -1 : +1; });
	// clear current list contents
	while (list.length > 0) { list.options[0] = null; }
	// add heading and control items to list
	var i=0;
	var indent=String.fromCharCode(160)+String.fromCharCode(160);
	if (cmi.all.length==tiddlers.length)
		var summary=cmi.summaryMsg.format([tiddlers.length,(tiddlers.length!=1)?cmi.plural:cmi.single]);
	else
		var summary=cmi.summaryFilteredMsg.format([tiddlers.length,cmi.all.length,(cmi.all.length!=1)?cmi.plural:cmi.single]);
	list.options[i++]=new Option(summary,"",false,false);
	list.options[i++]=new Option(((cmi.sort=="title"   )?">":indent)+' [by title]',"",false,false);
	list.options[i++]=new Option(((cmi.sort=="modified")?">":indent)+' [by date]',"",false,false);
	list.options[i++]=new Option(((cmi.sort=="tags")?">":indent)+' [by tags]',"",false,false);
	// output the tiddler list
	switch(cmi.sort) {
		case "title":
			for(var t = 0; t < tiddlers.length; t++)
				list.options[i++] = new Option(tiddlers[t].title,tiddlers[t].title,false,false);
			break;
		case "modified":
			// sort descending for newest date first
			tiddlers.sort(function (a,b) {if(a['modified'] == b['modified']) return(0); else return (a['modified'] > b['modified']) ? -1 : +1; });
			var lastSection = "";
			for(var t = 0; t < tiddlers.length; t++) {
				var tiddler = tiddlers[t];
				var theSection = tiddler.modified.toLocaleDateString();
				if (theSection != lastSection) {
					list.options[i++] = new Option(theSection,"",false,false);
					lastSection = theSection;
				}
				list.options[i++] = new Option(indent+indent+tiddler.title,tiddler.title,false,false);
			}
			break;
		case "tags":
			var theTitles = {}; // all tiddler titles, hash indexed by tag value
			var theTags = new Array();
			for(var t=0; t<tiddlers.length; t++) {
				var title=tiddlers[t].title;
				var tags=tiddlers[t].tags;
				if (!tags || !tags.length) {
					if (theTitles["untagged"]==undefined) { theTags.push("untagged"); theTitles["untagged"]=new Array(); }
					theTitles["untagged"].push(title);
				}
				else for(var s=0; s<tags.length; s++) {
					if (theTitles[tags[s]]==undefined) { theTags.push(tags[s]); theTitles[tags[s]]=new Array(); }
					theTitles[tags[s]].push(title);
				}
			}
			theTags.sort();
			for(var tagindex=0; tagindex<theTags.length; tagindex++) {
				var theTag=theTags[tagindex];
				list.options[i++]=new Option(theTag,"",false,false);
				for(var t=0; t<theTitles[theTag].length; t++)
					list.options[i++]=new Option(indent+indent+theTitles[theTag][t],theTitles[theTag][t],false,false);
			}
			break;
		}
	list.selectedIndex=selectedIndex;		  // select current control item
	if (list.size<cmi.listsize) list.size=cmi.listsize;
	if (list.size>list.options.length) list.size=list.options.length;
}

config.macros.importTiddlers.filterTiddlerList=function(success,params,txt,src,xhr) {
	var cmi=config.macros.importTiddlers; // abbreviation
	var src=src.replace(/%20/g," ");
	if (!success) { displayMessage(cmi.openErrMsg.format([src,xhr.status])); return; }
	cmi.all = cmi.readTiddlersFromHTML(txt);
	var count=cmi.all?cmi.all.length:0;
	var querypos=src.lastIndexOf("?"); if (querypos!=-1) src=src.substr(0,querypos);
	displayMessage(cmi.foundMsg.format([count,src]));
	cmi.inbound=cmi.filterByHash(params,cmi.all); // use full URL including hash (if any)
	document.getElementById("importLastFilter").value=cmi.lastFilter;
	window.refreshImportList(0);
}

config.macros.importTiddlers.filterByHash=function(src,tiddlers)
{
	var hashpos=src.lastIndexOf("#"); if (hashpos==-1) return tiddlers;
	var hash=src.substr(hashpos+1); if (!hash.length) return tiddlers;
	var tids=[];
	var params=hash.parseParams("anon",null,true,false,false);
	for (var p=1; p<params.length; p++) {
		switch (params[p].name) {
			case "anon":
			case "open":
				tids.pushUnique(params[p].value);
				break;
			case "tag":
				if (store.getMatchingTiddlers) { // for boolean expressions - see MatchTagsPlugin
					var r=store.getMatchingTiddlers(params[p].value,null,tiddlers);
					for (var t=0; t<r.length; t++) tids.pushUnique(r[t].title);
				} else for (var t=0; t<tiddlers.length; t++)
					if (tiddlers[t].isTagged(params[p].value))
						tids.pushUnique(tiddlers[t].title);
				break;
			case "story":
				for (var t=0; t<tiddlers.length; t++)
					if (tiddlers[t].title==params[p].value) {
						tiddlers[t].changed();
						for (var s=0; s<tiddlers[t].links.length; s++)
							tids.pushUnique(tiddlers[t].links[s]);
						break;
					}
				break;
			case "search":
				for (var t=0; t<tiddlers.length; t++)
					if (tiddlers[t].text.indexOf(params[p].value)!=-1)
						tids.pushUnique(tiddlers[t].title);
				break;
		}
	}
	var matches=[];
	for (var t=0; t<tiddlers.length; t++)
		if (tids.contains(tiddlers[t].title))
			matches.push(tiddlers[t]);
	displayMessage(config.macros.importTiddlers.filterMsg.format([matches.length,hash]));
	config.macros.importTiddlers.lastFilter=hash;
	return matches;
}
//}}}

// // re-entrant processing for handling import with interactive collision prompting
//{{{
function importTiddlers(startIndex)
{
	var cmi=config.macros.importTiddlers; // abbreviation

	if (!cmi.inbound) return -1;

	var list = document.getElementById('importList');
	if (!list) return;
	var t;
	// if starting new import, reset import status flags
	if (startIndex==0)
		for (var t=0;t<cmi.inbound.length;t++)
			cmi.inbound[t].status="";
	for (var i=startIndex; i<list.options.length; i++)
		{
		// if list item is not selected or is a heading (i.e., has no value), skip it
		if ((!list.options[i].selected) || ((t=list.options[i].value)==""))
			continue;
		for (var j=0;j<cmi.inbound.length;j++)
			if (cmi.inbound[j].title==t) break;
		var inbound = cmi.inbound[j];
		var theExisting = store.getTiddler(inbound.title);
		// avoid redundant import for tiddlers that are listed multiple times (when 'by tags')
		if (inbound.status=="added")
			continue;
		// don't import the "ImportedTiddlers" history from the other document...
		if (inbound.title=='ImportedTiddlers')
			continue;
		// if tiddler exists and import not marked for replace or merge, stop importing
		if (theExisting && (inbound.status.substr(0,7)!="replace") && (inbound.status.substr(0,5)!="merge"))
			return i;
		// assemble tags (remote + existing + added)
		var newTags = "";
		if (cmi.importTags)
			newTags+=inbound.getTags()	// import remote tags
		if (cmi.keepTags && theExisting)
			newTags+=" "+theExisting.getTags(); // keep existing tags
		if (cmi.addTags && cmi.newTags.trim().length)
			newTags+=" "+cmi.newTags; // add new tags
		inbound.set(null,null,null,null,newTags.trim());
		// set the status to 'added' (if not already set by the 'ask the user' UI)
		inbound.status=(inbound.status=="")?'added':inbound.status;
		// set sync fields
		if (cmi.sync) {
			if (!inbound.fields) inbound.fields={}; // for TW2.1.x backward-compatibility
			inbound.fields["server.page.revision"]=inbound.modified.convertToYYYYMMDDHHMM();
			inbound.fields["server.type"]="file";
			inbound.fields["server.host"]=(cmi.local?"file://":"")+cmi.src;
		}
		// do the import!
		store.suspendNotifications();
		store.saveTiddler(inbound.title, inbound.title, inbound.text, inbound.modifier, inbound.modified, inbound.tags, inbound.fields, true, inbound.created);
                store.fetchTiddler(inbound.title).created = inbound.created; // force creation date to imported value (needed for TW2.1.x and earlier)
		store.resumeNotifications();
		}
	return(-1);	// signals that we really finished the entire list
}
//}}}

//{{{
function importStopped()
{
	var cmi=config.macros.importTiddlers; // abbreviation
	var list = document.getElementById('importList');
	var theNewTitle = document.getElementById('importNewTitle');
	if (!list) return;
	if (cmi.index==-1){ 
		document.getElementById('importStart').value=cmi.startText;
		importReport();		// import finished... generate the report
	} else {
		// import collision...
		// show the collision panel and set the title edit field
		document.getElementById('importStart').value=cmi.stopText;
		cmi.showPanel('importCollisionPanel',true);
		theNewTitle.value=list.options[cmi.index].value;
		if (document.getElementById('importApplyToAll').checked
			&& cmi.lastAction
			&& cmi.lastAction.id!="importRename") {
			onClickImportButton(cmi.lastAction);
		}
	}
}
//}}}

// // ''REPORT GENERATOR''
//{{{
function importReport()
{
	var cmi=config.macros.importTiddlers; // abbreviation
	if (!cmi.inbound) return;

	// if import was not completed, the collision panel will still be open... close it now.
	var panel=document.getElementById('importCollisionPanel'); if (panel) panel.style.display='none';

	// get the alphasorted list of tiddlers
	var tiddlers = cmi.inbound;
	// gather the statistics
	var count=0; var total=0;
	for (var t=0; t<tiddlers.length; t++) {
		if (!tiddlers[t].status || !tiddlers[t].status.trim().length) continue;
		if (tiddlers[t].status.substr(0,7)!="skipped") count++;
		total++;
	}
	// generate a report
	if (total) displayMessage(cmi.processedMsg.format([total]));
	if (count && config.options.chkImportReport) {
		// get/create the report tiddler
		var theReport = store.getTiddler('ImportedTiddlers');
		if (!theReport) { theReport= new Tiddler(); theReport.title = 'ImportedTiddlers'; theReport.text  = ""; }
		// format the report content
		var now = new Date();
		var newText = "On "+now.toLocaleString()+", "+config.options.txtUserName
		newText +=" imported "+count+" tiddler"+(count==1?"":"s")+" from\n[["+cmi.src+"|"+cmi.src+"]]:\n";
		if (cmi.addTags && cmi.newTags.trim().length)
			newText += "imported tiddlers were tagged with: \""+cmi.newTags+"\"\n";
		newText += "<<<\n";
		for (var t=0; t<tiddlers.length; t++) if (tiddlers[t].status) newText += "#[["+tiddlers[t].title+"]] - "+tiddlers[t].status+"\n";
		newText += "<<<\n";
		// update the ImportedTiddlers content and show the tiddler
		theReport.text	 = newText+((theReport.text!="")?'\n----\n':"")+theReport.text;
		theReport.modifier = config.options.txtUserName;
		theReport.modified = new Date();
                store.saveTiddler(theReport.title, theReport.title, theReport.text, theReport.modifier, theReport.modified, theReport.tags, theReport.fields);
		story.displayTiddler(null,theReport.title,1,null,null,false);
		story.refreshTiddler(theReport.title,1,true);
	}

	// reset status flags
	for (var t=0; t<cmi.inbound.length; t++) cmi.inbound[t].status="";

	// mark document as dirty and let display update as needed
	if (count) { store.setDirty(true); store.notifyAll(); }

	// always show final message when tiddlers were actually loaded
	if (count) displayMessage(cmi.importedMsg.format([count,tiddlers.length,cmi.src.replace(/%20/g," ")]));
}
//}}}

// // File and XMLHttpRequest I/O
//{{{
config.macros.importTiddlers.askForFilename=function(here) {
	var msg=here.title; // use tooltip as dialog box message
	var path=getLocalPath(document.location.href);
	var slashpos=path.lastIndexOf("/"); if (slashpos==-1) slashpos=path.lastIndexOf("\\"); 
	if (slashpos!=-1) path = path.substr(0,slashpos+1); // remove filename from path, leave the trailing slash
	var file="";
	var result="";
	if(window.Components) { // moz
		try {
			netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
			var nsIFilePicker = window.Components.interfaces.nsIFilePicker;
			var picker = Components.classes['@mozilla.org/filepicker;1'].createInstance(nsIFilePicker);
			picker.init(window, msg, nsIFilePicker.modeOpen);
			var thispath = Components.classes['@mozilla.org/file/local;1'].createInstance(Components.interfaces.nsILocalFile);
			thispath.initWithPath(path);
			picker.displayDirectory=thispath;
			picker.defaultExtension='html';
			picker.defaultString=file;
			picker.appendFilters(nsIFilePicker.filterAll|nsIFilePicker.filterText|nsIFilePicker.filterHTML);
			if (picker.show()!=nsIFilePicker.returnCancel) var result=picker.file.persistentDescriptor;
		}
		catch(e) { alert('error during local file access: '+e.toString()) }
	}
	else { // IE
		try { // XPSP2 IE only
			var s = new ActiveXObject('UserAccounts.CommonDialog');
			s.Filter='All files|*.*|Text files|*.txt|HTML files|*.htm;*.html|';
			s.FilterIndex=3; // default to HTML files;
			s.InitialDir=path;
			s.FileName=file;
			if (s.showOpen()) var result=s.FileName;
		}
		catch(e) {  // fallback
			var result=prompt(msg,path+file);
		}
	}
	return result;
}

config.macros.importTiddlers.fileExists=function(theFile) {
	var found=false;
	if(window.Components) {
		try { netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); }
		catch(e) { return false; } // security access denied
		var file = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile);
		try { file.initWithPath(theFile); }
		catch(e) { return false; } // invalid directory
		found = file.exists();
	}
	else { // use ActiveX FSO object for MSIE 
		var fso = new ActiveXObject("Scripting.FileSystemObject");
		found = fso.FileExists(theFile)
	}
	return found;
}

config.macros.importTiddlers.loadRemoteFile = function(src,callback) {
	if (src==undefined || !src.length) return null; // filename is required
	var original=src; // URL as specified
	var hashpos=src.indexOf("#"); if (hashpos!=-1) src=src.substr(0,hashpos); // URL with #... suffix removed (needed for IE)
	clearMessage();
	displayMessage(this.openMsg.format([src.replace(/%20/g," ")]));
	if (src.substr(0,5)!="http:" && src.substr(0,5)!="file:") { // if src is relative (i.e., not a URL)
		if (!this.fileExists(src)) { // if file cannot be found, might be relative path.. try fixup
			var pathPrefix=document.location.href;  // get current document path and trim off filename
			var slashpos=pathPrefix.lastIndexOf("/"); if (slashpos==-1) slashpos=pathPrefix.lastIndexOf("\\"); 
			if (slashpos!=-1 && slashpos!=pathPrefix.length-1) pathPrefix=pathPrefix.substr(0,slashpos+1);
			src=pathPrefix+src;
			if (pathPrefix.substr(0,5)!="http:") src=getLocalPath(src);
		}
	}
	if (src.substr(0,5)!="http:" && src.substr(0,5)!="file:") { // if not remote URL, read from local filesystem
		var txt=loadFile(src);
		if ((txt==null)||(txt==false)) // file didn't load
			{ displayMessage(config.macros.importTiddlers.openErrMsg.format([src.replace(/%20/g," "),"(filesystem error)"])); }
		else {
			displayMessage(config.macros.importTiddlers.readMsg.format([txt.length,src.replace(/%20/g," ")]));
			if (callback) callback(true,original,convertUTF8ToUnicode(txt),src,null);
		}
	}
	else {
		var name=config.options.txtRemoteUsername; var pass=config.options.txtRemotePassword;
		var xhr=doHttp("GET",src,null,null,name,pass,callback,original,null)
		if (!xhr) displayMessage(config.macros.importTiddlers.openErrMsg.format([src,"(XMLHTTPRequest error)"]));
	}
}

config.macros.importTiddlers.readTiddlersFromHTML=function(html)
{
	var remoteStore=new TiddlyWiki();
	remoteStore.importTiddlyWiki(html);
	return remoteStore.getTiddlers("title");	
}
//}}}
On 2008年7月11日 下午 07:42:52, 比目魚 imported 9 tiddlers from
[[D:\MCSE2008\notebook.html|D:\MCSE2008\notebook.html]]:
<<<
#[[AD系統 (Active Directory)]] - added
#[[Chap 1 - 建置AD系統]] - added
#[[Chap 2 - 網域用戶端系統]] - added
#[[Chap 3 - 管理組織單位 (Organization Unit)]] - added
#[[Chap 4 - 管理網域使用者帳號]] - added
#[[Chap 5 - 管理網域群組]] - added
#[[Chap 6 - 群組原則 (GPO) 規劃與應用]] - added
#[[Chap 7 - AD 委派授權 (Delegation)]] - added
#[[Chap 8 - AD 線上維護]] - added
<<<
/***
|''Name:''|IntelliTaggerPlugin|
|''Version:''|1.0.2 (2007-07-25)|
|''Type:''|plugin|
|''Source:''|http://tiddlywiki.abego-software.de/#IntelliTaggerPlugin|
|''Author:''|Udo Borkowski (ub [at] abego-software [dot] de)|
|''Documentation:''|[[IntelliTaggerPlugin Documentation]]|
|''~SourceCode:''|[[IntelliTaggerPlugin SourceCode]]|
|''Licence:''|[[BSD open source license (abego Software)]]|
|''~CoreVersion:''|2.0.8|
|''Browser:''|Firefox 1.5.0.2 or better|
***/
/***
!Version History
* 1.0.2 (2007-07-25): 
** Feature: "Return" key may be used to accept first tag suggestion (beside "Alt-1")
** Bugfix: Keyboard shortcuts (Alt+3 etc.) shifted
* 1.0.1 (2007-05-18): Improvement: Speedup when using TiddlyWikis with many tags
* 1.0.0 (2006-04-26): Initial release

***/
// /%
if(!version.extensions.IntelliTaggerPlugin){if(!window.abego){window.abego={};}if(!abego.internal){abego.internal={};}abego.alertAndThrow=function(s){alert(s);throw s;};if(version.major<2){abego.alertAndThrow("Use TiddlyWiki 2.0.8 or better to run the IntelliTagger Plugin.");}version.extensions.IntelliTaggerPlugin={major:1,minor:0,revision:2,date:new Date(2007,6,25),type:"plugin",source:"http://tiddlywiki.abego-software.de/#IntelliTaggerPlugin",documentation:"[[IntelliTaggerPlugin Documentation]]",sourcecode:"[[IntelliTaggerPlugin SourceCode]]",author:"Udo Borkowski (ub [at] abego-software [dot] de)",licence:"[[BSD open source license (abego Software)]]",tiddlywiki:"Version 2.0.8 or better",browser:"Firefox 1.5.0.2 or better"};abego.createEllipsis=function(_2){var e=createTiddlyElement(_2,"span");e.innerHTML="&hellip;";};abego.isPopupOpen=function(_4){return _4&&_4.parentNode==document.body;};abego.openAsPopup=function(_5){if(_5.parentNode!=document.body){document.body.appendChild(_5);}};abego.closePopup=function(_6){if(abego.isPopupOpen(_6)){document.body.removeChild(_6);}};abego.getWindowRect=function(){return {left:findScrollX(),top:findScrollY(),height:findWindowHeight(),width:findWindowWidth()};};abego.moveElement=function(_7,_8,_9){_7.style.left=_8+"px";_7.style.top=_9+"px";};abego.centerOnWindow=function(_a){if(_a.style.position!="absolute"){throw "abego.centerOnWindow: element must have absolute position";}var _b=abego.getWindowRect();abego.moveElement(_a,_b.left+(_b.width-_a.offsetWidth)/2,_b.top+(_b.height-_a.offsetHeight)/2);};abego.isDescendantOrSelf=function(_c,e){while(e){if(_c==e){return true;}e=e.parentNode;}return false;};abego.toSet=function(_e){var _f={};for(var i=0;i<_e.length;i++){_f[_e[i]]=true;}return _f;};abego.filterStrings=function(_11,_12,_13){var _14=[];for(var i=0;i<_11.length&&(_13===undefined||_14.length<_13);i++){var s=_11[i];if(s.match(_12)){_14.push(s);}}return _14;};abego.arraysAreEqual=function(a,b){if(!a){return !b;}if(!b){return false;}var n=a.length;if(n!=b.length){return false;}for(var i=0;i<n;i++){if(a[i]!=b[i]){return false;}}return true;};abego.moveBelowAndClip=function(_1b,_1c){if(!_1c){return;}var _1d=findPosX(_1c);var _1e=findPosY(_1c);var _1f=_1c.offsetHeight;var _20=_1d;var _21=_1e+_1f;var _22=findWindowWidth();if(_22<_1b.offsetWidth){_1b.style.width=(_22-100)+"px";}var _23=_1b.offsetWidth;if(_20+_23>_22){_20=_22-_23-30;}if(_20<0){_20=0;}_1b.style.left=_20+"px";_1b.style.top=_21+"px";_1b.style.display="block";};abego.compareStrings=function(a,b){return (a==b)?0:(a<b)?-1:1;};abego.sortIgnoreCase=function(arr){var _27=[];var n=arr.length;for(var i=0;i<n;i++){var s=arr[i];_27.push([s.toString().toLowerCase(),s]);}_27.sort(function(a,b){return (a[0]==b[0])?0:(a[0]<b[0])?-1:1;});for(i=0;i<n;i++){arr[i]=_27[i][1];}};abego.getTiddlerField=function(_2d,_2e,_2f){var _30=document.getElementById(_2d.idPrefix+_2e);var e=null;if(_30!=null){var _32=_30.getElementsByTagName("*");for(var t=0;t<_32.length;t++){var c=_32[t];if(c.tagName.toLowerCase()=="input"||c.tagName.toLowerCase()=="textarea"){if(!e){e=c;}if(c.getAttribute("edit")==_2f){e=c;}}}}return e;};abego.setRange=function(_35,_36,end){if(_35.setSelectionRange){_35.setSelectionRange(_36,end);var max=0+_35.scrollHeight;var len=_35.textLength;var top=max*_36/len,bot=max*end/len;_35.scrollTop=Math.min(top,(bot+top-_35.clientHeight)/2);}else{if(_35.createTextRange!=undefined){var _3b=_35.createTextRange();_3b.collapse();_3b.moveEnd("character",end);_3b.moveStart("character",_36);_3b.select();}else{_35.select();}}};abego.internal.TagManager=function(){var _3c=null;var _3d=function(){if(_3c){return;}_3c={};store.forEachTiddler(function(_3e,_3f){for(var i=0;i<_3f.tags.length;i++){var tag=_3f.tags[i];var _42=_3c[tag];if(!_42){_42=_3c[tag]={count:0,tiddlers:{}};}_42.tiddlers[_3f.title]=true;_42.count+=1;}});};var _43=TiddlyWiki.prototype.saveTiddler;TiddlyWiki.prototype.saveTiddler=function(_44,_45,_46,_47,_48,_49){var _4a=this.fetchTiddler(_44);var _4b=_4a?_4a.tags:[];var _4c=(typeof _49=="string")?_49.readBracketedList():_49;_43.apply(this,arguments);if(!abego.arraysAreEqual(_4b,_4c)){abego.internal.getTagManager().reset();}};var _4d=TiddlyWiki.prototype.removeTiddler;TiddlyWiki.prototype.removeTiddler=function(_4e){var _4f=this.fetchTiddler(_4e);var _50=_4f&&_4f.tags.length>0;_4d.apply(this,arguments);if(_50){abego.internal.getTagManager().reset();}};this.reset=function(){_3c=null;};this.getTiddlersWithTag=function(tag){_3d();var _52=_3c[tag];return _52?_52.tiddlers:null;};this.getAllTags=function(_53){_3d();var _54=[];for(var i in _3c){_54.push(i);}for(i=0;_53&&i<_53.length;i++){_54.pushUnique(_53[i],true);}abego.sortIgnoreCase(_54);return _54;};this.getTagInfos=function(){_3d();var _56=[];for(var _57 in _3c){_56.push([_57,_3c[_57]]);}return _56;};var _58=function(a,b){var a1=a[1];var b1=b[1];var d=b[1].count-a[1].count;return d!=0?d:abego.compareStrings(a[0].toLowerCase(),b[0].toLowerCase());};this.getSortedTagInfos=function(){_3d();var _5e=this.getTagInfos();_5e.sort(_58);return _5e;};this.getPartnerRankedTags=function(_5f){var _60={};for(var i=0;i<_5f.length;i++){var _62=this.getTiddlersWithTag(_5f[i]);for(var _63 in _62){var _64=store.getTiddler(_63);if(!(_64 instanceof Tiddler)){continue;}for(var j=0;j<_64.tags.length;j++){var tag=_64.tags[j];var c=_60[tag];_60[tag]=c?c+1:1;}}}var _68=abego.toSet(_5f);var _69=[];for(var n in _60){if(!_68[n]){_69.push(n);}}_69.sort(function(a,b){var d=_60[b]-_60[a];return d!=0?d:abego.compareStrings(a.toLowerCase(),b.toLowerCase());});return _69;};};abego.internal.getTagManager=function(){if(!abego.internal.gTagManager){abego.internal.gTagManager=new abego.internal.TagManager();}return abego.internal.gTagManager;};(function(){var _6e=2;var _6f=1;var _70=30;var _71;var _72;var _73;var _74;var _75;var _76;if(!abego.IntelliTagger){abego.IntelliTagger={};}var _77=function(){return _72;};var _78=function(tag){return _75[tag];};var _7a=function(s){var i=s.lastIndexOf(" ");return (i>=0)?s.substr(0,i):"";};var _7d=function(_7e){var s=_7e.value;var len=s.length;return (len>0&&s[len-1]!=" ");};var _81=function(_82){var s=_82.value;var len=s.length;if(len>0&&s[len-1]!=" "){_82.value+=" ";}};var _85=function(tag,_87,_88){if(_7d(_87)){_87.value=_7a(_87.value);}story.setTiddlerTag(_88.title,tag,0);_81(_87);abego.IntelliTagger.assistTagging(_87,_88);};var _89=function(n){if(_76&&_76.length>n){return _76[n];}return (_74&&_74.length>n)?_74[n]:null;};var _8b=function(n,_8d,_8e){var _8f=_89(n);if(_8f){_85(_8f,_8d,_8e);}};var _90=function(_91){var pos=_91.value.lastIndexOf(" ");var _93=(pos>=0)?_91.value.substr(++pos,_91.value.length):_91.value;return new RegExp(_93.escapeRegExp(),"i");};var _94=function(_95,_96){var _97=0;for(var i=0;i<_95.length;i++){if(_96[_95[i]]){_97++;}}return _97;};var _99=function(_9a,_9b,_9c){var _9d=1;var c=_9a[_9b];for(var i=_9b+1;i<_9a.length;i++){if(_9a[i][1].count==c){if(_9a[i][0].match(_9c)){_9d++;}}else{break;}}return _9d;};var _a0=function(_a1,_a2){var _a3=abego.internal.getTagManager().getSortedTagInfos();var _a4=[];var _a5=0;for(var i=0;i<_a3.length;i++){var c=_a3[i][1].count;if(c!=_a5){if(_a2&&(_a4.length+_99(_a3,i,_a1)>_a2)){break;}_a5=c;}if(c==1){break;}var s=_a3[i][0];if(s.match(_a1)){_a4.push(s);}}return _a4;};var _a9=function(_aa,_ab){return abego.filterStrings(abego.internal.getTagManager().getAllTags(_ab),_aa);};var _ac=function(){if(!_71){return;}var _ad=store.getTiddlerText("IntelliTaggerMainTemplate");if(!_ad){_ad="<b>Tiddler IntelliTaggerMainTemplate not found</b>";}_71.innerHTML=_ad;applyHtmlMacros(_71,null);refreshElements(_71,null);};var _ae=function(e){if(!e){var e=window.event;}var tag=this.getAttribute("tag");if(_73){_73.call(this,tag,e);}return false;};var _b2=function(_b3){createTiddlyElement(_b3,"span",null,"tagSeparator"," | ");};var _b4=function(_b5,_b6,_b7,_b8,_b9){if(!_b6){return;}var _ba=_b8?abego.toSet(_b8):{};var n=_b6.length;var c=0;for(var i=0;i<n;i++){var tag=_b6[i];if(_ba[tag]){continue;}if(c>0){_b2(_b5);}if(_b9&&c>=_b9){abego.createEllipsis(_b5);break;}c++;var _bf="";var _c0=_b5;if(_b7<10){_c0=createTiddlyElement(_b5,"span",null,"numberedSuggestion");_b7++;var key=_b7<10?""+(_b7):"0";createTiddlyElement(_c0,"span",null,"suggestionNumber",key+") ");var _c2=_b7==1?"Return or ":"";_bf=" (Shortcut: %1Alt-%0)".format([key,_c2]);}var _c3=config.views.wikified.tag.tooltip.format([tag]);var _c4=(_78(tag)?"Remove tag '%0'%1":"Add tag '%0'%1").format([tag,_bf]);var _c5="%0; Shift-Click: %1".format([_c4,_c3]);var btn=createTiddlyButton(_c0,tag,_c5,_ae,_78(tag)?"currentTag":null);btn.setAttribute("tag",tag);}};var _c7=function(){if(_71){window.scrollTo(0,ensureVisible(_71));}if(_77()){window.scrollTo(0,ensureVisible(_77()));}};var _c8=function(e){if(!e){var e=window.event;}if(!_71){return;}var _cb=resolveTarget(e);if(_cb==_77()){return;}if(abego.isDescendantOrSelf(_71,_cb)){return;}abego.IntelliTagger.close();};addEvent(document,"click",_c8);var _cc=Story.prototype.gatherSaveFields;Story.prototype.gatherSaveFields=function(e,_ce){_cc.apply(this,arguments);var _cf=_ce.tags;if(_cf){_ce.tags=_cf.trim();}};var _d0=function(_d1){story.focusTiddler(_d1,"tags");var _d2=abego.getTiddlerField(story,_d1,"tags");if(_d2){var len=_d2.value.length;abego.setRange(_d2,len,len);window.scrollTo(0,ensureVisible(_d2));}};var _d4=config.macros.edit.handler;config.macros.edit.handler=function(_d5,_d6,_d7,_d8,_d9,_da){_d4.apply(this,arguments);var _db=_d7[0];if((_da instanceof Tiddler)&&_db=="tags"){var _dc=_d5.lastChild;_dc.onfocus=function(e){abego.IntelliTagger.assistTagging(_dc,_da);setTimeout(function(){_d0(_da.title);},100);};_dc.onkeyup=function(e){if(!e){var e=window.event;}if(e.altKey&&!e.ctrlKey&&!e.metaKey&&(e.keyCode>=48&&e.keyCode<=57)){_8b(e.keyCode==48?9:e.keyCode-49,_dc,_da);}else{if(e.ctrlKey&&e.keyCode==32){_8b(0,_dc,_da);}}if(!e.ctrlKey&&(e.keyCode==13||e.keyCode==10)){_8b(0,_dc,_da);}setTimeout(function(){abego.IntelliTagger.assistTagging(_dc,_da);},100);return false;};_81(_dc);}};var _e0=function(e){if(!e){var e=window.event;}var _e3=resolveTarget(e);var _e4=_e3.getAttribute("tiddler");if(_e4){story.displayTiddler(_e3,_e4,"IntelliTaggerEditTagsTemplate",false);_d0(_e4);}return false;};var _e5=config.macros.tags.handler;config.macros.tags.handler=function(_e6,_e7,_e8,_e9,_ea,_eb){_e5.apply(this,arguments);abego.IntelliTagger.createEditTagsButton(_eb,createTiddlyElement(_e6.lastChild,"li"));};var _ec=function(){if(_71&&_72&&!abego.isDescendantOrSelf(document,_72)){abego.IntelliTagger.close();}};setInterval(_ec,100);abego.IntelliTagger.displayTagSuggestions=function(_ed,_ee,_ef,_f0,_f1){_74=_ed;_75=abego.toSet(_ee);_76=_ef;_72=_f0;_73=_f1;if(!_71){_71=createTiddlyElement(document.body,"div",null,"intelliTaggerSuggestions");_71.style.position="absolute";}_ac();abego.openAsPopup(_71);if(_77()){var w=_77().offsetWidth;if(_71.offsetWidth<w){_71.style.width=(w-2*(_6e+_6f))+"px";}abego.moveBelowAndClip(_71,_77());}else{abego.centerOnWindow(_71);}_c7();};abego.IntelliTagger.assistTagging=function(_f3,_f4){var _f5=_90(_f3);var s=_f3.value;if(_7d(_f3)){s=_7a(s);}var _f7=s.readBracketedList();var _f8=_f7.length>0?abego.filterStrings(abego.internal.getTagManager().getPartnerRankedTags(_f7),_f5,_70):_a0(_f5,_70);abego.IntelliTagger.displayTagSuggestions(_a9(_f5,_f7),_f7,_f8,_f3,function(tag,e){if(e.shiftKey){onClickTag.call(this,e);}else{_85(tag,_f3,_f4);}});};abego.IntelliTagger.close=function(){abego.closePopup(_71);_71=null;return false;};abego.IntelliTagger.createEditTagsButton=function(_fb,_fc,_fd,_fe,_ff,id,_101){if(!_fd){_fd="[edit]";}if(!_fe){_fe="Edit the tags";}if(!_ff){_ff="editTags";}var _102=createTiddlyButton(_fc,_fd,_fe,_e0,_ff,id,_101);_102.setAttribute("tiddler",(_fb instanceof Tiddler)?_fb.title:String(_fb));return _102;};abego.IntelliTagger.getSuggestionTagsMaxCount=function(){return 100;};config.macros.intelliTagger={label:"intelliTagger",handler:function(_103,_104,_105,_106,_107,_108){var _109=_107.parseParams("list",null,true);var _10a=_109[0]["action"];for(var i=0;_10a&&i<_10a.length;i++){var _10c=_10a[i];var _10d=config.macros.intelliTagger.subhandlers[_10c];if(!_10d){abego.alertAndThrow("Unsupported action '%0'".format([_10c]));}_10d(_103,_104,_105,_106,_107,_108);}},subhandlers:{showTags:function(_10e,_10f,_110,_111,_112,_113){_b4(_10e,_74,_76?_76.length:0,_76,abego.IntelliTagger.getSuggestionTagsMaxCount());},showFavorites:function(_114,_115,_116,_117,_118,_119){_b4(_114,_76,0);},closeButton:function(_11a,_11b,_11c,_11d,_11e,_11f){var _120=createTiddlyButton(_11a,"close","Close the suggestions",abego.IntelliTagger.close);},version:function(_121){var t="IntelliTagger %0.%1.%2".format([version.extensions.IntelliTaggerPlugin.major,version.extensions.IntelliTaggerPlugin.minor,version.extensions.IntelliTaggerPlugin.revision]);var e=createTiddlyElement(_121,"a");e.setAttribute("href","http://tiddlywiki.abego-software.de/#IntelliTaggerPlugin");e.innerHTML="<font color=\"black\" face=\"Arial, Helvetica, sans-serif\">"+t+"<font>";},copyright:function(_124){var e=createTiddlyElement(_124,"a");e.setAttribute("href","http://tiddlywiki.abego-software.de");e.innerHTML="<font color=\"black\" face=\"Arial, Helvetica, sans-serif\">&copy; 2006-2007 <b><font color=\"red\">abego</font></b> Software<font>";}}};})();config.shadowTiddlers["IntelliTaggerStyleSheet"]="/***\n"+"!~IntelliTagger Stylesheet\n"+"***/\n"+"/*{{{*/\n"+".intelliTaggerSuggestions {\n"+"\tposition: absolute;\n"+"\twidth: 600px;\n"+"\n"+"\tpadding: 2px;\n"+"\tlist-style: none;\n"+"\tmargin: 0;\n"+"\n"+"\tbackground: #eeeeee;\n"+"\tborder: 1px solid DarkGray;\n"+"}\n"+"\n"+".intelliTaggerSuggestions .currentTag   {\n"+"\tfont-weight: bold;\n"+"}\n"+"\n"+".intelliTaggerSuggestions .suggestionNumber {\n"+"\tcolor: #808080;\n"+"}\n"+"\n"+".intelliTaggerSuggestions .numberedSuggestion{\n"+"\twhite-space: nowrap;\n"+"}\n"+"\n"+".intelliTaggerSuggestions .intelliTaggerFooter {\n"+"\tmargin-top: 4px;\n"+"\tborder-top-width: thin;\n"+"\tborder-top-style: solid;\n"+"\tborder-top-color: #999999;\n"+"}\n"+".intelliTaggerSuggestions .favorites {\n"+"\tborder-bottom-width: thin;\n"+"\tborder-bottom-style: solid;\n"+"\tborder-bottom-color: #999999;\n"+"\tpadding-bottom: 2px;\n"+"}\n"+"\n"+".intelliTaggerSuggestions .normalTags {\n"+"\tpadding-top: 2px;\n"+"}\n"+"\n"+".intelliTaggerSuggestions .intelliTaggerFooter .button {\n"+"\tfont-size: 10px;\n"+"\n"+"\tpadding-left: 0.3em;\n"+"\tpadding-right: 0.3em;\n"+"}\n"+"\n"+"/*}}}*/\n";config.shadowTiddlers["IntelliTaggerMainTemplate"]="<!--\n"+"{{{\n"+"-->\n"+"<div class=\"favorites\" macro=\"intelliTagger action: showFavorites\"></div>\n"+"<div class=\"normalTags\" macro=\"intelliTagger action: showTags\"></div>\n"+"<!-- The Footer (with the Navigation) ============================================ -->\n"+"<table class=\"intelliTaggerFooter\" border=\"0\" width=\"100%\" cellspacing=\"0\" cellpadding=\"0\"><tbody>\n"+"  <tr>\n"+"\t<td align=\"left\">\n"+"\t\t<span macro=\"intelliTagger action: closeButton\"></span>\n"+"\t</td>\n"+"\t<td align=\"right\">\n"+"\t\t<span macro=\"intelliTagger action: version\"></span>, <span macro=\"intelliTagger action: copyright \"></span>\n"+"\t</td>\n"+"  </tr>\n"+"</tbody></table>\n"+"<!--\n"+"}}}\n"+"-->\n";config.shadowTiddlers["IntelliTaggerEditTagsTemplate"]="<!--\n"+"{{{\n"+"-->\n"+"<div class='toolbar' macro='toolbar +saveTiddler -cancelTiddler'></div>\n"+"<div class='title' macro='view title'></div>\n"+"<div class='tagged' macro='tags'></div>\n"+"<div class='viewer' macro='view text wikified'></div>\n"+"<div class='toolbar' macro='toolbar +saveTiddler -cancelTiddler'></div>\n"+"<div class='editor' macro='edit tags'></div><div class='editorFooter'><span macro='message views.editor.tagPrompt'></span><span macro='tagChooser'></span></div>\n"+"<!--\n"+"}}}\n"+"-->\n";config.shadowTiddlers["BSD open source license (abego Software)"]="See [[Licence|http://tiddlywiki.abego-software.de/#%5B%5BBSD%20open%20source%20license%5D%5D]].";config.shadowTiddlers["IntelliTaggerPlugin Documentation"]="[[Documentation on abego Software website|http://tiddlywiki.abego-software.de/doc/IntelliTagger.pdf]].";config.shadowTiddlers["IntelliTaggerPlugin SourceCode"]="[[Plugin source code on abego Software website|http://tiddlywiki.abego-software.de/archive/IntelliTaggerPlugin/Plugin-IntelliTagger-src.1.0.2.js]]\n";(function(){var _126=restart;restart=function(){setStylesheet(store.getTiddlerText("IntelliTaggerStyleSheet"),"IntelliTaggerStyleSheet");_126.apply(this,arguments);};})();}
// %/
/***
|''Name:''|IntelliTagsEditCommandPlugin|
|''Version:''|1.0.0 (2007-10-03)|
|''Type:''|plugin|
|''Description:''|A command for your tiddler's toolbar to directly edit the tiddler's tags using the IntelliTaggerPlugin, without switching to "edit mode".|
|''Source:''|http://tiddlywiki.abego-software.de/#IntelliTagsEditCommandPlugin|
|''Requires:''|IntelliTaggerPlugin http://tiddlywiki.abego-software.de/#IntelliTaggerPlugin|
|''Author:''|Udo Borkowski (ub [at] abego-software [dot] de)|
|''Licence:''|[[BSD open source license (abego Software)]]|
|''~CoreVersion:''|2.0.8|
|''Browser:''|Firefox 1.5.0.2 or better|
***/
/***
!Using the "IntelliTagsEditCommandPlugin"
Add the command {{{intelliTagsEdit}}} into the 'macro' attribute of the 'toolbar' {{{<div...>}}} in your ViewTemplate.

''Example:''
{{{
<div class='toolbar' 
        macro='toolbar -closeTiddler closeOthers +editTiddler intelliTagsEdit permalink references jump'>
</div>
}}}

This adds a "tags" button to the toolbar of the tiddlers (next to the ''edit'' button). Pressing the "tags" button will open the input field for the tiddler's tags and let you edit the tags with all the [[IntelliTaggerPlugin|http://tiddlywiki.abego-software.de/#IntelliTaggerPlugin]] features.
***/
/***
!Source Code
***/
//{{{
(function(){

if (!version.extensions.IntelliTaggerPlugin)
    throw Error("IntelliTagsEditCommandPlugin requires the IntelliTaggerPlugin (http://tiddlywiki.abego-software.de/#IntelliTaggerPlugin)");

if (config.commands.intelliTagsEdit) 
    return;

config.commands.intelliTagsEdit = {
	text: "tags",
	tooltip: "edit the tags"
};

config.commands.intelliTagsEdit.handler = function(event,src,title) {
	var button = abego.IntelliTagger.createEditTagsButton(title, null, "tags", "edit the tags");
	button.onclick(event);
	return false;
};

})();
//}}}
<<tagsTree domain "" 2 4 index label>>
<<tagsTree 2279 "" 2 4 index label>>
<<tagsTree supplement "" 1 4 index label>>
<<tagsTree twcms "" 1 4 index label>>
<<tagsTree KMKConfig "" 1 4 index label>>
<<tabs txtMainTab "最近更新" "依更新日期排序" TabTimeline "分類" "所有標籤" TabTags "設定文章" "說所有設定文章" TabMoreShadowed>>

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

<!--{{{-->
<style type="text/css">
#contentWrapper {display:none;}
</style>

<div id="SplashScreen" style="border: 3px solid #ccc; display: block; text-align: center; width: 320px; margin: 100px auto; padding: 50px; color:#000; font-size: 28px; font-family:Tahoma; background-color:#eee;">
<b>Sky of flatfish</b><br><br><img src="loader.gif"><br>
<span style="font-size: 14px; color:red;">Requires Javascript.</span>
</div>
<!--}}}-->
<!--{{{-->
<div class='header' macro='gradient vert [[ColorPalette::PrimaryLight]] [[ColorPalette::PrimaryDark]]'>
<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='toolBar' refresh='content' force='true' tiddler='ToolBar'></div>
<div id='mainMenu' refresh='content' force='true' tiddler='MainMenu'></div>

<!--
<div id='sidebar'>
<div id='sidebarTabs' refresh='content' force='true' tiddler='SideBarTabs'></div>
</div>
-->

<div id='displayArea'>
<div id='messageArea'></div>
<div id='tiddlersBar' refresh='none' ondblclick='config.macros.tiddlersBar.onTiddlersBarAction(event)'></div>
<div id='tiddlerDisplay'></div>
</div>
<!--}}}-->
//{{{
//============================================================================
//                           PartTiddlerPlugin

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

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

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

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

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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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




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

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

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

	return this.abegoIsPartTiddler;
}

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

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

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

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

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

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

} // of "install only once"
//}}}
<<tabs txtMainTab "最近更新" "依更新日期排序" TabTimeline "分類" "所有標籤" TabTags "設定文章" "說所有設定文章" TabMoreShadowed>>
<<showUpdates excludeTag:excludeLists write:'(index < 10) ? ""+""+ tiddler.modified.formatString("YYYY年0MM月0DD日")+ "\n&nbsp;&nbsp;&nbsp;&nbsp;[["  +tiddler.title+"]]"+"\n" : ""'>>
''flatfish''@2008 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;powered by TWtBala - TiddlyWiki 2.3.0
比目魚的天空 - 讓人藍藍的 AD !!!
/***
|''Name:''|SparklinePlugin|
|''Description:''|Sparklines macro|
***/
//{{{
if(!version.extensions.SparklinePlugin) {
version.extensions.SparklinePlugin = {installed:true};

//--
//-- Sparklines
//--

config.macros.sparkline = {};
config.macros.sparkline.handler = function(place,macroName,params)
{
	var data = [];
	var min = 0;
	var max = 0;
	var v;
	for(var t=0; t<params.length; t++) {
		v = parseInt(params[t]);
		if(v < min)
			min = v;
		if(v > max)
			max = v;
		data.push(v);
	}
	if(data.length < 1)
		return;
	var box = createTiddlyElement(place,"span",null,"sparkline",String.fromCharCode(160));
	box.title = data.join(",");
	var w = box.offsetWidth;
	var h = box.offsetHeight;
	box.style.paddingRight = (data.length * 2 - w) + "px";
	box.style.position = "relative";
	for(var d=0; d<data.length; d++) {
		var tick = document.createElement("img");
		tick.border = 0;
		tick.className = "sparktick";
		tick.style.position = "absolute";
		tick.src = "data:image/gif,GIF89a%01%00%01%00%91%FF%00%FF%FF%FF%00%00%00%C0%C0%C0%00%00%00!%F9%04%01%00%00%02%00%2C%00%00%00%00%01%00%01%00%40%02%02T%01%00%3B";
		tick.style.left = d*2 + "px";
		tick.style.width = "2px";
		v = Math.floor(((data[d] - min)/(max-min)) * h);
		tick.style.top = (h-v) + "px";
		tick.style.height = v + "px";
		box.appendChild(tick);
	}
};


}
//}}}
/***

''Inspired by [[TiddlyPom|http://www.warwick.ac.uk/~tuspam/tiddlypom.html]]''

|Name|SplashScreenPlugin|
|Created by|SaqImtiaz|
|Location|http://tw.lewcid.org/#SplashScreenPlugin|
|Version|0.21 |
|Requires|~TW2.08+|
!Description:
Provides a simple splash screen that is visible while the TW is loading.

!Installation
Copy the source text of this tiddler to your TW in a new tiddler, tag it with systemConfig and save and reload. The SplashScreen will now be installed and will be visible the next time you reload your TW.

!Customizing
Once the SplashScreen has been installed and you have reloaded your TW, the splash screen html will be present in the MarkupPreHead tiddler. You can edit it and customize to your needs.

!History
* 20-07-06 : version 0.21, modified to hide contentWrapper while SplashScreen is displayed.
* 26-06-06 : version 0.2, first release

!Code
***/
//{{{
var old_lewcid_splash_restart=restart;

restart = function()
{   if (document.getElementById("SplashScreen"))
        document.getElementById("SplashScreen").style.display = "none";
      if (document.getElementById("contentWrapper"))
        document.getElementById("contentWrapper").style.display = "block";
    
    old_lewcid_splash_restart();
   
    if (splashScreenInstall)
       {if(config.options.chkAutoSave)
			{saveChanges();}
        displayMessage("TW SplashScreen has been installed, please save and refresh your TW.");
        }
}


var oldText = store.getTiddlerText("MarkupPreHead");
if (oldText.indexOf("SplashScreen")==-1)
   {var siteTitle = store.getTiddlerText("SiteTitle");
   var splasher='\n\n<style type="text/css">#contentWrapper {display:none;}</style><div id="SplashScreen" style="border: 3px solid #ccc; display: block; text-align: center; width: 320px; margin: 100px auto; padding: 50px; color:#000; font-size: 28px; font-family:Tahoma; background-color:#eee;"><b>'+siteTitle +'</b> is loading<blink> ...</blink><br><br><span style="font-size: 14px; color:red;">Requires Javascript.</span></div>';
   if (! store.tiddlerExists("MarkupPreHead"))
       {var myTiddler = store.createTiddler("MarkupPreHead");}
   else
      {var myTiddler = store.getTiddler("MarkupPreHead");}
      myTiddler.set(myTiddler.title,oldText+splasher,config.options.txtUserName,null,null);
      store.setDirty(true);
      var splashScreenInstall = true;
}
//}}}
/*{{{*/

/* 主要項目樣式 

    在 Tiddler 中的使用格式如下 :
    {{item1{Item description}}}

*/
.item1{
 line-height:28px;
 font-weight:bold;
 font-size:14px;
 border-left: 10px solid blue;
 margin: 0px 0px 0px 20px;
 padding: 0px 0px 0px 3px;
 background-color:transparent;
}

/* 實作項目樣式 

    在 Tiddler 中的使用格式如下 :
    {{op1{operation description}}}

*/
.op1{
 line-height:28px;
 font-weight:bold; 
 font-size:14px;
 margin:0px 0px 0px 0px;
 padding: 0px 0px 0px 0px;
 background-color:transparent;
}


/*
Making preformated <pre> text wrap in CSS3, Mozilla, Opera and IE

word-wrap: break-word; - 視窗邊界換行,僅 IE 支援。也可以用 word-brak: break-all; 但不會保持英文單字的完整性。
white-space: pre; - 對某標籤作預先格式化,所有標準瀏覽器皆支援。
white-space: -moz-pre-wrap; - 預先格式化,但在元素邊界換行,僅 Mozilla (Firefox) 支援。
white-space: pre-wrap; - 預先格式化,但在元素邊界換行,僅 Opera 支援。
*/
.viewer pre {
  font-size:12px;
  white-space: pre-wrap;       /* css-3 */
  white-space: -moz-pre-wrap;  /* Mozilla, since 1999 */
  white-space: -pre-wrap;      /* Opera 4-6 */
  white-space: -o-pre-wrap;    /* Opera 7 */
  word-wrap: break-word;       /* Internet Explorer 5.5+ */
}
.viewer pre {border:1px solid [[ColorPalette::SecondaryLight]]; background:[[ColorPalette::SecondaryPale]];}


/*
無框線表格樣式設定, 以下是使用範例:

|!Col1|!Col2|!Col3|
|r1c1| r1r2c2 |r1c3|
|r2c1|~|r2c3|
|borderless|k    // 使用格式

*/
.borderless, .borderless table, .borderless td, .borderless tr, .borderless th, .borderless tbody { 
   border:0 !important; margin:0 !important; padding:2px !important; 
   td.vertical-align:top !important;margin-left: auto !important; 
   margin-right: auto !important;
}

.externalLink {text-decoration:none}

#toolBar { 
 background-color: #eee; 
 color:#ccc;
 width: auto;
 text-align:left;
 padding: 0.4em 0.6em 0.4em 0.6em;
}

h1,h2,h3 {padding-bottom:1px; margin-top:0.1em;margin-bottom:0.1em;}
h4,h5,h6 {margin-top:0.1em;}
h1 {font-size:1.2em;}
h2 {font-size:1.0em;}
h3 {font-size:0.8em;}
h4 {font-size:0.6em;}
h5 {font-size:0.4em;}

.headerShadow {position:relative; padding:2.0em 0em 1em 1em; left:-1px; top:-1px;}
.headerForeground {position:absolute; padding:2.0em 0em 1em 1em; left:0px; top:0px;}

#mainMenu {
position:absolute; left:0; width:15.5em; text-align:left; line-height:1.2em; 
padding:1.0em 0.5em 0.2em 0.5em; font-size:1em;
}

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

/*
 toBalaFile 巨集的 Style 設定
*/
.toBalaFile {background:#fff; border:0px solid #ccc; padding:1px 7px 1px 3px; margin:2px;}
.toBalaFileEdit {border:1px solid #841;padding:2px;margin:2px 5px 2px 5px;}
.toBalaFileCancel {border:1px solid #841;padding:2px;margin:2px 5px 2px 5px;}
.toBalaFileToolBar {background:#fff;border-bottom: 3px solid #841;padding:3px 0px 5px 0px;margin:5px 0px 0px 3px;}
.toBalaFileSave {border:1px solid #841;padding:2px;margin:2px 5px 2px 5px;}

/*}}}*/
/*{{{*/
/***** LAYOUT STYLES -  DO NOT EDIT! *****/
ul.suckerfish, ul.suckerfish ul {
	margin: 0;
	padding: 0;
	list-style: none;
	line-height:1.4em;
}

ul.suckerfish  li {
	display: inline-block; 
	display: block;
	float: left; 
}

ul.suckerfish li ul {
	position: absolute;
	left: -999em;
}

ul.suckerfish li:hover ul, ul.suckerfish li.sfhover ul {
	left: auto;
}

ul.suckerfish ul li {
	float: none;
	border-right: 0;
	border-left:0;
}

ul.suckerfish a, ul.suckerfish a:hover {
	display: block;
}

ul.suckerfish li a.tiddlyLink, ul.suckerfish li a, #mainMenu ul.suckerfish li a {font-weight:bold;}
/**** END LAYOUT STYLES *****/


/**** COLORS AND APPEARANCE - DEFAULT *****/
ul.suckerfish li a {
	padding: 0.5em 1.5em;
	color: #FFF;
	background: #0066aa;
	border-bottom: 0;
	font-weight:bold;
}

ul.suckerfish li:hover a, ul.suckerfish li.sfhover a{
	background: #00558F;
}

ul.suckerfish li:hover ul a, ul.suckerfish li.sfhover ul a{
	color: #000;
	background: #eff3fa;
	border-top:1px solid #FFF;
}

ul.suckerfish ul li a:hover {
	background: #e0e8f5;
}

ul.suckerfish li a{
	width:9em;
}

ul.suckerfish ul li a, ul.suckerfish ul li a:hover{
	display:inline-block;
	width:9em;
}

ul.suckerfish li {
	border-left: 1px solid #00558F;
}
/***** END COLORS AND APPEARANCE - DEFAULT *****/


/***** LAYOUT AND APPEARANCE: VERTICAL *****/
ul.suckerfish.vertical li{
	width:10em;
	border-left: 0px solid #00558f;
}

ul.suckerfish.vertical ul li, ul.suckerfish.vertical li a, ul.suckerfish.vertical li:hover a, ul.suckerfish.vertical li.sfhover a {
	border-left: 0.8em solid #00558f;
}

ul.suckerfish.vertical li a, ul.suckerfish.vertical li:hover a, ul.suckerfish.vertical li.sfhover a,  ul.suckerfish.vertical li.sfhover a:hover{
	width:8em;
}

ul.suckerfish.vertical {
	width:10em; text-align:left;
	float:left;
}

ul.suckerfish.vertical li a {
	padding: 0.5em 1em 0.5em 1em;
	border-top:1px solid  #fff;
}

ul.suckerfish.vertical, ul.suckerfish.vertical ul {
	line-height:1.4em;
}

ul.suckerfish.vertical li:hover ul, ul.suckerfish.vertical li.sfhover ul { 
	margin: -2.4em 0 0 10.9em;
}

ul.suckerfish.vertical li:hover ul li a, ul.suckerfish.vertical li.sfhover ul li a {
	border: 0px solid #FFF;
}

ul.suckerfish.vertical li:hover a, ul.suckerfish.vertical li.sfhover a{
	padding-right:1.1em;
}

ul.suckerfish.vertical li:hover ul li, ul.suckerfish.vertical li.sfhover ul li {
	border-bottom:1px solid  #fff;
}

/***** END LAYOUT AND APPEARANCE: VERTICAL *****/
/*}}}*/
/*{{{*/
* html .tiddler {height:1%;}

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

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

hr {height:1px;}

a {text-decoration:none;}

dt {font-weight:bold;}

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

.txtOptionInput {width:11em;}

#contentWrapper .chkOptionInput {border:0;}

.externalLink {text-decoration:underline;}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

.whenBackstage {display:none;}
.backstageVisible .whenBackstage {display:block;}
/*}}}*/
<<tabs txtMoreTab "未完成" "內容空白的文章" TabMoreMissing "未引用" "未被引用的文章" TabMoreOrphans "預設文章" "已預設內容的隱藏文章" TabMoreShadowed>>
<<list shadowed>>
<<allTags excludeLists>>
<<timeline created 15>>
/***
|Name|TaggedTemplateTweak|
|Source|http://www.TiddlyTools.com/#TaggedTemplateTweak|
|Version|1.1.0|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|plugin|
|Requires||
|Overrides|Story.prototype.chooseTemplateForTiddler()|
|Description|use alternative ViewTemplate/EditTemplate for tiddler's tagged with specific tag values|
The core function, "story.chooseTemplateForTiddler(title,template)" is essentially a "pass-thru" that returns the same template it was given, and is provided by the core so that plugins can customize the template selection logic to select alternative templates, based on whatever programmatic criteria is appropriate.  This tweak extends story.chooseTemplateForTiddler() so that ''whenever a tiddler is marked with a specific tag value, it can be viewed and/or edited using alternatives to the standard tiddler templates.'' 
!!!!!Usage
<<<
Each alternative template is associated with a specific tiddler tag value by using that tag value as a prefix added to the standard TiddlyWiki template titles, [[ViewTemplate]] and [[EditTemplate]].

For example, any tiddlers that are tagged with ''<<tag media>>'' will look for alternative templates named [[mediaViewTemplate]] and [[mediaEditTemplate]].  Additionally, in order to find templates that have proper WikiWord tiddler titles (e.g., [[MediaViewTemplate]] and [[MediaEditTemplate]]), the plugin will also attempt to use a capitalized form of the tag value (e.g., ''Media'') as a prefix.  //This capitalization is for comparison purposes only and will not alter the actual tag values that are stored in the tiddler.//

If no matching alternative template can be found by using //any// of the tiddler's tags (either "as-is" or capitalized), the tiddler defaults to using the appropriate standard [[ViewTemplate]] or [[EditTemplate]] definition.

''To add your own custom templates:''
>First, decide upon a suitable tag keyword to uniquely identify your custom templates and create custom view and/or edit templates using that keyword as a prefix (e.g., "KeywordViewTemplate" and "KeywordEditTemplate").  Then, simply create a tiddler and tag it with your chosen keyword... that's it!  As long as the tiddler is tagged with your keyword, it will be displayed using the corresponding alternative templates.  If you remove the tag or rename/delete the alternative templates, the tiddler will revert to using the standard viewing and editing templates.
<<<
!!!!!Examples
<<<
|Sample tiddler| tag | view template | edit template |
|[[MediaSample - QuickTime]]| <<tag media>> | [[MediaViewTemplate]] | [[MediaEditTemplate]] |
|[[MediaSample - Windows]]| <<tag media>> | [[MediaViewTemplate]] | [[MediaEditTemplate]] |
|[[CDSample]]| <<tag CD>> | [[CDViewTemplate]] | [[CDEditTemplate]] |
|<<newTiddler label:"create new task..." title:SampleTask tag:task text:"Type some text and then press DONE to view the task controls">> | <<tag task>> | [[TaskViewTemplate]] | [[EditTemplate]] |

//(note: if these samples are not present in your document, please visit// http://www.TiddlyTools.com/ //to view these sample tiddlers on-line)//
<<<
!!!!!Revisions
<<<
2007.06.23 [1.1.0] re-written to use automatic 'tag prefix' search instead of hard coded check for each tag.  Allows new custom tags to be used without requiring code changes to this plugin.
2007.06.11 [1.0.0] initial release
<<<
!!!!!Code
***/
//{{{
version.extensions.taggedTemplate= {major: 1, minor: 1, revision: 0, date: new Date(2007,6,18)};
Story.prototype.taggedTemplate_chooseTemplateForTiddler = Story.prototype.chooseTemplateForTiddler
Story.prototype.chooseTemplateForTiddler = function(title,template)
{
	// get default template from core
	var template=this.taggedTemplate_chooseTemplateForTiddler.apply(this,arguments);

	// if the tiddler to be rendered doesn't exist yet, just return core result
	var tiddler=store.getTiddler(title); if (!tiddler) return template;

	// look for template whose prefix matches a tag on this tiddler
	for (t=0; t<tiddler.tags.length; t++) {
		var tag=tiddler.tags[t];
		if (store.tiddlerExists(tag+template)) { template=tag+template; break; }
		// try capitalized tag (to match WikiWord template titles)
		var cap=tag.substr(0,1).toUpperCase()+tag.substr(1);
		if (store.tiddlerExists(cap+template)) { template=cap+template; break; }
	}

	return template;
}
//}}}
/***
|''Name:''|~TaggerPlugin|
|''Version:''|1.0.1 (2006-06-01)|
|''Source:''|http://tw.lewcid.org//#TaggerPlugin|
|''Author:''|SaqImtiaz|
|''Description:''|Provides a drop down listing current tiddler tags, and allowing toggling of tags.|
|''Documentation:''|[[TaggerPluginDocumentation]]|
|''Source Code:''|[[TaggerPluginSource]]|
|''~TiddlyWiki:''|Version 2.0.8 or better|
***/
// /%
config.tagger={defaults:{label:"Tags: ",tooltip:"Manage tiddler tags",taglist:"true",excludeTags:"",notags:"tiddler has no tags",aretags:"current tiddler tags:",toggletext:"add tags:"}};config.macros.tagger={};config.macros.tagger.arrow=(document.all?"▼":"▾");config.macros.tagger.handler=function(_1,_2,_3,_4,_5,_6){var _7=config.tagger.defaults;var _8=_5.parseParams("tagman",null,true);var _9=((_8[0].label)&&(_8[0].label[0])!=".")?_8[0].label[0]+this.arrow:_7.label+this.arrow;var _a=((_8[0].tooltip)&&(_8[0].tooltip[0])!=".")?_8[0].tooltip[0]:_7.tooltip;var _b=((_8[0].taglist)&&(_8[0].taglist[0])!=".")?_8[0].taglist[0]:_7.taglist;var _c=((_8[0].exclude)&&(_8[0].exclude[0])!=".")?(_8[0].exclude[0]).readBracketedList():_7.excludeTags.readBracketedList();if((_8[0].source)&&(_8[0].source[0])!="."){var _d=_8[0].source[0];}if(_d&&!store.getTiddler(_d)){return false;}var _e=function(e){if(!e){var e=window.event;}var _11=Popup.create(this);var _12=store.getTags();var _13=new Array();for(var i=0;i<_12.length;i++){_13.push(_12[i][0]);}if(_d){var _15=store.getTiddler(_d);_13=_15.tags.sort();}var _16=_6.tags.sort();var _17=function(_18,_19,_1a){var sp=createTiddlyElement(createTiddlyElement(_11,"li"),"span",null,"tagger");var _1c=createTiddlyButton(sp,_18,_1a+" '"+_19+"'",taggerOnToggle,"button","toggleButton");_1c.setAttribute("tiddler",_6.title);_1c.setAttribute("tag",_19);insertSpacer(sp);if(window.createTagButton_orig_mptw){createTagButton_orig_mptw(sp,_19)}else{createTagButton(sp,_19);}};createTiddlyElement(_11,"li",null,"listTitle",(_6.tags.length==0?_7.notags:_7.aretags));for(var t=0;t<_16.length;t++){_17("[x]",_16[t],"remove tag ");}createTiddlyElement(createTiddlyElement(_11,"li"),"hr");if(_b!="false"){createTiddlyElement(_11,"li",null,"listTitle",_7.toggletext);for(var i=0;i<_13.length;i++){if(!_6.tags.contains(_13[i])&&!_c.contains(_13[i])){_17("[ ]",_13[i],"add tag ");}}createTiddlyElement(createTiddlyElement(_11,"li"),"hr");}var _1f=createTiddlyButton(createTiddlyElement(_11,"li"),("Create new tag"),null,taggerOnToggle);_1f.setAttribute("tiddler",_6.title);if(_d){_1f.setAttribute("source",_d);}Popup.show(_11,false);e.cancelBubble=true;if(e.stopPropagation){e.stopPropagation();}return (false);};createTiddlyButton(_1,_9,_a,_e,"button","taggerDrpBtn");};window.taggerOnToggle=function(e){var tag=this.getAttribute("tag");var _22=this.getAttribute("tiddler");var _23=store.getTiddler(_22);if(!tag){var _24=prompt("Enter new tag:","");if(_24!=""&&_24!=null){var tag=_24;if(this.getAttribute("source")){var _26=store.getTiddler(this.getAttribute("source"));_26.tags.pushUnique(_24);}}else{return false;}}if(!_23||!_23.tags){store.saveTiddler(_22,_22,"",config.options.txtUserName,new Date(),tag);}else{if(_23.tags.find(tag)==null){_23.tags.push(tag);}else{if(!_24){_23.tags.splice(_23.tags.find(tag),1);}}store.saveTiddler(_23.title,_23.title,_23.text,_23.modifier,_23.modified,_23.tags);}story.refreshTiddler(_22,null,true);if(config.options.chkAutoSave){saveChanges();}return false;};setStylesheet(".tagger a.button {font-weight: bold;display:inline; padding:0px;}\n"+".tagger #toggleButton {padding-left:2px; padding-right:2px; margin-right:1px; font-size:110%;}\n"+"#nestedtagger {background:#2E5ADF; border: 1px solid #0331BF;}\n"+".popup .listTitle {color:#000;}\n"+"","TaggerStyles");window.lewcidTiddlerSwapTag=function(_27,_28,_29){for(var i=0;i<_27.tags.length;i++){if(_27.tags[i]==_28){_27.tags[i]=_29;return true;}}return false;};window.lewcidRenameTag=function(e){var tag=this.getAttribute("tag");var _2d=prompt("Rename tag '"+tag+"' to:",tag);if((_2d==tag)||(_2d==null)){return false;}if(store.tiddlerExists(_2d)){if(confirm(config.messages.overwriteWarning.format([_2d.toString()]))){story.closeTiddler(_2d,false,false);}else{return null;}}tagged=store.getTaggedTiddlers(tag);if(tagged.length!=0){for(var j=0;j<tagged.length;j++){lewcidTiddlerSwapTag(tagged[j],tag,_2d);}}if(store.tiddlerExists(tag)){store.saveTiddler(tag,_2d);}if(document.getElementById("tiddler"+tag)){var _2f=document.getElementById(story.idPrefix+tag);var _30=story.positionTiddler(_2f);var _31=document.getElementById(story.container);story.closeTiddler(tag,false,false);story.createTiddler(_31,_30,_2d,null);story.saveTiddler(_2d);}if(config.options.chkAutoSave){saveChanges();}return false;};window.onClickTag=function(e){if(!e){var e=window.event;}var _34=resolveTarget(e);var _35=(!isNested(_34));if((Popup.stack.length>1)&&(_35==true)){Popup.removeFrom(1);}else{if(Popup.stack.length>0&&_35==false){Popup.removeFrom(0);}}var _36=(_35==false)?"popup":"nestedtagger";var _37=createTiddlyElement(document.body,"ol",_36,"popup",null);Popup.stack.push({root:this,popup:_37});var tag=this.getAttribute("tag");var _39=this.getAttribute("tiddler");if(_37&&tag){var _3a=store.getTaggedTiddlers(tag);var _3b=[];var li,r;for(r=0;r<_3a.length;r++){if(_3a[r].title!=_39){_3b.push(_3a[r].title);}}var _3d=config.views.wikified.tag;if(_3b.length>0){var _3e=createTiddlyButton(createTiddlyElement(_37,"li"),_3d.openAllText.format([tag]),_3d.openAllTooltip,onClickTagOpenAll);_3e.setAttribute("tag",tag);createTiddlyElement(createTiddlyElement(_37,"li"),"hr");for(r=0;r<_3b.length;r++){createTiddlyLink(createTiddlyElement(_37,"li"),_3b[r],true);}}else{createTiddlyText(createTiddlyElement(_37,"li",null,"disabled"),_3d.popupNone.format([tag]));}createTiddlyElement(createTiddlyElement(_37,"li"),"hr");var h=createTiddlyLink(createTiddlyElement(_37,"li"),tag,false);createTiddlyText(h,_3d.openTag.format([tag]));createTiddlyElement(createTiddlyElement(_37,"li"),"hr");var _40=createTiddlyButton(createTiddlyElement(_37,"li"),("Rename tag '"+tag+"'"),null,lewcidRenameTag);_40.setAttribute("tag",tag);}Popup.show(_37,false);e.cancelBubble=true;if(e.stopPropagation){e.stopPropagation();}return (false);};if(!window.isNested){window.isNested=function(e){while(e!=null){var _42=document.getElementById("contentWrapper");if(_42==e){return true;}e=e.parentNode;}return false;};}config.shadowTiddlers.TaggerPluginDocumentation="The documentation is available [[here.|http://tw.lewcid.org/#TaggerPluginDocumentation]]";config.shadowTiddlers.TaggerPluginSource="The uncompressed source code is available [[here.|http://tw.lewcid.org/#TaggerPluginSource]]";
// %/
/***
|''Name:''|TagsTreePlugin|
|''Description:''|Displays tags hierachy as a tree of tagged tiddlers.<br>Can be used to create dynamic outline navigation.|
|''Version:''|1.0.1|
|''Date:''|Jan 04,2008|
|''Source:''|http://visualtw.ouvaton.org/VisualTW.html|
|''Author:''|Pascal Collin|
|''License:''|[[BSD open source license|License]]|
|''~CoreVersion:''|2.1.0|
|''Browser:''|Firefox 2.0; InternetExplorer 6.0|
!Demo
On the plugin [[homepage|http://visualtw.ouvaton.org/VisualTW.html]] :
*Try to tag some <<newTiddler>> with a tag displayed in the menu and edit MainMenu.
*Look at some tags like [[Plugins]] or [[menu]].
!Installation
#import the plugin,
#save and reload,
#optionally, edit TagsTreeStyleSheet.
! Usage
{{{<<tagsTree>>}}} macro accepts the following //optional// parameters.
|!#|!parameter|!description|!by default|
|1|{{{root}}}|Uses {{{root}}} tag as tree root|- In a //tiddler// content or template : uses the tiddler as root tag.<br>- In the //page// content or template (by ex MainMenu) : displays all untagged tags.|
|2|{{{excludeTag}}}|Excludes all such tagged tiddlers from the tree|Uses default excludeLists tag|
|3|{{{level}}}|Expands nodes until level {{{level}}}.<br>Value {{{0}}} hides expand/collapse buttons.|Nodes are collapsed on first level|
|4|{{{depth}}}|Hierachy depth|6 levels depth (H1 to H6 header styles)|
|5|{{{sortField}}}|Alternate sort field. By example : "index".|Sorts tags and tiddlers alphabetically (on their title)|
|6|{{{labelField}}}|Alertnate label field. By example : "label".|Displays tiddler's title|

!Useful addons
*[[FieldsEditorPlugin]] : //create//, //edit//, //view// and //delete// commands in toolbar <<toolbar fields>>.
*[[TaggerPlugin]] : Provides a drop down listing current tiddler tags, and allowing toggling of tags.
!Advanced Users
You can change the global defaults for TagsTreePlugin, like default {{{level}}} value or level styles, by editing or overriding the first config.macros.tagsTree attributes below.
!Code
***/
//{{{
config.macros.tagsTree = {
	expand : "+",
	collapse : "–",
	depth : 6,
	level : 1,
	sortField : "",	
	labelField : "",
	styles : ["h1","h2","h3","h4","h5","h6"],
	trees : {}
}

config.macros.tagsTree.handler = function(place,macroName,params,wikifier,paramString,tiddler)
{
	var root = params[0] ? params[0] : (tiddler ? tiddler.title : null);
	var excludeTag = params[1] ? params[1] : "excludeTagsTree";
	var level = params[2] ? params[2] : config.macros.tagsTree.level;
	var depth = params[3] ? params[3] : config.macros.tagsTree.depth;
	var sortField = params[4] ? params[4] : config.macros.tagsTree.sortField;
	var labelField = params[5] ? params[5] : config.macros.tagsTree.labelField;
	var showButtons = (level>0);
	var id = config.macros.tagsTree.getId(place);
	if (config.macros.tagsTree.trees[id]==undefined) config.macros.tagsTree.trees[id]={};
	config.macros.tagsTree.createSubTree(place,id,root,excludeTag,[],level>0 ? level : 1,depth, sortField, labelField,showButtons);
}

config.macros.tagsTree.createSubTree = function(place, id, root, excludeTag, ancestors, level, depth, sortField, labelField,showButtons){
	var childNodes = root ? this.getChildNodes(root, ancestors) : this.getRootTags(excludeTag);
	var isOpen = (level>0) || (!showButtons);
	if (root && this.trees[id][root]!=undefined) isOpen = this.trees[id][root]; 
	if (root && ancestors.length) {
		var t = store.getTiddler(root);
		if (childNodes.length && depth>0) {
			var wrapper = createTiddlyElement(place , this.styles[Math.min(Math.max(ancestors.length,1),6)-1],null,"branch");
			if (showButtons) {
				b = createTiddlyButton(wrapper, isOpen ? config.macros.tagsTree.collapse : config.macros.tagsTree.expand, null, config.macros.tagsTree.onClick);
				b.setAttribute("treeId",id);
				b.setAttribute("tiddler",root);					
			}
			createTiddlyText(createTiddlyLink(wrapper, root),t&&labelField ? t.fields[labelField] ? t.fields[labelField] : root : root);
		}
		else 
			createTiddlyText(createTiddlyLink(place, root,false,"leaf"),t&&labelField ? t.fields[labelField] ? t.fields[labelField] : root : root);
	}
	if (childNodes.length && depth) {
		var d = createTiddlyElement(place,"div",null,"subtree");
		d.style.display= isOpen ? "block" : "none";
		if (sortField)
			childNodes.sort(function(a, b){
				var fa=a.fields[sortField];
				var fb=b.fields[sortField];
				return (fa==undefined && fb==undefined) ? a.title < b.title ? -1 : a.title > b.title ? 1 : 0 : (fa==undefined && fb!=undefined) ? 1 :(fa!=undefined && fb==undefined) ? -1 : fa < fb ? -1 : fa > fb ? 1 : 0;
			})
		for (var cpt=0; cpt<childNodes.length; cpt++)
			this.createSubTree(d, id, childNodes[cpt].title, excludeTag, ancestors.concat(root), level-1, depth-1, sortField, labelField, showButtons);	
	}	
}

config.macros.tagsTree.onClick = function(e){
	var id = this.getAttribute("treeId");
	var tiddler = this.getAttribute("tiddler");	
	var n = this.parentNode.nextSibling;
	var isOpen = n.style.display != "none";
	if(config.options.chkAnimate && anim && typeof Slider == "function")
		anim.startAnimating(new Slider(n,!isOpen,null,"none"));
	else
		n.style.display = isOpen ? "none" : "block";
	this.firstChild.nodeValue = isOpen ? config.macros.tagsTree.expand : config.macros.tagsTree.collapse;
	config.macros.tagsTree.trees[id][tiddler]=!isOpen;
	return false;
}

config.macros.tagsTree.getChildNodes = function(root ,ancestors){
	var childs = store.getTaggedTiddlers(root);
	var result = new Array();
	for (var cpt=0; cpt<childs.length; cpt++)
		if (childs[cpt].title!=root && ancestors.indexOf(childs[cpt].title)==-1) result.push(childs[cpt]);
	return result;
}

config.macros.tagsTree.getRootTags = function(excludeTag){
	var tags = store.getTags(excludeTag);
	tags.sort(function(a,b) {return a[0].toLowerCase() < b[0].toLowerCase() ? -1 : (a[0].toLowerCase() == b[0].toLowerCase() ? 0 : +1);});
	var result = new Array();
	for (var cpt=0; cpt<tags.length; cpt++) {
		var t = store.getTiddler(tags[cpt][0]);
		if (!t || t.tags.length==0) result.push(t ? t : {title:tags[cpt][0],fields:{}});
	}
	return result;
}

config.macros.tagsTree.getId = function(element){
	while (!element.id && element.parentNode) element=element.parentNode;
	return element.id ? element.id : "<html>";
}

config.shadowTiddlers.TagsTreeStyleSheet = "/*{{{*/\n";
config.shadowTiddlers.TagsTreeStyleSheet +=".leaf, .subtree {display:block; margin-left : 0.5em}\n";
config.shadowTiddlers.TagsTreeStyleSheet +=".subtree {margin-bottom:0.5em}\n";
config.shadowTiddlers.TagsTreeStyleSheet +="#mainMenu {text-align:left}\n";
config.shadowTiddlers.TagsTreeStyleSheet +=".branch .button {border:1px solid #DDD; color:#AAA;font-size:9px;padding:0 2px;margin-right:0.3em;vertical-align:middle;text-align:center;}\n";
config.shadowTiddlers.TagsTreeStyleSheet +="/*}}}*/";

store.addNotification("TagsTreeStyleSheet", refreshStyles); 

config.shadowTiddlers.MainMenu="<<tagsTree>>"

config.shadowTiddlers.PageTemplate = config.shadowTiddlers.PageTemplate.replace(/id='mainMenu' refresh='content' /,"id='mainMenu' refresh='content' force='true' ")

//}}}
/*{{{*/
.leaf, .subtree {display:block}

/* 設定 Tree 第一層的 left margin */ 
#mainMenu>.subtree {margin-left:0em}

.leaf {margin-left:0.2em; margin-bottom:0.2em; color:navy;}
.subtree {margin-left:0.8em;}

.branch .button {
   border:1px solid #DDD; color:#999;
   font-size:10px;padding:0 4px;
   margin-right:0.5em;
   vertical-align:middle;text-align:center;
}

/*}}}*/
/***
|''Name:''|TiddlersBarPlugin|
|''Description:''|A bar to switch between tiddlers through tabs (like browser tabs bar).|
|''Version:''|1.2.5|
|''Date:''|Jan 18,2008|
|''Source:''|http://visualtw.ouvaton.org/VisualTW.html|
|''Author:''|Pascal Collin|
|''License:''|[[BSD open source license|License]]|
|''~CoreVersion:''|2.1.0|
|''Browser:''|Firefox 2.0; InternetExplorer 6.0, others|
!Demos
On [[homepage|http://visualtw.ouvaton.org/VisualTW.html]], open several tiddlers to use the tabs bar.
!Installation
#import this tiddler from [[homepage|http://visualtw.ouvaton.org/VisualTW.html]] (tagged as systemConfig)
#save and reload
#''if you're using a custom [[PageTemplate]]'', add {{{<div id='tiddlersBar' refresh='none' ondblclick='config.macros.tiddlersBar.onTiddlersBarAction(event)'></div>}}} before {{{<div id='tiddlerDisplay'></div>}}}
#optionally, adjust StyleSheetTiddlersBar
!Tips
*Doubleclick on the tiddlers bar (where there is no tab) create a new tiddler.
*Tabs include a button to close {{{x}}} or save {{{!}}} their tiddler.
*By default, click on the current tab close all others tiddlers.
!Configuration options 
<<option chkDisableTabsBar>> Disable the tabs bar (to print, by example).
<<option chkHideTabsBarWhenSingleTab >> Automatically hide the tabs bar when only one tiddler is displayed. 
<<option txtSelectedTiddlerTabButton>> ''selected'' tab command button.
/<<option txtPreviousTabKey>> previous tab access key.
<<option txtNextTabKey>> next tab access key.
!Code
***/
//{{{
config.options.chkDisableTabsBar = config.options.chkDisableTabsBar ? config.options.chkDisableTabsBar : false;
config.options.chkHideTabsBarWhenSingleTab  = config.options.chkHideTabsBarWhenSingleTab  ? config.options.chkHideTabsBarWhenSingleTab  : false;
config.options.txtSelectedTiddlerTabButton = config.options.txtSelectedTiddlerTabButton ? config.options.txtSelectedTiddlerTabButton : "closeOthers";
config.options.txtPreviousTabKey = config.options.txtPreviousTabKey ? config.options.txtPreviousTabKey : "";
config.options.txtNextTabKey = config.options.txtNextTabKey ? config.options.txtNextTabKey : "";
config.macros.tiddlersBar = {
	tooltip : "see ",
	tooltipClose : "click here to close this tab",
	tooltipSave : "click here to save this tab",
	promptRename : "Enter tiddler new name",
	currentTiddler : "",
	previousState : false,
	previousKey : config.options.txtPreviousTabKey,
	nextKey : config.options.txtNextTabKey,	
	tabsAnimationSource : null, //use document.getElementById("tiddlerDisplay") if you need animation on tab switching.
	handler: function(place,macroName,params) {
		var previous = null;
		if (config.macros.tiddlersBar.isShown())
			story.forEachTiddler(function(title,e){
				if (title==config.macros.tiddlersBar.currentTiddler){
					var d = createTiddlyElement(null,"span",null,"tab tabSelected");
					config.macros.tiddlersBar.createActiveTabButton(d,title);
					if (previous && config.macros.tiddlersBar.previousKey) previous.setAttribute("accessKey",config.macros.tiddlersBar.nextKey);
					previous = "active";
				}
				else {
					var d = createTiddlyElement(place,"span",null,"tab tabUnselected");
					var btn = createTiddlyButton(d,title,config.macros.tiddlersBar.tooltip + title,config.macros.tiddlersBar.onSelectTab);
					btn.setAttribute("tiddler", title);
					if (previous=="active" && config.macros.tiddlersBar.nextKey) btn.setAttribute("accessKey",config.macros.tiddlersBar.previousKey);
					previous=btn;
				}
				var isDirty =story.isDirty(title);
				var c = createTiddlyButton(d,isDirty ?"!":"x",isDirty?config.macros.tiddlersBar.tooltipSave:config.macros.tiddlersBar.tooltipClose, isDirty ? config.macros.tiddlersBar.onTabSave : config.macros.tiddlersBar.onTabClose,"tabButton");
				c.setAttribute("tiddler", title);
				if (place.childNodes) {
					place.insertBefore(document.createTextNode(" "),place.firstChild); // to allow break line here when many tiddlers are open
					place.insertBefore(d,place.firstChild); 
				}
				else place.appendChild(d);
			})
	}, 
	refresh: function(place,params){
		removeChildren(place);
		config.macros.tiddlersBar.handler(place,"tiddlersBar",params);
		if (config.macros.tiddlersBar.previousState!=config.macros.tiddlersBar.isShown()) {
			story.refreshAllTiddlers();
			if (config.macros.tiddlersBar.previousState) story.forEachTiddler(function(t,e){e.style.display="";});
			config.macros.tiddlersBar.previousState = !config.macros.tiddlersBar.previousState;
		}
	},
	isShown : function(){
		if (config.options.chkDisableTabsBar) return false;
		if (!config.options.chkHideTabsBarWhenSingleTab) return true;
		var cpt=0;
		story.forEachTiddler(function(){cpt++});
		return (cpt>1);
	},
	selectNextTab : function(){  //used when the current tab is closed (to select another tab)
		var previous="";
		story.forEachTiddler(function(title){
			if (!config.macros.tiddlersBar.currentTiddler) {
				story.displayTiddler(null,title);
				return;
			}
			if (title==config.macros.tiddlersBar.currentTiddler) {
				if (previous) {
					story.displayTiddler(null,previous);
					return;
				}
				else config.macros.tiddlersBar.currentTiddler=""; 	// so next tab will be selected
			}
			else previous=title;
			});		
	},
	onSelectTab : function(e){
		var t = this.getAttribute("tiddler");
		if (t) story.displayTiddler(null,t);
		return false;
	},
	onTabClose : function(e){
		var t = this.getAttribute("tiddler");
		if (t) {
			if(story.hasChanges(t) && !readOnly) {
				if(!confirm(config.commands.cancelTiddler.warning.format([t])))
				return false;
			}
			story.closeTiddler(t);
		}
		return false;
	},
	onTabSave : function(e) {
		var t = this.getAttribute("tiddler");
		if (!e) e=window.event;
		if (t) config.commands.saveTiddler.handler(e,null,t);
		return false;
	},
	onSelectedTabButtonClick : function(event,src,title) {
		var t = this.getAttribute("tiddler");
		if (!event) event=window.event;
		if (t && config.options.txtSelectedTiddlerTabButton && config.commands[config.options.txtSelectedTiddlerTabButton])
			config.commands[config.options.txtSelectedTiddlerTabButton].handler(event, src, t);
		return false;
	},
	onTiddlersBarAction: function(event) {
		var source = event.target ? event.target.id : event.srcElement.id; // FF uses target and IE uses srcElement;
		if (source=="tiddlersBar") story.displayTiddler(null,'New Tiddler',DEFAULT_EDIT_TEMPLATE,false,null,null);
	},
	createActiveTabButton : function(place,title) {
		if (config.options.txtSelectedTiddlerTabButton && config.commands[config.options.txtSelectedTiddlerTabButton]) {
			var btn = createTiddlyButton(place, title, config.commands[config.options.txtSelectedTiddlerTabButton].tooltip ,config.macros.tiddlersBar.onSelectedTabButtonClick);
			btn.setAttribute("tiddler", title);
		}
		else
			createTiddlyText(place,title);
	}
}

story.coreCloseTiddler = story.coreCloseTiddler? story.coreCloseTiddler : story.closeTiddler;
story.coreDisplayTiddler = story.coreDisplayTiddler ? story.coreDisplayTiddler : story.displayTiddler;

story.closeTiddler = function(title,animate,unused) {
	if (title==config.macros.tiddlersBar.currentTiddler)
		config.macros.tiddlersBar.selectNextTab();
	story.coreCloseTiddler(title,false,unused); //disable animation to get it closed before calling tiddlersBar.refresh
	var e=document.getElementById("tiddlersBar");
	if (e) config.macros.tiddlersBar.refresh(e,null);
}

story.displayTiddler = function(srcElement,tiddler,template,animate,unused,customFields,toggle){
	story.coreDisplayTiddler(config.macros.tiddlersBar.tabsAnimationSource,tiddler,template,animate,unused,customFields,toggle);
	var title = (tiddler instanceof Tiddler)? tiddler.title : tiddler;  
	if (config.macros.tiddlersBar.isShown()) {
		story.forEachTiddler(function(t,e){
			if (t!=title) e.style.display="none";
			else e.style.display="";
		})
		config.macros.tiddlersBar.currentTiddler=title;
	}
	var e=document.getElementById("tiddlersBar");
	if (e) config.macros.tiddlersBar.refresh(e,null);
}

var coreRefreshPageTemplate = coreRefreshPageTemplate ? coreRefreshPageTemplate : refreshPageTemplate;
refreshPageTemplate = function(title) {
	coreRefreshPageTemplate(title);
	if (config.macros.tiddlersBar) config.macros.tiddlersBar.refresh(document.getElementById("tiddlersBar"));
}

//ensureVisible=function (e) {return 0} //disable bottom scrolling (not useful now)

config.shadowTiddlers.StyleSheetTiddlersBar = "/*{{{*/\n";
config.shadowTiddlers.StyleSheetTiddlersBar += "#tiddlersBar .button {border:0}\n";
config.shadowTiddlers.StyleSheetTiddlersBar += "#tiddlersBar .tab {white-space:nowrap}\n";
config.shadowTiddlers.StyleSheetTiddlersBar += "#tiddlersBar {padding : 1em 0.5em 2px 0.5em}\n";
config.shadowTiddlers.StyleSheetTiddlersBar += ".tabUnselected .tabButton, .tabSelected .tabButton {padding : 0 2px 0 2px; margin: 0 0 0 4px;}\n";
config.shadowTiddlers.StyleSheetTiddlersBar += ".tiddler, .tabContents {border:1px [[ColorPalette::TertiaryPale]] solid;}\n";
config.shadowTiddlers.StyleSheetTiddlersBar +="/*}}}*/";
store.addNotification("StyleSheetTiddlersBar", refreshStyles);

config.refreshers.none = function(){return true;}
config.shadowTiddlers.PageTemplate=config.shadowTiddlers.PageTemplate.replace(/<div id='tiddlerDisplay'><\/div>/m,"<div id='tiddlersBar' refresh='none' ondblclick='config.macros.tiddlersBar.onTiddlersBarAction(event)'></div>\n<div id='tiddlerDisplay'></div>");

//}}}
<<search>> | [[首頁]] | [[土芭樂 3.0 - 數位新思路|http://tbala.net/]]  | [[TiddlyWiki 練功坊|http://tiddlywiki.tbala.net/]] |  <<newTiddler label:"新增文章">>  <<saveChanges>> 
<!--{{{-->
<div class='toolbar' macro='toolbar closeTiddler closeOthers +editTiddler > fields syncing permalink references jump'></div>
<div class='title' macro='view title'></div>
<div class='subtitle'><span macro='view modifier link'></span>, <span macro='view modified date'></span> (<span macro='message views.wikified.createdPrompt'></span> <span macro='view created date'></span>)</div>

<!--
<div class='tagging' macro='tagging'></div>
-->
<div class='tagged' macro='tags'></div>
<div class='viewer' macro='view text wikified'></div>
<div class='tagClear'></div>
<!--}}}-->
/***
|''Name:''|abego.IncludePlugin|
|''Version:''|1.0.0 (2007-02-08)|
|''Type:''|plugin|
|''Source:''|http://tiddlywiki.abego-software.de/#IncludePlugin|
|''Author:''|Udo Borkowski (ub [at] abego-software [dot] de)|
|''Documentation:''|[[IncludePlugin Documentation|http://tiddlywiki.abego-software.de/#%5B%5BIncludePlugin%20Documentation%5D%5D]]|
|''Community:''|([[del.icio.us|http://del.icio.us/post?url=http://tiddlywiki.abego-software.de/index.html%23IncludePlugin]]) ([[Support|http://groups.google.com/group/TiddlyWiki]])|
|''Copyright:''|&copy; 2007 [[abego Software|http://www.abego-software.de]]|
|''Licence:''|[[BSD open source license (abego Software)|http://www.abego-software.de/legal/apl-v10.html]]|
|''~CoreVersion:''|2.1.3|
|''Browser:''|Firefox 1.5.0.9 or better; Internet Explorer 6.0|
***/
//{{{

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

var invokeLater = function(func, delay, priority) {
	return abego.invokeLater ? abego.invokeLater(func, delay, priority) : setTimeout(func,delay);
};

// Asynchronously load the given (local or remote) file.
// 
// @param url 		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 
//					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 abego.loadFile.
//
// @param params 	passed through to the callback function
// 
abego.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.
	if (url.search(/^((http(s)?)|(file)):/) != 0) {
		
		// no protocol specified. 
		if (url.search(/^((.\:\\)|(\\\\)|(\/))/) == 0) {
			// "url" is an "absolute" path to a local file. Prefix it with file://
			url = "file://"+url;
			
		} else {
			// "url" is a "relative" URL. Make it absolute
			
			// prefix the url with the directory containing the current document
			// (This also includes the protocol prefix)
			var documentPath = document.location.toString();
			var i = documentPath.lastIndexOf("/");
			url = documentPath.substr(0,i+1)+url;
		}
		// replace every \ by a /, to cover Windows style pathes
		url = url.replace(/\\/mg,"/");
	}
	
	loadRemoteFile(url,onLoad,params);

};

// Asynchronously load the given (local or remote) TiddlyWiki store.
// 
// @param url 		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 
//					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 abego.loadTiddlyWikiStore
//
// @param params 	passed through to the callbackWithStore
//
// @progress		[optional] 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 "abego.loadTiddlyWikiStore"
//								state: one of these: "Started", "Processing", "Done", "Failed"
//									"Processing" means the data has been received and in now processed.
// 
abego.loadTiddlyWikiStore = function(url,callbackWithStore,params,progress) {
	
	var sendProgress = function(message, state) {
		if (progress)
			progress(message,"abego.loadTiddlyWikiStore",state,url,params);
	};
	
	// Load contents of a TiddlyWiki from a string
	//# Returns null on success, an error message otherwise.
	//# based on code from TiddlyWiki 2.2 alpha
	var importTiddlyWiki = function(store,text)
	{
		// Crack out the content - will be refactored to share code with saveChanges()
		var posOpeningDiv = text.indexOf(startSaveArea);
		var limitClosingDiv = text.indexOf("<!--POST-BODY-END--"+">");
		var posClosingDiv = text.lastIndexOf(endSaveArea,limitClosingDiv == -1 ? text.length : limitClosingDiv);
		if((posOpeningDiv == -1) || (posClosingDiv == -1))
			return config.messages.invalidFileError.format([url]);
		var content = "<html><body>" + text.substring(posOpeningDiv,posClosingDiv + endSaveArea.length) + "</body></html>";
		// Create the iframe
		var iframe = document.createElement("iframe");
		iframe.style.display = "none";
		document.body.appendChild(iframe);
		var doc = iframe.document;
		if(iframe.contentDocument)
			doc = iframe.contentDocument; // For NS6
		else if(iframe.contentWindow)
			doc = iframe.contentWindow.document; // For IE5.5 and IE6
		// Put the content in the iframe
		doc.open();
		doc.writeln(content);
		doc.close();
		// Load the content into a TiddlyWiki() object
		var storeArea = doc.getElementById("storeArea");
		store.loadFromDiv(storeArea,"store");
		// Get rid of the iframe
		iframe.parentNode.removeChild(iframe);
		return null;
	};
	
	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 orig_invalidFileError = config.messages.invalidFileError;
		config.messages.invalidFileError = "The file '%0' does not appear to be a valid TiddlyWiki file";
		try {
			// Load the content into a TiddlyWiki() object
			var importStore = new TiddlyWiki();
			var errorText = importTiddlyWiki(importStore,content);
			if (errorText)
				sendError(errorText);
			else
				sendStore(importStore);

		} catch (ex) {
			sendError(exceptionText(ex));
		} finally {
			config.messages.invalidFileError = orig_invalidFileError;
		}
	};
	
	sendProgress("Start loading %0".format([url]),"Started");
	abego.loadFile(url,callback,params);
};


//==============================================================================
// Include Plugin 

(function(){

// only install once
if (abego.TiddlyWikiIncluder) return;


// --------------------------------------------------
// 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;
var includes = []; // [] of Strings. the urls of the stores to include, in the sequence of the calls.
var includedStores = {}; // url(String) -> TiddlyWiki or String; when not (yet) loaded a status or 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;

// --------------------------------------------------
// 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() {
		abego.TiddlyWikiIncluder.sendProgress("","","Done");
	};
	
	refreshTiddlyWikiTimerID = setInterval(function() {
		idleCount++;
		if (idleCount <= 10)
			return;
			
		clearInterval(refreshTiddlyWikiTimerID);
		refreshTiddlyWikiTimerID = undefined;
			
		abego.TiddlyWikiIncluder.sendProgress("Refreshing...","","");
		refreshDisplay();
		invokeLater(sendDone,0,REFRESH_PRIORITY);
	},0);
};

// Calls callback for every loaded store and returns the first non-false/null.. value returned by callback.
//
// @param callback  function(store, url)
//
var forEachLoadedStore = function(callback) {
	var result;
	for (var i = 0; i < includes.length; i++) {
		var theStore = abego.TiddlyWikiIncluder.getStore(includes[i]);
		if (theStore && (result = callback(theStore, includes[i])))
			return result;
	}
};

var attachToStore = function() {
	if (!window.store)
		return invokeLater(attachToStore,100);
		
	var orig_fetchTiddler = store.fetchTiddler;
	
	store.fetchTiddler = function(title) {
		var t = orig_fetchTiddler.apply(this,arguments);
		if (t) return t;
		
		// When there is a shadowtiddler with that name done look for
		// any included tiddler since these would hide the shadow
		if (config.shadowTiddlers[title] !== undefined) return undefined;
		
		// Don't look for the "New Tiddler" tiddler in the included TiddlyWikis,
		// since returning such a tiddler (that is readonly) will make it impossible
		// in the Main TiddlyWiki to create new tiddlers.
		if (title == config.macros.newTiddler.title) return undefined;

		return forEachLoadedStore(
				function(theStore, url) {
					var t = theStore.fetchTiddler(title);
					if (t) 
						t.includeURL = url;
					return t;
				});
	};

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

var includeFromIncludeList = function() {
	if (!window.store)
		return invokeLater(includeFromIncludeList,100);
		
	var includeListText = store.getTiddlerText("IncludeList");
	if (includeListText) 
		wikify(includeListText,document.createElement("div"));
};

var getFunctionUsingForReallyEachTiddler = function(func) {
	var wrapper = function() {
		var orig_forEachTiddler = store.forEachTiddler;

		var forEachTiddlerWithIncludes = function(callback) {
			var done = {};
			var includeURL;

			var callbackWrapper = function(title, tiddler) {
				// ensure every title is only processed once
				if (done[title]) 
					return;
				done[title] = 1;
				
				// for "included tiddlers" set the includeURL;
				if (includeURL)
					tiddler.includeURL = includeURL;
				
				callback.apply(this,arguments);
			};
			
			// forEachTiddler over the original tiddlers
			orig_forEachTiddler.call(store, callbackWrapper);
			
			// add all shadowTiddler titles to done 
			// (to avoid an included store hides a shadow tiddler)
			for (var n in config.shadowTiddlers)
				done[n] = 1;

			// add all the "New Tiddler" tiddlerto done 
			// (to avoid an included store (with "New Tiddler") makes it impossible to create new tiddlers)
			done[config.macros.newTiddler.title] = 1;

			// forEachTiddler over every included store
			forEachLoadedStore(
					function(theStore, url) {
						includeURL = url;
						theStore.forEachTiddler(callbackWrapper);
					});
		};
		
		store.forEachTiddler = forEachTiddlerWithIncludes;
		try {
			return func.apply(this,arguments);
		} finally {
			store.forEachTiddler = orig_forEachTiddler;
		}
	};
	
	return wrapper;
};

var useForReallyEachTiddler = function(object,property) {
	return object[property] = getFunctionUsingForReallyEachTiddler(object[property]);
};


//================================================================================
// abego.TiddlyWikiIncluder

abego.TiddlyWikiIncluder = {};

abego.TiddlyWikiIncluder.setProgressFunction = function(func) {
	progress = func;
};

abego.TiddlyWikiIncluder.getProgressFunction = function(func) {
	return progress;
};

abego.TiddlyWikiIncluder.sendProgress = function(message, sender, state) {
	if (progress)
		progress.apply(this,arguments);
};


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


// Returns true when there are "pending" includes, i.e. TiddlyWiki that are not yet loaded.
//
// A TiddlyWiki that failed loading is not pending.
//
abego.TiddlyWikiIncluder.hasPendingIncludes = function() {
	for (var i = 0; i < includes.length; i++) {
		var state = abego.TiddlyWikiIncluder.getState(includes[i]);
		if (state == WAITING || state == LOADING)
			return true;
	}
	return false;
};


// @return [] of Strings, the URLs of the includes
//
abego.TiddlyWikiIncluder.getIncludes = function() {
	return includes.slice();
};


// @return [may be null] a state/error text of the store with the given URL, or null when the store is already loaded
//
abego.TiddlyWikiIncluder.getState = function(url) {
	var s = includedStores[url];
	if (!s)
		return getMissingIncludeMsg(url);
	return typeof s == "string" ? s : null;
};


// @return [may be null] the (TiddlyWiki) store  with the given URL, null if not (yet) loaded.
//
abego.TiddlyWikiIncluder.getStore = function(url) {
	var s = includedStores[url];
	if (!s)
		return getMissingIncludeMsg(url);
	return s instanceof TiddlyWiki ? s : null;
};


// Includes the (local or remote) TiddlyWiki store with the given url.
// 
// stores with urls already already included are ignored.
//
// @param url	see url@abego.loadTiddlyWikiStore
// @param delayMilliSeconds [optional] if defined loading starts delayMilliSeconds later, otherwise "immediately"
//
abego.TiddlyWikiIncluder.include = function(url, delayMilliSeconds) {
	if (!isIncludeEnabled() || includedStores[url])
		return;
	var self = this;
	
	includes.push(url);
	includedStores[url] = WAITING;

	var loadStoreCallback = function(theStore,urlInCallback,params,errorMessage) {
		if (theStore === undefined) {
			includedStores[url] = errorMessage;
			self.onError(url, errorMessage);
			return;
		}
		includedStores[url] = theStore;
		pendingOnLoadURLs.push(url);
		invokeLater(notifyListeners);
	};
	
	var loadStore = function() {
		includedStores[url] = LOADING;
		abego.loadTiddlyWikiStore(url,loadStoreCallback,null,progress);
	};
	
	if (delayMilliSeconds)
		invokeLater(loadStore, delayMilliSeconds);
	else
		loadStore();
};


// iterates over all tiddlers of "the store" and all tiddlers of included (and loaded) stores
//
abego.TiddlyWikiIncluder.forReallyEachTiddler = function(callback) {
	var caller = function() {
		store.forEachTiddler(callback);
	};
	
	getFunctionUsingForReallyEachTiddler(caller).call(store);
};


// function abego.TiddlyWikiIncluder.getFunctionUsingForReallyEachTiddler(func)
//
// Returns a function that behaves as func, but every call to store.forEachTiddler will actually 
// be a call to forReallyEachTiddler, i.e. iterate over the tiddlers the main store and of the 
// included TiddlyWikis
//
// @return the patched function
//
abego.TiddlyWikiIncluder.getFunctionUsingForReallyEachTiddler = getFunctionUsingForReallyEachTiddler;


// function abego.TiddlyWikiIncluder.useForReallyEachTiddler(object,property)
//
// Patches the function hold in the given property of the object in such a way that every call
// to store.forEachTiddler will actually be a call to forReallyEachTiddler, i.e. iterate over the
// tiddlers the main staire and of the included TiddlyWikis
//
// @param object
// @param property the name of the property of the object containing the function to be patched.
// @return the patched function
//
abego.TiddlyWikiIncluder.useForReallyEachTiddler = useForReallyEachTiddler;


// Add a listener function to the TiddlyWikiIncluder.
//
// @param listener function(urls)
//							url: [] of Strings, containing the urls of the TiddlyWiki just included
//									(see url@abego.TiddlyWikiIncluder.include)
//						called whenever one or more TiddlyWiki store are successfully included.
//
abego.TiddlyWikiIncluder.addListener = function(listener) {
	listeners.push(listener);
};

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

abego.TiddlyWikiIncluder.addListener(refreshTiddlyWiki);

//----------------------------------------------------------------------------
// Options Support

if (config.options.chkUseInclude === undefined) config.options.chkUseInclude = true;

config.shadowTiddlers.AdvancedOptions += "\n<<option chkUseInclude>> Include ~TiddlyWikis (IncludeList | IncludeState | [[help|http://tiddlywiki.abego-software.de/#%5B%5BIncludePlugin%20Documentation%5D%5D]])\n^^(Reload this ~TiddlyWiki to make changes become effective)^^";
config.shadowTiddlers.IncludeState = "<<includeState>>";

//================================================================================
// Default Progress Handling for abego.TiddlyWikiIncluder

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

abego.TiddlyWikiIncluder.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",
		"abegoInclude");

	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 == "abego.loadTiddlyWikiStore") {
			idleCount = 0;
			if (state == "Processing")
				showState("Including...");
		} else {
			showState(message);
		}
	};
	return myProgressFunction;
};

abego.TiddlyWikiIncluder.setProgressFunction(abego.TiddlyWikiIncluder.getDefaultProgressFunction());


//================================================================================
// The "include" macro
//
// Syntax: <<include {url}* [delay: {milliSeconds}] [hide: true] >>
//

config.macros.include = {};
config.macros.include.handler = function(place,macroName,params,wikifier,paramString,tiddler) {
    params = paramString.parseParams("url",null,true,false,true); // allowEval, cascadeDefaults, names allowed
	var delay = parseInt(getParam(params,"delay","0"));
	var urls = params[0]["url"];
	var hide = getFlag(params, "hide", false);
	if (!hide)
		createTiddlyText(createTiddlyElement(place,"code"),wikifier.source.substring(wikifier.matchStart, wikifier.nextMatch));
	for (var i = 0; urls && i < urls.length; i++)
		abego.TiddlyWikiIncluder.include(urls[i],delay);
};


//================================================================================
// 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 = abego.TiddlyWikiIncluder.getIncludes();
		if (!includes.length)
			return "{{noIncludes{\nNo includes or 'include' 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 = abego.TiddlyWikiIncluder.getState(inc);
			s += t ? "{{{"+t+"}}}" : "included";
			s += "|\n"
		}
		s += "|includeState|k\n";
		return s;
	};
	
	var updateState = function(){
		removeChildren(div);
		wikify(getFullState(),div);
		if (abego.TiddlyWikiIncluder.hasPendingIncludes())
			invokeLater(updateState,500,UPDATE_STATE_PRIORITY);
	};

	var div = createTiddlyElement(place,"div");
	
	invokeLater(updateState,0,UPDATE_STATE_PRIORITY);
};

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

var orig_Tiddler_isReadOnly = Tiddler.prototype.isReadOnly;

// Includes tiddlers are readonly.
Tiddler.prototype.isReadOnly = function() {
	return orig_Tiddler_isReadOnly.apply(this,arguments) || this.isIncluded();
}

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

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


//================================================================================
// TiddlyWiki modifications

// In some TiddlyWiki functions the "forEachTiddler" should work on all tiddlers, also those from 
// included store. (E.g. TiddlyWiki.prototype.getTags)
//
// But not for all (e.g. TiddlyWiki.prototype.getTiddlers is used for saving, but only the "own" tiddlers should be saved)
//
// Therefore explicitly list the functions that should be "wrapped" to use the "forReallyEachTiddler".
//
var tiddlyWikiFunctionsUsingForReallyEachTiddler = {
	getMissingLinks: 1, getOrphans: 1,getTags:1, reverseLookup: 1, updateTiddlers: 1};
	
for (var n in tiddlyWikiFunctionsUsingForReallyEachTiddler)
	useForReallyEachTiddler(TiddlyWiki.prototype,n);


//================================================================================
// Make IntelliTagger "Include-aware"

var patchIntelliTagger = function() {
	if (abego.IntelliTagger)
		useForReallyEachTiddler(abego.IntelliTagger,"assistTagging");
};

//================================================================================
// Perform plugin startup tasks

attachToStore();
invokeLater(includeFromIncludeList,100);
invokeLater(patchIntelliTagger,100);

})();

//}}}
''horizontal:''
{{{
* menu #1
** [[item #1-1]]
** [[item #1-2]]
** [[item #1-3]]
* menu #2
** [[item #2-1]]
** [[item #2-2]]
** [[menu #2-3]]
* menu #3
** [[item #2-1]]
** [[item #2-2]]
** [[menu #2-3]]
<<dropMenu>>
}}}
* menu #1
** [[item #1-1]]
** [[item #1-2]]
** [[item #1-3]]
* menu #2
** [[item #2-1]]
** [[item #2-2]]
** [[menu #2-3]]
* menu #3
** [[item #2-1]]
** [[item #2-2]]
** [[menu #2-3]]
<<dropMenu>>

''vertical:''
{{{
* menu #1
** [[item #1-1]]
** [[item #1-2]]
** [[item #1-3]]
* menu #2
** [[item #2-1]]
** [[item #2-2]]
** [[menu #2-3]]
<<dropMenu vertical>>
}}}

* menu #1
** [[item #1-1]]
** [[item #1-2]]
** [[item #1-3]]
* menu #2
** [[item #2-1]]
** [[item #2-2]]
** [[menu #2-3]]
<<dropMenu vertical>>


/% %/
!使用說明
{{{
1. 規劃標籤名
2. 根據 "標籤名" 產生 [編輯] 與 [顯示] 的 Template

    例如 : 標籤名為 HTML, 那麼二個 Template 的名稱為 HTMLEditTemplate, HTMLViewTemplate,
              以後只要文章的標籤有 HTML, 便會自動套用這二個 Template

3. 將以下巨集命令加入 ToolBar 文章中

    <<newTiddler  label:"新增網頁"    tag:"HTML"     template:"HTMLEditTemplate"   title:"新增網頁">>
                              ^                ^                      ^                           ^
                         按鈕名稱        新文章的標籤      新文章第一次使用的 Template     新文章的 Title

    * 必須要安裝 TaggedTemplateTweak 這個插件, 才有以上功能

}}}

請點選以下按鈕, 測試 easyEdit 功能

<<newTiddler label:新增網頁 tag:"HTML" template:"HTMLEditTemplate" title:"新增網頁">>


!HTMLEditTemplate
{{{
<div class='toolbar' macro='toolbar +saveTiddler  -cancelTiddler deleteTiddler'></div>
<div class='title' macro='view title'></div>
<div class='editor' macro='edit title'></div>
<div macro='annotations'></div>
<div class='editor' macro='easyEdit text'></div>
                                      ^
                                 這是重點

<div class='editor' macro='edit tags'></div>
<div class='editorFooter'>
<span macro='message views.editor.tagPrompt'></span>
<span macro='tagChooser'></span>
</div>
}}}

!HTMLViewTemplate
{{{
<div class='toolbar' macro='toolbar closeTiddler closeOthers +easyEdit > fields syncing permalink references jump'></div>
                                                                    ^
                                                                這是重點
<div class='title' macro='view title'></div>
<div class='subtitle'><span macro='view modifier link'></span>, <span macro='view modified date'></span> (<span macro='message views.wikified.createdPrompt'></span> <span macro='view created date'></span>)</div>
<div class='tagged' macro='tags'></div>
<div class='viewer' macro='view text wikified'></div>
<div class='tagClear'></div>
}}}
/***
|''Name:''|easyEditPlugin|
|''Description:''|Lite and extensible Wysiwyg editor for TiddlyWiki.|
|''Version:''|1.3.3|
|''Date:''|Dec 21,2007|
|''Source:''|http://visualtw.ouvaton.org/VisualTW.html|
|''Author:''|Pascal Collin|
|''License:''|[[BSD open source license|License]]|
|''~CoreVersion:''|2.1.0|
|''Browser:''|Firefox 2.0; InternetExplorer 6.0|
!Installation
#import the plugin,
#save and reload,
#use the <<toolbar easyEdit>> button in the tiddler's toolbar (in default ViewTemplate) or add {{{easyEdit}}} command in your own toolbar.
! Useful Addons
*[[HTMLFormattingPlugin|http://www.tiddlytools.com/#HTMLFormattingPlugin]] to embed wiki syntax in html tiddlers.<<br>>//__Tips__ : When this plugin is installed, you can use anchor syntax to link tiddlers in wysiwyg mode (example : #example). Anchors are converted back and from wiki syntax when editing.//
*[[TaggedTemplateTweak|http://www.TiddlyTools.com/#TaggedTemplateTweak]] to use alternative ViewTemplate/EditTemplate for tiddler's tagged with specific tag values.
!Configuration
|Buttons in the toolbar (empty = all).<<br>>//Example : bold,underline,separator,forecolor//<<br>>The buttons will appear in this order.| <<option txtEasyEditorButtons>>|
|EasyEditor default height | <<option txtEasyEditorHeight>>|
|Stylesheet applied to the edited richtext |[[EasyEditDocStyleSheet]]|
|Template called by the {{{write}}} button |[[EasyEditTemplate]]|
!How to extend EasyEditor
*To add your own buttons, add some code like the following in a systemConfig tagged tiddler (//use the prompt attribute only if there is a parameter//) :
**{{{EditorToolbar.buttons.heading = {label:"H", toolTip : "Set heading level", prompt: "Enter heading level"};}}} 
**{{{EditorToolbar.buttonsList +=",heading";}}}
*To get the list of all possible commands, see the documentation of the [[Gecko built-in rich text editor|http://developer.mozilla.org/en/docs/Midas]] or the [[IE command identifiers|http://msdn2.microsoft.com/en-us/library/ms533049.aspx]].
*To go further in customization, see [[Link button|EasyEditPlugin-LinkButton]] as an example.
!Code
***/

//{{{

var geckoEditor={};
var IEeditor={};

config.options.txtEasyEditorHeight = config.options.txtEasyEditorHeight ? config.options.txtEasyEditorHeight : "500px";
config.options.txtEasyEditorButtons = config.options.txtEasyEditorButtons ? config.options.txtEasyEditorButtons : "";

// TW2.1.x compatibility
config.browser.isGecko = config.browser.isGecko ? config.browser.isGecko : (config.userAgent.indexOf("gecko") != -1); 
config.macros.annotations = config.macros.annotations ? config.macros.annotations : {handler : function() {}}


// EASYEDITOR MACRO

config.macros.easyEdit = {
	handler : function(place,macroName,params,wikifier,paramString,tiddler) {
		var field = params[0];
		var height = params[1] ? params[1] : config.options.txtEasyEditorHeight;
		var editor = field ? new easyEditor(tiddler,field,place,height) : null;
	},
	gather: function(element){
		var iframes = element.getElementsByTagName("iframe");
		if (iframes.length!=1) return null
		var text = "<html>"+iframes[0].contentWindow.document.body.innerHTML+"</html>";
		text = config.browser.isGecko ? geckoEditor.postProcessor(text) : (config.browser.isIE ? IEeditor.postProcessor(text) : text);
		return text;
	}
}

// EASYEDITOR CLASS

function easyEditor(tiddler,field,place,height) {
	this.tiddler = tiddler;
	this.field = field;
	this.browser = config.browser.isGecko ? geckoEditor : (config.browser.isIE ? IEeditor : null);
	this.wrapper = createTiddlyElement(place,"div",null,"easyEditor");
	this.wrapper.setAttribute("easyEdit",this.field);
	this.iframe = createTiddlyElement(null,"iframe");
	this.browser.setupFrame(this.iframe,height,contextualCallback(this,this.onload));
	this.wrapper.appendChild(this.iframe);
}

easyEditor.prototype.onload = function(){
	this.editor = this.iframe.contentWindow;
	this.doc = this.editor.document;
	if (!this.browser.isDocReady(this.doc)) return null;
	
	if (!this.tiddler.isReadOnly() && this.doc.designMode.toLowerCase()!="on") {
		this.doc.designMode = "on";
		if (this.browser.reloadOnDesignMode) return false;	// IE fire readystatechange after designMode change
	}
	
	var internalCSS = store.getTiddlerText("EasyEditDocStyleSheet");
	setStylesheet(internalCSS,"EasyEditDocStyleSheet",this.doc);
	this.browser.initContent(this.doc,store.getValue(this.tiddler,this.field));

	var barElement=createTiddlyElement(null,"div",null,"easyEditorToolBar");
	this.wrapper.insertBefore(barElement,this.wrapper.firstChild);
	this.toolbar = new EditorToolbar(this.doc,barElement,this.editor);

	this.browser.plugEvents(this.doc,contextualCallback(this,this.scheduleButtonsRefresh));
	this.editor.focus();
}

easyEditor.SimplePreProcessoror = function(text) {
	var re = /^<html>(.*)<\/html>$/m;
	var htmlValue = re.exec(text);
	var value = (htmlValue && (htmlValue.length>0)) ? htmlValue[1] : text;
	return value;
}

easyEditor.prototype.scheduleButtonsRefresh=function() { //doesn't refresh buttons state when rough typing
	if (this.nextUpdate) window.clearTimeout(this.nextUpdate);
	this.nextUpdate = window.setTimeout(contextualCallback(this.toolbar,EditorToolbar.onUpdateButton),easyEditor.buttonDelay);
}

easyEditor.buttonDelay = 200;

// TOOLBAR CLASS

function EditorToolbar(target,parent,window){
	this.target = target;
	this.window=window;
	this.elements={};
	var row = createTiddlyElement(createTiddlyElement(createTiddlyElement(parent,"table"),"tbody"),"tr");
	var buttons = (config.options.txtEasyEditorButtons ? config.options.txtEasyEditorButtons : EditorToolbar.buttonsList).split(",");
	for(var cpt = 0; cpt < buttons.length; cpt++){
		var b = buttons[cpt];
		var button = EditorToolbar.buttons[b];
		if (button) {
			if (button.separator)
				createTiddlyElement(row,"td",null,"separator").innerHTML+="&nbsp;";
			else {
				var cell=createTiddlyElement(row,"td",null,b+"Button");
				if (button.onCreate) button.onCreate.call(this, cell, b);
				else EditorToolbar.createButton.call(this, cell, b);
			}
		}
	}
}

EditorToolbar.createButton = function(place,name){
	this.elements[name] = createTiddlyButton(place,EditorToolbar.buttons[name].label,EditorToolbar.buttons[name].toolTip,contextualCallback(this,EditorToolbar.onCommand(name)),"button");
}

EditorToolbar.onCommand = function(name){
	var button = EditorToolbar.buttons[name];
	return function(){
		var parameter = false;
		if (button.prompt) {
			var parameter = this.target.queryCommandValue(name);
			parameter = prompt(button.prompt,parameter);
		}
		if (parameter != null) {
			this.target.execCommand(name, false, parameter);
			EditorToolbar.onUpdateButton.call(this);
		}
		return false;
	}
}

EditorToolbar.getCommandState = function(target,name){
	try {return target.queryCommandState(name)}
	catch(e){return false}
}

EditorToolbar.onRefreshButton = function (name){
	if (EditorToolbar.getCommandState(this.target,name)) addClass(this.elements[name].parentNode,"buttonON");
	else removeClass(this.elements[name].parentNode,"buttonON");
	this.window.focus();
}

EditorToolbar.onUpdateButton = function(){
	for (b in this.elements) 
		if (EditorToolbar.buttons[b].onRefresh) EditorToolbar.buttons[b].onRefresh.call(this,b);
		else EditorToolbar.onRefreshButton.call(this,b);
}

EditorToolbar.buttons = {
	separator : {separator : true},
	bold : {label:"B", toolTip : "Bold"},
	italic : {label:"I", toolTip : "Italic"},
	underline : {label:"U", toolTip : "Underline"},
	strikethrough : {label:"S", toolTip : "Strikethrough"},
	insertunorderedlist : {label:"\u25CF", toolTip : "Unordered list"},
	insertorderedlist : {label:"1.", toolTip : "Ordered list"},
	justifyleft : {label:"[\u2261", toolTip : "Align left"},
	justifyright : {label:"\u2261]", toolTip : "Align right"},
	justifycenter : {label:"\u2261", toolTip : "Align center"},
	justifyfull : {label:"[\u2261]", toolTip : "Justify"},
	removeformat : {label:"\u00F8", toolTip : "Remove format"},
	fontsize : {label:"\u00B1", toolTip : "Set font size", prompt: "Enter font size"},
	forecolor : {label:"C", toolTip : "Set font color", prompt: "Enter font color"},
	fontname : {label:"F", toolTip : "Set font name", prompt: "Enter font name"},
	heading : {label:"H", toolTip : "Set heading level", prompt: "Enter heading level (example : h1, h2, ...)"},
	indent : {label:"\u2192[", toolTip : "Indent paragraph"},
	outdent : {label:"[\u2190", toolTip : "Outdent paragraph"},
	inserthorizontalrule : {label:"\u2014", toolTip : "Insert an horizontal rule"},
	insertimage : {label:"\u263C", toolTip : "Insert image", prompt: "Enter image url"}
}

EditorToolbar.buttonsList = "bold,italic,underline,strikethrough,separator,increasefontsize,decreasefontsize,fontsize,forecolor,fontname,separator,removeformat,separator,insertparagraph,insertunorderedlist,insertorderedlist,separator,justifyleft,justifyright,justifycenter,justifyfull,indent,outdent,separator,heading,separator,inserthorizontalrule,insertimage";

if (config.browser.isGecko) {
	EditorToolbar.buttons.increasefontsize = {onCreate : EditorToolbar.createButton, label:"A", toolTip : "Increase font size"};
	EditorToolbar.buttons.decreasefontsize = {onCreate : EditorToolbar.createButton, label:"A", toolTip : "Decrease font size"};
	EditorToolbar.buttons.insertparagraph = {label:"P", toolTip : "Format as paragraph"};
}

// GECKO (FIREFOX, ...) BROWSER SPECIFIC METHODS

geckoEditor.setupFrame = function(iframe,height,callback) {
	iframe.setAttribute("style","width: 100%; height:" + height);
	iframe.addEventListener("load",callback,true);
}

geckoEditor.plugEvents = function(doc,onchange){
	doc.addEventListener("keyup", onchange, true);
	doc.addEventListener("keydown", onchange, true);
	doc.addEventListener("click", onchange, true);
}

geckoEditor.postProcessor = function(text){return text};

geckoEditor.preProcessor = function(text){return easyEditor.SimplePreProcessoror(text)}

geckoEditor.isDocReady = function() {return true;}

geckoEditor.reloadOnDesignMode=false;

geckoEditor.initContent = function(doc,content){
	if (content) doc.execCommand("insertHTML",false,geckoEditor.preProcessor(content));
}

// INTERNET EXPLORER BROWSER SPECIFIC METHODS
	
IEeditor.setupFrame = function(iframe,height,callback) {
	iframe.width="99%";  //IE displays the iframe at the bottom if 100%. CSS layout problem ? I don't know. To be studied...
	iframe.height=height.toString();
	iframe.attachEvent("onreadystatechange",callback);
}

IEeditor.plugEvents = function(doc,onchange){
	doc.attachEvent("onkeyup", onchange);
	doc.attachEvent("onkeydown", onchange);
	doc.attachEvent("onclick", onchange);
}

IEeditor.isDocReady = function(doc){
	if (doc.readyState!="complete") return false;
	if (!doc.body) return false;
	return (doc && doc.getElementsByTagName && doc.getElementsByTagName("head") && doc.getElementsByTagName("head").length>0);
}

IEeditor.postProcessor = function(text){return text};

IEeditor.preProcessor = function(text){return easyEditor.SimplePreProcessoror(text)}

IEeditor.reloadOnDesignMode=true;

IEeditor.initContent = function(doc,content){
	if (content) doc.body.innerHTML=IEeditor.preProcessor(content);
}
	
function contextualCallback(obj,func){
    return function(){return func.call(obj)}
}
	
Story.prototype.previousGatherSaveEasyEdit = Story.prototype.previousGatherSaveEasyEdit ? Story.prototype.previousGatherSaveEasyEdit : Story.prototype.gatherSaveFields; // to avoid looping if this line is called several times
Story.prototype.gatherSaveFields = function(e,fields){
	if(e && e.getAttribute) {
		var f = e.getAttribute("easyEdit");
		if(f){
			var newVal = config.macros.easyEdit.gather(e);
			if (newVal) fields[f] = newVal;
		}
		this.previousGatherSaveEasyEdit(e, fields);
	}
}

config.commands.easyEdit={
	text: "編輯網頁",
	tooltip: "Edit this tiddler in wysiwyg mode",
	readOnlyText: "檢視",
	readOnlyTooltip: "View the source of this tiddler",
	handler : function(event,src,title) {
		clearMessage();
		var tiddlerElem = document.getElementById(story.idPrefix + title);
		var fields = tiddlerElem.getAttribute("tiddlyFields");
		story.displayTiddler(null,title,"EasyEditTemplate",false,null,fields);
		return false;
	}
}

config.shadowTiddlers.ViewTemplate = config.shadowTiddlers.ViewTemplate.replace(/\+editTiddler/,"+editTiddler easyEdit");

config.shadowTiddlers.EasyEditTemplate = config.shadowTiddlers.EditTemplate.replace(/macro='edit text'/,"macro='easyEdit text'");

config.shadowTiddlers.EasyEditToolBarStyleSheet = "/*{{{*/\n";
config.shadowTiddlers.EasyEditToolBarStyleSheet += ".easyEditorToolBar {font-size:0.8em}\n" ;
config.shadowTiddlers.EasyEditToolBarStyleSheet += ".editor iframe {border:1px solid #DDD}\n" ;
config.shadowTiddlers.EasyEditToolBarStyleSheet += ".easyEditorToolBar td{border:1px solid #888; padding:2px 1px 2px 1px; vertical-align:middle}\n" ;
config.shadowTiddlers.EasyEditToolBarStyleSheet += ".easyEditorToolBar td.separator{border:0}\n" ;
config.shadowTiddlers.EasyEditToolBarStyleSheet += ".easyEditorToolBar .button{border:0;color:#444}\n" ;
config.shadowTiddlers.EasyEditToolBarStyleSheet += ".easyEditorToolBar .buttonON{background-color:#EEE}\n" ;
config.shadowTiddlers.EasyEditToolBarStyleSheet += ".easyEditorToolBar {margin:0.25em 0}\n" ;
config.shadowTiddlers.EasyEditToolBarStyleSheet += ".easyEditorToolBar .boldButton {font-weight:bold}\n" ;
config.shadowTiddlers.EasyEditToolBarStyleSheet += ".easyEditorToolBar .italicButton .button {font-style:italic;padding-right:0.65em}\n" ;
config.shadowTiddlers.EasyEditToolBarStyleSheet += ".easyEditorToolBar .underlineButton .button {text-decoration:underline}\n" ;
config.shadowTiddlers.EasyEditToolBarStyleSheet += ".easyEditorToolBar .strikeButton .button {text-decoration:line-through}\n" ;
config.shadowTiddlers.EasyEditToolBarStyleSheet += ".easyEditorToolBar .unorderedListButton {margin-left:0.7em}\n" ;
config.shadowTiddlers.EasyEditToolBarStyleSheet += ".easyEditorToolBar .justifyleftButton .button {padding-left:0.1em}\n" ;
config.shadowTiddlers.EasyEditToolBarStyleSheet += ".easyEditorToolBar .justifyrightButton .button {padding-right:0.1em}\n" ;
config.shadowTiddlers.EasyEditToolBarStyleSheet += ".easyEditorToolBar .justifyfullButton .button, .easyEditorToolBar .indentButton .button, .easyEditorToolBar .outdentButton .button {padding-left:0.1em;padding-right:0.1em}\n" ;
config.shadowTiddlers.EasyEditToolBarStyleSheet += ".easyEditorToolBar .increasefontsizeButton .button {padding-left:0.15em;padding-right:0.15em; font-size:1.3em; line-height:0.75em}\n" ;
config.shadowTiddlers.EasyEditToolBarStyleSheet += ".easyEditorToolBar .decreasefontsizeButton .button {padding-left:0.4em;padding-right:0.4em; font-size:0.8em;}\n" ;
config.shadowTiddlers.EasyEditToolBarStyleSheet += ".easyEditorToolBar .forecolorButton .button {color:red;}\n" ;
config.shadowTiddlers.EasyEditToolBarStyleSheet += ".easyEditorToolBar .fontnameButton .button {font-family:serif}\n" ;
config.shadowTiddlers.EasyEditToolBarStyleSheet +="/*}}}*/";

store.addNotification("EasyEditToolBarStyleSheet", refreshStyles); 

config.shadowTiddlers.EasyEditDocStyleSheet = "/*{{{*/\n \n/*}}}*/";
if (config.annotations) config.annotations.EasyEditDocStyleSheet = "This stylesheet is applied when editing a text with the wysiwyg easyEditor";

//}}}
/***
!Link button add-on
***/
//{{{
EditorToolbar.createLinkButton = function(place,name) {
	this.elements[name] = createTiddlyButton(place,EditorToolbar.buttons[name].label,EditorToolbar.buttons[name].toolTip,contextualCallback(this,EditorToolbar.onInputLink()),"button");
}

EditorToolbar.onInputLink = function() {
	return function(){
		var browser = config.browser.isGecko ? geckoEditor : (config.browser.isIE ? IEeditor : null);
		var value = browser ? browser.getLink(this.target) : "";
		value = prompt(EditorToolbar.buttons["createlink"].prompt,value);
		if (value) browser.doLink(this.target,value);
		else if (value=="") this.target.execCommand("unlink", false, value);
		EditorToolbar.onUpdateButton.call(this);
		return false;
	}
}

EditorToolbar.buttonsList += ",separator,createlink";

EditorToolbar.buttons.createlink = {onCreate : EditorToolbar.createLinkButton, label:"L", toolTip : "Set link", prompt: "Enter link url"};


geckoEditor.getLink=function(doc){
	var range=doc.defaultView.getSelection().getRangeAt(0);
	var container = range.commonAncestorContainer;
	var node = (container.nodeType==3) ? container.parentNode : range.startContainer.childNodes[range.startOffset];
	if (node && node.tagName=="A") {
		var r=doc.createRange();
		r.selectNode(node);
		doc.defaultView.getSelection().addRange(r);
		return (node.getAttribute("tiddler") ? "#"+node.getAttribute("tiddler") : node.href);
	}
	else return (container.nodeType==3 ? "#"+container.textContent.substr(range.startOffset, range.endOffset-range.startOffset).replace(/ $/,"") : "");
}

geckoEditor.doLink=function(doc,link){ // store tiddler in a temporary attribute to avoid url encoding of tiddler's name
	var pin = "href"+Math.random().toString().substr(3);
	doc.execCommand("createlink", false, pin);
	var isTiddler=(link.charAt(0)=="#");
	var node = doc.defaultView.getSelection().getRangeAt(0).commonAncestorContainer;
	var links= (node.nodeType!=3) ? node.getElementsByTagName("a") : [node.parentNode];
	for (var cpt=0;cpt<links.length;cpt++) 
			if (links[cpt].href==pin){
				links[cpt].href=isTiddler ? "javascript:;" : link; 
				links[cpt].setAttribute("tiddler",isTiddler ? link.substr(1) : "");
			}
}

geckoEditor.beforeLinkPostProcessor = geckoEditor.beforelinkPostProcessor ? geckoEditor.beforelinkPostProcessor : geckoEditor.postProcessor;
geckoEditor.postProcessor = function(text){
	return geckoEditor.beforeLinkPostProcessor(text).replace(/<a tiddler="([^"]*)" href="javascript:;">(.*?)(?:<\/a>)/gi,"[[$2|$1]]").replace(/<a tiddler="" href="/gi,'<a href="');
}

geckoEditor.beforeLinkPreProcessor = geckoEditor.beforeLinkPreProcessor ? geckoEditor.beforeLinkPreProcessor : geckoEditor.preProcessor
geckoEditor.preProcessor = function(text){
	return geckoEditor.beforeLinkPreProcessor(text).replace(/\[\[([^|\]]*)\|([^\]]*)]]/g,'<a tiddler="$2" href="javascript:;">$1</a>');
}


IEeditor.getLink=function(doc){
	var node=doc.selection.createRange().parentElement();
	if (node.tagName=="A") return node.href;
	else return (doc.selection.type=="Text"? "#"+doc.selection.createRange().text.replace(/ $/,"") :"");
}

IEeditor.doLink=function(doc,link){
	doc.execCommand("createlink", false, link);
}

IEeditor.beforeLinkPreProcessor = IEeditor.beforeLinkPreProcessor ? IEeditor.beforeLinkPreProcessor : IEeditor.preProcessor
IEeditor.preProcessor = function(text){
	return IEeditor.beforeLinkPreProcessor(text).replace(/\[\[([^|\]]*)\|([^\]]*)]]/g,'<a ref="#$2">$1</a>');
}

IEeditor.beforeLinkPostProcessor = IEeditor.beforelinkPostProcessor ? IEeditor.beforelinkPostProcessor : IEeditor.postProcessor;
IEeditor.postProcessor = function(text){
	return IEeditor.beforeLinkPostProcessor(text).replace(/<a href="#([^>]*)">([^<]*)<\/a>/gi,"[[$2|$1]]");
}

IEeditor.beforeLinkInitContent = IEeditor.beforeLinkInitContent ? IEeditor.beforeLinkInitContent : IEeditor.initContent;
IEeditor.initContent = function(doc,content){
	IEeditor.beforeLinkInitContent(doc,content);
	var links=doc.body.getElementsByTagName("A");
	for (var cpt=0; cpt<links.length; cpt++) {
		links[cpt].href=links[cpt].ref; //to avoid IE conversion of relative URLs to absolute
		links[cpt].removeAttribute("ref");	
	}
}

config.shadowTiddlers.EasyEditToolBarStyleSheet += "\n/*{{{*/\n.easyEditorToolBar .createlinkButton .button {color:blue;text-decoration:underline;}\n/*}}}*/";

config.shadowTiddlers.EasyEditDocStyleSheet += "\n/*{{{*/\na {color:#0044BB;font-weight:bold}\n/*}}}*/";

//}}}
For this "List" task we don't use the default action "addToList" (that simply adds all selected items to the list) but create the list using the "write" action and refer to the build-in variable "index" that is incremented for every tiddler being processed.
{{{
<<forEachTiddler
    where
        'tiddler.tags.contains("Notes")'
    write
        '(index < 10) ? "* [["+tiddler.title+"]]\n" : ""'
>>
}}}
In the write parameter there is a conditional output: when we are processing the tiddlers 0 to 9 it will write a line with:

 {{{* [[theTiddlerName]]}}}

Tiddler 10 and the following ones will generate no output (as the empty string is specified).

''//Result://''
<<forEachTiddler
    where
        'tiddler.tags.contains("Notes")'
    write
        '(index < 10) ? "* [["+tiddler.title+"]]\n" : ""'
>>
{{{
<<forEachTiddler
    where
        'tiddler.tags.contains("plugin")'
    write
        '""'
        end 'count+" Tiddlers found\n"'
        none '"No Tiddlers found\n"'
>>
}}}
The macro writes an empty string for every tiddler tagged "basic", i.e. it writes nothing. 

Just at the end it writes the number of found tiddlers (using the ''end'' feature of the ForEachTiddler macro) or "No Tiddler found" if no tiddler is tagged with "basic"  (using the ''none'' parameter) .

''//Result://''
<<forEachTiddler
    where
        'tiddler.tags.contains("plugin")'
    write
        '""'
        end 'count+" Tiddlers found\n"'
        none '"No Tiddlers found\n"'
>>
The following macro call exports all tiddlers to a text file "c:/~MyTiddlyWikiExport.txt", using a customized format.
{{{
<<forEachTiddler
 script 'function getSortedTagsText(tiddler) {var tags = tiddler.tags; if (!tags) return ""; tags.sort(); var result = ""; for (var i = 0; i < tags.length;i++) {result += tags[i]+ " ";} return result;} function writeTiddler(tiddler) {return "==== "+tiddler.title+"=========================\nTags: "+ getSortedTagsText(tiddler)+"\nModified: "+tiddler.modified.convertToYYYYMMDDHHMM()+"\nModifier: "+tiddler.modifier+"\n--------------------------------------------------\n"+tiddler.text+"\n--------------------------------------------------\n(End of "+tiddler.title+")\n\n\n\n"}'
 write 
 'writeTiddler(tiddler)' 
 toFile 'file:///c:/MyTiddlyWikiExport.txt' withLineSeparator '\r\n'
>>
}}}
For better readablility here the script text in a nicer layout:
{{{
function getSortedTagsText(tiddler) {
 var tags = tiddler.tags; 
 if (!tags) 
 return ""; 
 tags.sort(); 
 var result = ""; 
 for (var i = 0; i < tags.length;i++) {
 result += tags[i]+ " ";
 } 
 return result;
} 

function writeTiddler(tiddler) {
 return "==== "+tiddler.title+"=========================\n"+
 "Tags: "+ getSortedTagsText(tiddler)+"\n"+
 "Modified: "+tiddler.modified.convertToYYYYMMDDHHMM()+"\n"+
 "Modifier: "+tiddler.modifier+"\n"+
 "--------------------------------------------------\n"+
 tiddler.text+"\n"+
 "--------------------------------------------------\n"
 "(End of "+tiddler.title+")\n\n\n\n"
}
}}}

<<forEachTiddler
 script 'function getSortedTagsText(tiddler) {var tags = tiddler.tags; if (!tags) return ""; tags.sort(); var result = ""; for (var i = 0; i < tags.length;i++) {result += tags[i]+ " ";} return result;} function writeTiddler(tiddler) {return "==== "+tiddler.title+"=========================\nTags: "+ getSortedTagsText(tiddler)+"\nModified: "+tiddler.modified.convertToYYYYMMDDHHMM()+"\nModifier: "+tiddler.modifier+"\n--------------------------------------------------\n"+tiddler.text+"\n--------------------------------------------------\n(End of "+tiddler.title+")\n\n\n\n"}'
 write 
 'writeTiddler(tiddler)' 
 toFile 'file:///c:/MyTiddlyWikiExport.txt' withLineSeparator '\r\n'
>>
<<forEachTiddler
    where
       'tiddler.tags.contains("文章整理")'

    sortBy
       'tiddler.title.toUpperCase()'

    write '" [["+tiddler.title+" ]] \"view ["+tiddler.title+"]\" [["+tiddler.title+"]] "'

        begin '"<<tabs txtMyAutoTab "'

        end '">"+">"'

        none '"//No tiddler tagged with \"文章整理\"//"'
>>
//{{{
//============================================================================
// getCreateDate Function
//============================================================================
//
// Returns the "create date" as generated by the AutoTaggerPlugin
// (http://www.TiddlyTools.com/#AutoTaggerPlugin).
// The create date must be stored in the default format "YYYY.0MM.0DD".
//
// @return [may be null] the create date (as a String) or null if no create 
// date is found.
//
version.extensions.getCreateDate = {major: 1, minor: 0, revision: 0, 
 date: new Date(2005,11,21), 
 provider: "http://tiddlywiki.abego-software.de"};
//
function getCreateDate(tiddler) {
 if (!tiddler || !tiddler.tags) {
 return null;
 }

 for(var i = 0; i < tiddler.tags.length; i++) {
 var matches = tiddler.tags[i].match(/^[0-9]{4}\.[0-9]{2}\.[0-9]{2}$/);
 if (matches && matches.length > 0) {
 return matches[0];
 }
 }
 return null;
}

//}}}
/***
|''Name:''|zh-HantTranslationPlugin|
|''Description:''|Translation of TiddlyWiki into Traditional Chinese|
|''Source:''|http://tiddlywiki-zh.googlecode.com/svn/trunk/|
|''Subversion:''|http://svn.tiddlywiki.org/Trunk/association/locales/core/zh-Hant/locale.zh-Hant.js|
|''Author:''|BramChen (bram.chen (at) gmail (dot) com)|
|''Version:''|2.2.6|
|''Date:''|Dec 01, 2007|
|''Comments:''|Please make comments at http://groups-beta.google.com/group/TiddlyWiki-zh/|
|''License:''|[[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|''~CoreVersion:''|2.2.0|
***/

//{{{
// --
// -- Translateable strings
// --

// Strings in "double quotes" should be translated; strings in 'single quotes' should be left alone

config.locale = 'zh-Hant'; // W3C language tag

if (config.options.txtUserName == 'YourName' || !config.options.txtUserName) // do not translate this line, but do translate the next line
	merge(config.options,{txtUserName: "YourName"});

merge(config.tasks,{
	save: {text: "儲存", tooltip: "儲存變更至此 TiddlyWiki", action: saveChanges},
	sync: {text: "同步", tooltip: "將你的資料內容與外部伺服器與檔案同步", content: '<<sync>>'},
	importTask: {text: "導入", tooltip: "自其他檔案或伺服器導入文章或套件", content: '<<importTiddlers>>'},
	tweak: {text: "選項", tooltip: "改變此 TiddlyWiki 的顯示與行為的設定", content: '<<options>>'},
	plugins: {text: "套件管理", tooltip: "管理已安裝的套件", content: '<<plugins>>'}
});

merge(config.optionsDesc,{
	txtUserName: "編輯文章所使用之作者署名",
	chkRegExpSearch: "啟用正規式搜尋",
	chkCaseSensitiveSearch: "搜尋時,區分大小寫",
	chkAnimate: "使用動畫顯示",
	chkSaveBackups: "儲存變更前,保留備份檔案",
	chkAutoSave: "自動儲存變更",
	chkGenerateAnRssFeed: "儲存變更時,也儲存 RSS feed",
	chkSaveEmptyTemplate: "儲存變更時,也儲存空白範本",
	chkOpenInNewWindow: "於新視窗開啟連結",
	chkToggleLinks: "點擊已開啟文章將其關閉",
	chkHttpReadOnly: "非本機瀏覽文件時,隱藏編輯功能",
	chkForceMinorUpdate: "修改文章時,不變更作者名稱與日期時間",
	chkConfirmDelete: "刪除文章前須確認",
	chkInsertTabs: "使用 tab 鍵插入定位字元,而非跳至下一個欄位",
	txtBackupFolder: "存放備份檔案的資料夾",
	txtMaxEditRows: "編輯模式中顯示列數",
	txtFileSystemCharSet: "指定儲存文件所在之檔案系統之字集 (僅適用於 Firefox/Mozilla only)"});

// Messages
merge(config.messages,{
	customConfigError: "套件載入發生錯誤,詳細請參考 PluginManager",
	pluginError: "發生錯誤: %0",
	pluginDisabled: "未執行,因標籤設為 'systemConfigDisable'",
	pluginForced: "已執行,因標籤設為 'systemConfigForce'",
	pluginVersionError: "未執行,套件需較新版本的 TiddlyWiki",
	nothingSelected: "尚未作任何選擇,至少需選擇一項",
	savedSnapshotError: "此 TiddlyWiki 未正確存檔,詳見 http://www.tiddlywiki.com/#DownloadSoftware",
	subtitleUnknown: "(未知)",
	undefinedTiddlerToolTip: "'%0' 尚無內容",
	shadowedTiddlerToolTip: "'%0' 尚無內容, 但已定義隱藏的預設值",
	tiddlerLinkTooltip: "%0 - %1, %2",
	externalLinkTooltip: "外部連結至 %0",
	noTags: "未設定標籤的文章",
	notFileUrlError: "須先將此 TiddlyWiki 存至檔案,才可儲存變更",
	cantSaveError: "無法儲存變更。可能的原因有:\n- 你的瀏覽器不支援此儲存功能(Firefox, Internet Explorer, Safari and Opera 經適當設定後可儲存變更)\n- 也可能是你的 TiddlyWiki 檔名包含不合法的字元所致。\n- 或是 TiddlyWiki 文件被改名或搬移。",
	invalidFileError: " '%0' 非有效之 TiddlyWiki 文件",
	backupSaved: "已儲存備份",
	backupFailed: "無法儲存備份",
	rssSaved: "RSS feed 已儲存",
	rssFailed: "無法儲存 RSS feed ",
	emptySaved: "已儲存範本",
	emptyFailed: "無法儲存範本",
	mainSaved: "主要的TiddlyWiki已儲存",
	mainFailed: "無法儲存主要 TiddlyWiki,所作的改變未儲存",
	macroError: "巨集 <<\%0>> 執行錯誤",
	macroErrorDetails: "執行巨集 <<\%0>> 時,發生錯誤 :\n%1",
	missingMacro: "無此巨集",
	overwriteWarning: "'%0' 已存在,[確定]覆寫之",
	unsavedChangesWarning: "注意! 尚未儲存變更\n\n[確定]存檔,或[取消]放棄存檔?",
	confirmExit: "--------------------------------\n\nTiddlyWiki 以更改內容尚未儲存,繼續的話將遺失這些更動\n\n--------------------------------",
	saveInstructions: "SaveChanges",
	unsupportedTWFormat: "未支援此 TiddlyWiki 格式:'%0'",
	tiddlerSaveError: "儲存文章 '%0' 時,發生錯誤。",
	tiddlerLoadError: "載入文章 '%0' 時,發生錯誤。",
	wrongSaveFormat: "無法使用格式 '%0' 儲存,請使用標准格式存放",
	invalidFieldName: "無效的欄位名稱:%0",
	fieldCannotBeChanged: "無法變更欄位:'%0'",
	loadingMissingTiddler: "正從伺服器 '%1' 的:\n\n工作區 '%3' 中的 '%2' 擷取文章 '%0'"});

merge(config.messages.messageClose,{
	text: "關閉",
	tooltip: "關閉此訊息"});

config.messages.backstage = {
	open: {text: "控制台", tooltip: "開啟控制台執行編寫工作"},
	close: {text: "關閉", tooltip: "關閉控制台"},
	prompt: "控制台:",
	decal: {
		edit: {text: "編輯", tooltip: "編輯 '%0'"}
	}
};

config.messages.listView = {
	tiddlerTooltip: "檢視全文",
	previewUnavailable: "(無法預覽)"
};

config.messages.dates.months = ["一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月"];
config.messages.dates.days = ["星期日", "星期一","星期二", "星期三", "星期四", "星期五", "星期六"];
// config.messages.dates.shortMonths = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
config.messages.dates.shortMonths = ["一", "二", "三", "四", "五", "六", "七", "八", "九", "十", "十一", "十二"];
// config.messages.dates.shortDays = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
config.messages.dates.shortDays = ["日", "一","二", "三", "四", "五", "六"];
// suffixes for dates, eg "1st","2nd","3rd"..."30th","31st"
config.messages.dates.daySuffixes = ["st","nd","rd","th","th","th","th","th","th","th",
		"th","th","th","th","th","th","th","th","th","th",
		"st","nd","rd","th","th","th","th","th","th","th",
		"st"];
config.messages.dates.am = "上午";
config.messages.dates.pm = "下午";

merge(config.messages.tiddlerPopup,{ 
	});

merge(config.views.wikified.tag,{
	labelNoTags: "未設標籤",
	labelTags: "標籤: ",
	openTag: "開啟標籤 '%0'",
	tooltip: "顯示標籤為 '%0' 的文章",
	openAllText: "開啟以下所有文章",
	openAllTooltip: "開啟以下所有文章",
	popupNone: "僅此文標籤為 '%0'"});

merge(config.views.wikified,{
	defaultText: "",
	defaultModifier: "(未完成)",
	shadowModifier: "(預設)",
	dateFormat: "YYYY年0MM月0DD日",
	createdPrompt: "建立於"});

merge(config.views.editor,{
	tagPrompt: "設定標籤之間以空白區隔,[[標籤含空白時請使用雙中括弧]],或點選現有之標籤加入",
	defaultText: ""});

merge(config.views.editor.tagChooser,{
	text: "標籤",
	tooltip: "點選現有之標籤加至本文章",
	popupNone: "未設定標籤",
	tagTooltip: "加入標籤 '%0'"});

merge(config.messages,{
	sizeTemplates:
		[
		{unit: 1024*1024*1024, template: "%0\u00a0GB"},
		{unit: 1024*1024, template: "%0\u00a0MB"},
		{unit: 1024, template: "%0\u00a0KB"},
		{unit: 1, template: "%0\u00a0B"}
		]});

merge(config.macros.search,{
	label: " 尋找",
	prompt: "搜尋本 Wiki",
	accessKey: "F",
	successMsg: " %0 篇符合條件: %1",
	failureMsg: " 無符合條件: %0"});

merge(config.macros.tagging,{
	label: "引用標籤:",
	labelNotTag: "無引用標籤",
	tooltip: "列出標籤為 '%0' 的文章"});

merge(config.macros.timeline,{
	dateFormat: "YYYY年0MM月0DD日"});

merge(config.macros.allTags,{
	tooltip: "顯示文章- 標籤為'%0'",
	noTags: "沒有標籤"});

config.macros.list.all.prompt = "依字母排序";
config.macros.list.missing.prompt = "被引用且內容空白的文章";
config.macros.list.orphans.prompt = "未被引用的文章";
config.macros.list.shadowed.prompt = "這些隱藏的文章已預設內容";
config.macros.list.touched.prompt = "自下載或新增後被修改過的文章"; 

merge(config.macros.closeAll,{
	label: "全部關閉",
	prompt: "關閉所有開啟中的 tiddler (編輯中除外)"});

merge(config.macros.permaview,{
	label: "引用連結",
	prompt: "可存取現有開啟之文章的連結位址"});

merge(config.macros.saveChanges,{
	label: "儲存變更",
	prompt: "儲存所有文章,產生新的版本",
	accessKey: "S"});

merge(config.macros.newTiddler,{
	label: "新增文章",
	prompt: "新增 tiddler",
	title: "新增文章",
	accessKey: "N"});

merge(config.macros.newJournal,{
	label: "新增日誌",
	prompt: "新增 jounal",
	accessKey: "J"});

merge(config.macros.options,{
	wizardTitle: "增訂的進階選項",
	step1Title: "增訂的選項儲存於瀏覽器的 cookies",
	step1Html: "<input type='hidden' name='markList'></input><br><input type='checkbox' checked='false' name='chkUnknown'>顯示未知選項</input>",
	unknownDescription: "//(未知)//",
	listViewTemplate: {
		columns: [
			{name: 'Option', field: 'option', title: "選項", type: 'String'},
			{name: 'Description', field: 'description', title: "說明", type: 'WikiText'},
			{name: 'Name', field: 'name', title: "名稱", type: 'String'}
			],
		rowClasses: [
			{className: 'lowlight', field: 'lowlight'}
			]}
	});

merge(config.macros.plugins,{
	wizardTitle: "擴充套件管理",
	step1Title: "- 已載入之套件",
	step1Html: "<input type='hidden' name='markList'></input>", // DO NOT TRANSLATE
	skippedText: "(此套件因剛加入,故尚未執行)",
	noPluginText: "未安裝套件",
	confirmDeleteText: "確認是否刪除此文章:\n\n%0",
	removeLabel: "移除 systemConfig 標籤",
	removePrompt: "移除 systemConfig 標籤",
	deleteLabel: "刪除",
	deletePrompt: "永遠刪除所選",

	listViewTemplate : {
		columns: [
			{name: 'Selected', field: 'Selected', rowName: 'title', type: 'Selector'},
			{name: 'Tiddler', field: 'tiddler', title: "套件", type: 'Tiddler'},
			{name: 'Size', field: 'size', tiddlerLink: 'size', title: "大小", type: 'Size'},
			{name: 'Forced', field: 'forced', title: "強制執行", tag: 'systemConfigForce', type: 'TagCheckbox'},
			{name: 'Disabled', field: 'disabled', title: "停用", tag: 'systemConfigDisable', type: 'TagCheckbox'},
			{name: 'Executed', field: 'executed', title: "已載入", type: "Boolean", trueText: "是", falseText: "否"},
			{name: 'Startup Time', field: 'startupTime', title: "載入時間", type: 'String'},
			{name: 'Error', field: 'error', title: "載入狀態", type: 'Boolean', trueText: "錯誤", falseText: "正常"},
			{name: 'Log', field: 'log', title: "紀錄", type: 'StringList'}
			],
		rowClasses: [
			{className: 'error', field: 'error'},
			{className: 'warning', field: 'warning'}
			]}
	});

merge(config.macros.toolbar,{
	moreLabel: "其他",
	morePrompt: "顯示更多工具命令"});
	
merge(config.macros.refreshDisplay,{
	label: "刷新",
	prompt: "刷新此 TiddlyWiki 顯示"
	});
	
merge(config.macros.importTiddlers,{
	readOnlyWarning: "TiddlyWiki 於唯讀模式下,不支援導入文章。請由本機(file://)開啟 TiddlyWiki 文件",
	wizardTitle: "自其他檔案或伺服器導入文章",
	step1Title: "步驟一:指定伺服器或來源文件",
	step1Html: "指定伺服器類型:<select name='selTypes'><option value=''>選取...</option></select><br>請輸入網址或路徑:<input type='text' size=50 name='txtPath'><br>...或選擇來源文件:<input type='file' size=50 name='txtBrowse'><br><hr>...或選擇指定的饋入來源:<select name='selFeeds'><option value=''>選取...</option></select>",
	openLabel: "開啟",
	openPrompt: "開啟檔案或",
	openError: "讀取來源文件時發生錯誤",
	statusOpenHost: "正與伺服器建立連線",
	statusGetWorkspaceList: "正在取得可用之文章清單",
	step2Title: "步驟二:選擇工作區",
	step2Html: "輸入工作區名稱:<input type='text' size=50 name='txtWorkspace'><br>...或選擇工作區:<select name='selWorkspace'><option value=''>選取...</option></select>",
	cancelLabel: "取消",
	cancelPrompt: "取消本次導入動作",
	statusOpenWorkspace: "正在開啟工作區",
	statusGetTiddlerList: "正在取得可用之文章清單",
	step3Title: "步驟三:選擇欲導入之文章",
	step3Html: "<input type='hidden' name='markList'></input><br><input type='checkbox' checked='true' name='chkSync'>保持這些文章與伺服器的連結,便於同步後續的變更。</input><br><input type='checkbox' name='chkSave'>儲存此伺服器的詳細資訊於標籤為 'systemServer' 的文章名為:</input> <input type='text' size=25 name='txtSaveTiddler'>", 
	importLabel: "導入",
	importPrompt: "導入所選文章",
	confirmOverwriteText: "確定要覆寫這些文章:\n\n%0",
	step4Title: "步驟四:正在導入%0 篇文章",
	step4Html: "<input type='hidden' name='markReport'></input>", // DO NOT TRANSLATE
	doneLabel: "完成",
	donePrompt: "關閉",
	statusDoingImport: "正在導入文章 ...",
	statusDoneImport: "所選文章已導入",
	systemServerNamePattern: "%2 位於 %1",
	systemServerNamePatternNoWorkspace: "%1",
	confirmOverwriteSaveTiddler: "此 tiddler '%0' 已經存在。點擊「確定」以伺服器上料覆寫之,或「取消」不變更後離開",
	serverSaveTemplate: "|''Type:''|%0|\n|''網址:''|%1|\n|''工作區:''|%2|\n\n此文為自動產生紀錄伺服器之相關資訊。",
	serverSaveModifier: "(系統)",

	listViewTemplate: {
		columns: [
			{name: 'Selected', field: 'Selected', rowName: 'title', type: 'Selector'},
			{name: 'Tiddler', field: 'tiddler', title: "文章", type: 'Tiddler'},
			{name: 'Size', field: 'size', tiddlerLink: 'size', title: "大小", type: 'Size'},
			{name: 'Tags', field: 'tags', title: "標籤", type: 'Tags'}
			],
		rowClasses: [
			]}
	});

merge(config.macros.sync,{
	listViewTemplate: {
		columns: [
			{name: 'Selected', field: 'selected', rowName: 'title', type: 'Selector'},
			{name: 'Tiddler', field: 'tiddler', title: "文章", type: 'Tiddler'},
			{name: 'Server Type', field: 'serverType', title: "伺服器類型", type: 'String'},
			{name: 'Server Host', field: 'serverHost', title: "伺服器主機", type: 'String'},
			{name: 'Server Workspace', field: 'serverWorkspace', title: "伺服器工作區", type: 'String'},
			{name: 'Status', field: 'status', title: "同步情形", type: 'String'},
			{name: 'Server URL', field: 'serverUrl', title: "伺服器網址", text: "View", type: 'Link'}
			],
		rowClasses: [
			],
		buttons: [
			{caption: "同步更新這些文章", name: 'sync'}
			]},
	wizardTitle: "將你的資料內容與外部伺服器與檔案同步",
	step1Title: "選擇欲同步的文章",
	step1Html: '<input type="hidden" name="markList"></input>', // DO NOT TRANSLATE
	syncLabel: "同步",
	syncPrompt: "同步更新這些文章",
	hasChanged: "已更動",
	hasNotChanged: "未更動",
	syncStatusList: {
		none: {text: "...", color: 'transparent'},
		changedServer: {text: "伺服器資料已更動", color: '#80ff80'},
		changedLocally: {text: "本機資料已更動", color: '#80ff80'},
		changedBoth: {text: "已同時更新本機與伺服器上的資料", color: '#ff8080'},
		notFound: {text: "伺服器無此資料", color: '#ffff80'},
		putToServer: {text: "已儲存更新資料至伺服器", color: '#ff80ff'},
		gotFromServer: {text: "已從伺服器擷取更新資料", color: '#80ffff'}
		}
	});

merge(config.macros.annotations,{
	});

merge(config.commands.closeTiddler,{
	text: "關閉",
	tooltip: "關閉本文"});

merge(config.commands.closeOthers,{
	text: "關閉其他",
	tooltip: "關閉其他文章"});

merge(config.commands.editTiddler,{
	text: "編輯",
	tooltip: "編輯本文",
	readOnlyText: "檢視",
	readOnlyTooltip: "檢視本文之原始內容"});

merge(config.commands.saveTiddler,{
	text: "完成",
	tooltip: "確定修改"});

merge(config.commands.cancelTiddler,{
	text: "取消",
	tooltip: "取消修改",
	warning: "確定取消對 '%0' 的修改嗎?",
	readOnlyText: "完成",
	readOnlyTooltip: "返回正常顯示模式"});

merge(config.commands.deleteTiddler,{
	text: "刪除",
	tooltip: "刪除文章",
	warning: "確定刪除 '%0'?"});

merge(config.commands.permalink,{
	text: "引用連結",
	tooltip: "本文引用連結"});

merge(config.commands.references,{
	text: "引用",
	tooltip: "引用本文的文章",
	popupNone: "本文未被引用"});

merge(config.commands.jump,{
	text: "捲頁",
	tooltip: "捲頁至其他已開啟的文章"});

merge(config.commands.syncing,{
	text: "同步",
	tooltip: "本文章與伺服器或其他外部檔案的同步資訊",
	currentlySyncing: "<div>同步類型:<span class='popupHighlight'>'%0'</span></"+"div><div>與伺服器:<span class='popupHighlight'>%1 同步</span></"+"div><div>工作區:<span class='popupHighlight'>%2</span></"+"div>", // Note escaping of closing <div> tag
	notCurrentlySyncing: "無進行中的同步動作",
	captionUnSync: "停止同步此文章",
	chooseServer: "與其他伺服器同步此文章:",
	currServerMarker: "\u25cf ",
	notCurrServerMarker: "  "});

merge(config.commands.fields,{
	text: "欄位",
	tooltip: "顯示此文章的擴充資訊",
	emptyText: "此文章沒有擴充欄位",
	listViewTemplate: {
		columns: [
			{name: 'Field', field: 'field', title: "擴充欄位", type: 'String'},
			{name: 'Value', field: 'value', title: "內容", type: 'String'}
			],
		rowClasses: [
			],
		buttons: [
			]}});

merge(config.shadowTiddlers,{
	DefaultTiddlers: "GettingStarted",
	GettingStarted: "使用此 TiddlyWiki 的空白範本之前,請先修改以下預設文章:\n* SiteTitle 及 SiteSubtitle:網站的標題和副標題,顯示於頁面上方<br />(在儲存變更後,將顯示於瀏覽器視窗的標題列)。\n* MainMenu:主選單(通常在頁面左側)。\n* DefaultTiddlers:內含一些文章的標題,可於載入TiddlyWiki 後的預設開啟。\n請輸入您的大名,作為所建立/ 編輯的文章署名:<<option txtUserName>>",
	MainMenu: "[[使用說明|GettingStarted]]\n\n\n^^~TiddlyWiki 版本:<<version>>\n© 2007 [[UnaMesa|http://www.unamesa.org/]]^^",
	OptionsPanel: "這些設定將暫存於瀏覽器\n請簽名<<option txtUserName>>\n (範例:WikiWord)\n\n <<option chkSaveBackups>> 儲存備份\n <<option chkAutoSave>> 自動儲存\n <<option chkRegExpSearch>> 正規式搜尋\n <<option chkCaseSensitiveSearch>> 區分大小寫搜尋\n <<option chkAnimate>> 使用動畫顯示\n----\n [[進階選項|AdvancedOptions]]",
	SiteTitle: "我的 TiddlyWiki",
	SiteSubtitle: "一個可重複使用的個人網頁式筆記本",
	SiteUrl: 'http://www.tiddlywiki.com/',
	SideBarOptions: '<<search>><<closeAll>><<permaview>><<newTiddler>><<newJournal " YYYY年0MM月0DD日" "日誌">><<saveChanges>><<slider chkSliderOptionsPanel OptionsPanel  "偏好設定 »" "變更 TiddlyWiki 選項">>',
	SideBarTabs: '<<tabs txtMainTab "最近更新" "依更新日期排序" TabTimeline "全部" "所有文章" TabAll "分類" "所有標籤" TabTags "更多" "其他" TabMore>>',
	StyleSheet: '[[StyleSheetLocale]]',
	TabMore: '<<tabs txtMoreTab "未完成" "內容空白的文章" TabMoreMissing "未引用" "未被引用的文章" TabMoreOrphans "預設文章" "已預設內容的隱藏文章" TabMoreShadowed>>'});

merge(config.annotations,{
	AdvancedOptions: "此預設文章可以存取一些進階選項。",
	ColorPalette: "此預設文章裡的設定值,將決定 ~TiddlyWiki 使用者介面的配色。",
	DefaultTiddlers: "當 ~TiddlyWiki 在瀏覽器中開啟時,此預設文章裡列出的文章,將被自動顯示。",
	EditTemplate: "此預設文章裡的 HTML template 將決定文章進入編輯模式時的顯示版面。",
	GettingStarted: "此預設文章提供基本的使用說明。",
	ImportTiddlers: "此預設文章提供存取導入中的文章。",
	MainMenu: "此預設文章的內容,為於螢幕左側主選單的內容",
	MarkupPreHead: "此文章的內容將加至 TiddlyWiki 文件的 <head> 段落的起始",
	MarkupPostHead: "此文章的內容將加至 TiddlyWiki 文件的 <head> 段落的最後",
	MarkupPreBody: "此文章的內容將加至 TiddlyWiki 文件的 <body> 段落的起始",
	MarkupPostBody: "此文章的內容將加至 TiddlyWiki 文件的 <body> 段落的最後,於 script 區塊之前",
	OptionsPanel: "此預設文章的內容,為於螢幕右側副選單中的選項面板裡的內容",
	PageTemplate: "此預設文章裡的 HTML template 決定的 ~TiddlyWiki 主要的版面配置",
	PluginManager: "此預設文章提供存取套件管理員",
	SideBarOptions: "此預設文章的內容,為於螢幕右側副選單中選項面板裡的內容",
	SideBarTabs: "此預設文章的內容,為於螢幕右側副選單中的頁籤面板裡的內容",
	SiteSubtitle: "此預設文章的內容為頁面的副標題",
	SiteTitle: "此預設文章的內容為頁面的主標題",
	SiteUrl: "此預設文章的內容須設定為文件發佈時的完整網址",
	StyleSheetColors: "此預設文章內含的 CSS 規則,為相關的頁面元素的配色。''勿修改此文'',請於 StyleSheet 中作增修。",
	StyleSheet: "此預設文章內容可包含 CSS 規則",
	StyleSheetLayout: "此預設文章內含的 CSS 規則,為相關的頁面元素的版面配置。''勿修改此文'',請於 StyleSheet 中作增修。",
	StyleSheetLocale: "此預設文章內含的 CSS 規則,可依翻譯語系做適當調整",
	StyleSheetPrint: "此預設文章內含的 CSS 規則,用於列印時的樣式",
	TabAll: "此預設文章的內容,為於螢幕右側副選單中的「全部」頁籤的內容",
	TabMore: "此預設文章的內容,為於螢幕右側副選單中的「更多」頁籤的內容",
	TabMoreMissing: "此預設文章的內容,為於螢幕右側副選單中的「未完成」頁籤的內容",
	TabMoreOrphans: "此預設文章的內容,為於螢幕右側副選單中的「未引用」頁籤的內容",
	TabMoreShadowed: "此預設文章的內容,為於螢幕右側副選單中的「預設文章」頁籤的內容",
	TabTags: "此預設文章的內容,為於螢幕右側副選單中的「分類」頁籤的內容",
	TabTimeline: "此預設文章的內容,為於螢幕右側副選單中的「最近更新」頁籤的內容",
	ViewTemplate: "此預設文章裡的 HTML template 決定文章顯示的樣子"
	});
//}}}
#樹系內多樹根、子網域 DNS 如何實作?
#Non-DC 機器退出網域可用本機 administrator 帳號與 domain admins 群組帳號
#同樹系內使用者帳戶遷移,不會詢問如何設置密碼、不會詢問是否 maintain SIDHistory 欄位
**子網域搬移至父層網域 SIDhistory 直接 maintain
/***
|<html><a name="Top"/></html>''Name:''|PartTiddlerPlugin|
|''Version:''|1.0.9 (2007-07-14)|
|''Source:''|http://tiddlywiki.abego-software.de/#PartTiddlerPlugin|
|''Author:''|UdoBorkowski (ub [at] abego-software [dot] de)|
|''Licence:''|[[BSD open source license]]|
|''CoreVersion:''|2.1.3|
|''Browser:''|Firefox 1.0.4+; InternetExplorer 6.0|
!Table of Content<html><a name="TOC"/></html>
* <html><a href="javascript:;" onclick="window.scrollAnchorVisible('Description',null, event)">Description, Syntax</a></html>
* <html><a href="javascript:;" onclick="window.scrollAnchorVisible('Applications',null, event)">Applications</a></html>
** <html><a href="javascript:;" onclick="window.scrollAnchorVisible('LongTiddler',null, event)">Refering to Paragraphs of a Longer Tiddler</a></html>
** <html><a href="javascript:;" onclick="window.scrollAnchorVisible('Citation',null, event)">Citation Index</a></html>
** <html><a href="javascript:;" onclick="window.scrollAnchorVisible('TableCells',null, event)">Creating "multi-line" Table Cells</a></html>
** <html><a href="javascript:;" onclick="window.scrollAnchorVisible('Tabs',null, event)">Creating Tabs</a></html>
** <html><a href="javascript:;" onclick="window.scrollAnchorVisible('Sliders',null, event)">Using Sliders</a></html>
* <html><a href="javascript:;" onclick="window.scrollAnchorVisible('Revisions',null, event)">Revision History</a></html>
* <html><a href="javascript:;" onclick="window.scrollAnchorVisible('Code',null, event)">Code</a></html>
!Description<html><a name="Description"/></html>
With the {{{<part aPartName> ... </part>}}} feature you can structure your tiddler text into separate (named) parts. 
Each part can be referenced as a "normal" tiddler, using the "//tiddlerName//''/''//partName//" syntax (e.g. "About/Features").  E.g. you may create links to the parts (e.g. {{{[[Quotes/BAX95]]}}} or {{{[[Hobbies|AboutMe/Hobbies]]}}}), use it in {{{<<tiddler...>>}}} or {{{<<tabs...>>}}} macros etc.


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

!Revision history<html><a name="Revisions"/></html>
* v1.0.9 (2007-07-14)
** Bugfix: Error when using the SideBarTabs example and switching between "More" and "Shadow". Thanks to cmari for reporting the issue.
* v1.0.8 (2007-06-16)
** Speeding up display of tiddlers containing multiple pard definitions. Thanks to Paco Rivière for reporting the issue.
** Support "./partName" syntax inside <<tabs ...>> macro
* v1.0.7 (2007-03-07)
** Bugfix: <<tiddler "./partName">> does not always render correctly after a refresh (e.g. like it happens when using the "Include" plugin). Thanks to Morris Gray for reporting the bug.
* v1.0.6 (2006-11-07)
** Bugfix: cannot edit tiddler when UploadPlugin by Bidix is installed. Thanks to José Luis González Castro for reporting the bug.
* v1.0.5 (2006-03-02)
** Bugfix: Example with multi-line table cells does not work in IE6. Thanks to Paulo Soares for reporting the bug.
* v1.0.4 (2006-02-28)
** Bugfix: Shadow tiddlers cannot be edited (in TW 2.0.6). Thanks to Torsten Vanek for reporting the bug.
* v1.0.3 (2006-02-26)
** Adapt code to newly introduced Tiddler.prototype.isReadOnly() function (in TW 2.0.6). Thanks to Paulo Soares for reporting the problem.
* v1.0.2 (2006-02-05)
** Also allow other macros than the "tiddler" macro use the "." in the part reference (to refer to "this" tiddler)
* v1.0.1 (2006-01-27)
** Added Table of Content for plugin documentation. Thanks to RichCarrillo for suggesting.
** Bugfix: newReminder plugin does not work when PartTiddler is installed. Thanks to PauloSoares for reporting.
* v1.0.0 (2006-01-25)
** initial version
/***
|Name|ShowUpdatesPlugin|
|Created by|SaqImtiaz|
|Version|0.2 |
|Requires|~TW2.x|
!!!Description:
Allows you to list tiddlers that have changed since the users last visit. You can list only all changed tiddlers, or filter them to only show tiddlers that have or do not have a specific tag. By default a simple list of the titles of changed tiddlers is created. However, using an extremely versatile syntax you can provide a custom template for the generated text.

!!!Installation:
Copy the contents of this tiddler to your TW, tag with systemConfig, save and reload your TW.

!!!Syntax:
{{{<<showUpdates>>}}}
additional optional params:
{{{<showUpdates excludeTag:TagToExclude onlyTag:TagToList maxEntries:10 write:CustomWriteParameter >>}}}
excludeTag: ~TagToExclude
onlyTag: ~TagToList
maxEntries: max number of entries displayed when there are no updates. (default is 10, which can be changed in the config.macros.showUpdates.settings part of the code)
write: if a write parameter is not provided, an un-numbered list of the updates is generated. Alternatively, you can specify a custom 'template' for the text generated. The syntax for the write parameter is identical to that of the forEachTiddler macro. Additonal documentation on this syntax will be provided soon.
Some of the variables available in the write parameter are 'index', 'count' and 'lastVisit' where lastVisit is the date of the last visit in the format YYYYMMDDHHMM. Also areUpdates is a boolean that is true if there are new updates since the users last visit.

!!!To Do:
*refactor code to facilitate translations
*a streamlined version without the custom write parameter


!!!Code
***/
//{{{
window.lewcidLastVisit = '';
window.old_lewcid_whatsnew_restart = window.restart;
window.restart = function()
{
        if(config.options.txtLastVisit)
                 lewcidLastVisit= config.options.txtLastVisit;
        config.options.txtLastVisit = (new Date()).convertToYYYYMMDDHHMM();
        saveOptionCookie('txtLastVisit');
        window.old_lewcid_whatsnew_restart();
}

TiddlyWiki.prototype.lewcidGetTiddlers = function(field,excludeTag,includeTag,updatesOnly)
{
              var results = [];
              this.forEachTiddler(function(title,tiddler)
                      {
                      if(excludeTag == undefined || !tiddler.isTagged(excludeTag))
                                    if(includeTag == undefined ||  tiddler.isTagged(includeTag))
                                            if ( updatesOnly == false || tiddler.modified.convertToYYYYMMDDHHMM()>lewcidLastVisit)
                                                  results.push(tiddler);
                      });
              if(field)
                  results.sort(function (a,b) {if(a[field] == b[field]) return(0); else return (a[field] < b[field]) ? -1 : +1; });
              return results;
}

config.macros.showUpdates={};
config.macros.showUpdates.settings =
{
         maxEntries: 10  //max items to show, if there are no updates since last visit
}

config.macros.showUpdates.handler = function(place,macroName,params,wikifier,paramString,tiddler)
{
          var args = paramString.parseParams("list",null,true);
          var write = getParam(args, "write", undefined);
          var onlyTag = getParam(args, "onlyTag", undefined);
          var excludeTag = getParam(args, "excludeTag", undefined);
          var sortBy = "modified";
          var maxEntries = getParam(args,"maxEntries",this.settings.maxEntries);

          if (lewcidLastVisit) 
                {var tiddlers = store.lewcidGetTiddlers(sortBy,excludeTag,onlyTag,true);
                 var areUpdates = tiddlers.length>0? true:false;}

          //if (!lewcidLastVisit)
          //     {var countLine = "!!最近的更新:";
                  var tiddlers = store.lewcidGetTiddlers(sortBy,excludeTag,onlyTag,false);
                  var areUpdates = false;
          //     }
          //else if (tiddlers.length == 0)
          //     {var countLine = "!!@@color:red;上次拜訪後, 沒有任何更新 " + (Date.convertFromYYYYMMDDHHMM(lewcidLastVisit)).formatString(" (DD/MM/YY)") + "@@\n!!最近的更新:";
         //      var tiddlers = store.lewcidGetTiddlers(sortBy,excludeTag,onlyTag,false);}
         // else
         //      {var countLine ="!!@@ 自從上次拜訪後, 共有 "+ tiddlers.length +" 更新 " + (Date.convertFromYYYYMMDDHHMM(lewcidLastVisit)).formatString(" (DD/MM/YY)") + "@@";}

          tiddlers = tiddlers.reverse();
          var lastVisit = lewcidLastVisit? lewcidLastVisit:undefined;
          var count = areUpdates == true? tiddlers.length : maxEntries;
          var sp = createTiddlyElement(place,"span","showUpdates");
          if (write==undefined)
                 {
                  //wikify(countLine,sp);
                  var list = createTiddlyElement(sp,"ul");
                  for (var i = 0; i < count; i++)
                          {
                           var tiddler = tiddlers[i];
                           createTiddlyLink(createTiddlyElement(list,"li"), tiddler.title, true);
                          }
                 }
          else
                {
                 var list = '';
                 for (var index = 0; index < count; index++) {
                 var tiddler = tiddlers[index];
                 list += eval(write); }
                 wikify(list, sp);
                }
}
//}}}
/***
|''巨集名稱:''|toBalaAjax|
|''版本:''|1.0 (2008-03-06)|
|''原始檔:''||
|''作者:''|S L CHEN|
|''授權:''|BSD|
|''倚賴''|toBalaHTML, toBalaFile|
|''TiddlyWiki 適用版本''|2.3+|
|''適用瀏覽器''|Firefox 1.5+, IE 6.0|
|''使用語法''| |
***/

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

config.macros.toBalaAjax.handler = function(place,macroName,params,wikifier,paramString,tiddler){

  if (!params[0]) {
     alert("請給檔名");
     return;
  }

  // 檔名
  var xfname = params[0]; 

  var slabel = params[1] || "儲存網頁";
  var olabel = params[2] || "檢視網頁";
  var xwidth = params[3] || 550;
  var xheight = params[4] || 400;

  createTiddlyButton(place, olabel, olabel,
       function(e) { config.macros.toBalaHTML.show(e,"",xfname,xwidth,xheight); },
       null, null, null);

  if (readOnly) {
     return;
  }

  createTiddlyButton(place, slabel, slabel,
       function(e) { config.macros.toBalaSaveFile.show(e, tiddler.title,xfname); },
       null, null, null);
}
//}}}
!使用說明
{{{
<<toBalaAjax  "ajax\html\testAjax.htm"  "儲存網頁 : ajax\html\testAjax.htm">>
}}}

!實作範例
<<toBalaAjax "ajax\html\testAjax.htm" "儲存網頁 : ajax\html\testAjax.htm">>
/*{{{*/
<html>
<head>
<meta HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf8">
</head>

<body>
<h2 align=center>顯示網頁載入時間的警告視窗</h2>
<hr>

<script>
today = new Date();			// 產生日期物件
hour = today.getHours();		// 取得時數
minute = today.getMinutes();		// 取得分數
second = today.getSeconds();		// 取得秒數
string = "網頁載入時間是"+hour+"點"+minute+"分"+second+"秒";	// 連接字串
</script>
<a href="javascript:alert(string)">網頁載入時間</a>

<hr>
</body>
</html>
/*}}}*/
<<toBalaAjax "ajax\AjaxCall.htm" "儲存網頁 : ajax\AjaxCall.htm" "" "700" "450">>
/*{{{*/
<!-- 
程式名稱 : AjaxCall.html
程式描述 : Call XMLHTTP Object
適用瀏覽器 : Firefox 2.0,IE 5.5
參考文件 : 
-->
<html>
	
<head>
	
<meta http-equiv="Expires" content="0">
<meta http-equiv="Content-Type" content="text/html; charset=utf8">

<script>
var xmlhttp
function show(){
 
 if (window.XMLHttpRequest) {
    netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead");
    xmlhttp = new XMLHttpRequest();    
 }
 else if (window.ActiveXObject){ 
    try {
          xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
         }
    catch (e){
      try{
         xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
        }
      catch (e){}
    }
 }

 xmlhttp.open(document.getElementById("c").value,document.getElementById("u").value,false);
 xmlhttp.send("");
 if (parseInt(xmlhttp.status)>300){
     alert(xmlhttp.status);
 }
 else {
  document.getElementById("h").innerHTML=xmlhttp.getAllResponseHeaders();
  
  if (xmlhttp.getResponseHeader("Content-Type") == "text/xml"){
  	 xmlobj=xmlhttp.responseXML;
     document.getElementById("x").innerHTML=xmlobj.getElementsByTagName('app')[0].firstChild.nodeValue;
  }
  else{
  	 document.getElementById("x").innerHTML="";
     var testFrame = document.getElementById("myFrame");
     var doc = testFrame.contentDocument;
     if (doc == undefined || doc == null)
        doc = testFrame.contentWindow.document;
     doc.open();
     doc.write(xmlhttp.responseText);
	 doc.close(); 
  }  
 }
}
</script>
</head>

<style type="text/css">
body {
 background-color:white;
}
</style>

<body>
<h2>Ajax 測試程式 (使用本機的瀏覽器以 "開啟檔案" 方式執行)</h2>
<hr>
Method: <input id="c" value="GET" style="width: 100px;" type="text"><span> (要大寫) </span><br> 
URL: <input style="width: 250px;" id="u" value="http://" type="text"><br>

<button onclick="show();">傳送命令</button>
<hr>

<b>Response Header</b>
<pre id="h"></pre>

<b>Response XML</b>
<pre id="x"></pre>

<b>Response HTML</b><br>
<iframe id="myFrame" height="30%" width="100%"></iframe>

</body>
</html>

<!--
HTTP Methods
-------------
HTTP defines eight methods (sometimes referred to as "verbs") indicating the desired 
action to be performed on the identified resource.

HEAD
    Asks for the response identical to the one that would correspond to a GET request, 
    but without the response body. This is useful for retrieving meta-information 
	written in response headers, without having to transport the entire content.
GET
    Requests a representation of the specified resource. By far the most common method
	used on the Web today. Should not be used for operations that cause side-effects 
	(using it for actions in web applications is a common mis-use). See 'safe methods' 
	below.
POST
    Submits data to be processed (e.g. from an HTML form) to the identified resource. 
	The data is included in the body of the request. This may result in the creation 
	of a new resource or the updates of existing resources or both.
PUT
    Uploads a representation of the specified resource.
DELETE
    Deletes the specified resource.
TRACE
    Echoes back the received request, so that a client can see what intermediate 
	servers are adding or changing in the request.
OPTIONS
    Returns the HTTP methods that the server supports. This can be used to check the 
	functionality of a web server.
CONNECT
    For use with a proxy that can change to being an SSL tunnel.


WebDAV added the following methods to HTTP:

    * PROPFIND — Used to retrieve properties, persisted as XML, from a resource. 
	             It is also overloaded to allow one to retrieve the collection 
				 structure (a.k.a. directory hierarchy) of a remote system.
    * PROPPATCH — Used to change and delete multiple properties on a resource 
	              in a single atomic act.
    * MKCOL — Used to create collections (a.k.a. directory).
    * COPY — Used to copy a resource from one URI to another.
    * MOVE — Used to move a resource from one URI to another.
    * LOCK — Used to put a lock on a resource. WebDAV supports both shared and 
	         exclusive locks.
    * UNLOCK — To remove a lock from a resource.

-->
/*}}}*/
config.options.chkAutoSave=false;
config.options.chkSaveBackups=false;
config.options.txtUserName="比目魚";
config.options.txtMaxEditRows=25;
config.options.chkHttpReadOnly=true;

config.options.chkHideTabsBarWhenSingleTab=true;

config.options.chkDisableWikiLinks=true;
config.options.chkAllowLinksFromShadowTiddlers=true;
config.options.chkDisableNonExistingWikiLinks=true;
/***
|''巨集名稱:''|toBalaFile|
|''版本:''|1.0 (2008-03-18)|
|''原始檔:''||
|''作者:''|S L CHEN|
|''授權:''|BSD|
|''倚賴''||
|''TiddlyWiki 適用版本''|2.3+|
|''適用瀏覽器''|Firefox 1.5+, IE 6.0+|
|''使用語法''||
***/

//{{{
config.macros.toBalaFile={
	
	editLabel: "編輯",
	editTip: "編輯",
        saveLabel: "儲存",
	saveTip: "儲存",
        cancelLabel: "取消",
	cancelTip: "取消",
    
	GUIEditButtonOnclick: function(e,xtiddler,xbox,xfname,xx,yy) {

            if (config.browser.isIE) {
               window.event.cancelBubble=true;
            } else {  
               e.cancelBubble = true;   
               if (e.stopPropagation)  
                  e.stopPropagation();
            }

            removeChildren(xbox);

            var boxtool = createTiddlyElement(xbox,"div",null,"toBalaFileToolBar",null,null);
            var boxtext = createTiddlyElement(xbox,"textarea",null,null,null,null);
            wikify("@@color:#841;border:2px dotted #841;padding:2px;檔案 : <nowiki>"+xfname+"</nowiki>@@ ",boxtool);

            createTiddlyButton(boxtool,this.saveLabel,this.saveTip,
                            function(e) { config.macros.toBalaFile.GUISaveButtonOnclick(e,xtiddler,xbox,xfname,boxtext,xx,yy); },
                            "toBalaFileSave",null,null);
	    createTiddlyButton(boxtool,this.cancelLabel,this.cancelTip,
                            function(e) { config.macros.toBalaFile.GUICancelButtonOnclick(e,xtiddler,xbox,xfname,xx,yy); },
                            "toBalaFileCancel",null,null);

            // alert(xtitle+":"+xx+":"+yy);
            boxtext.setAttribute("rows",20);
            boxtext.setAttribute("cols",88);
            boxtext.value = xtiddler.text.substring(xx,yy);
        },

	GUISaveButtonOnclick: function(e,xtiddler1,xbox1,xfname1,boxtext1,xx1,yy1) {

            if (config.browser.isIE) {
               window.event.cancelBubble=true;
            } else {  
               e.cancelBubble = true;   
               if (e.stopPropagation)  
                  e.stopPropagation();
            }
 
            removeChildren(xbox1);
            var xtext=boxtext1.value;
            if (config.browser.isIE) {              
               xtext=xtext.replace(/\r/g,"");   // 請看最後的註解
            }
            var toptext=xtiddler1.text.substring(0,xx1);
            var bottomtext=xtiddler1.text.substring(yy1);
            xtiddler1.text=toptext+xtext+"\n"+bottomtext;

            story.refreshTiddler(xtiddler1.title,null,true);
            saveChanges(false);              // 參數 false, 代表不管 Dirty 與否, 均要執行存檔動作

            var baseDIR = getLocalPath(document.URL);
  
            if (config.browser.isWindows) {
                var baseDIR = baseDIR.replace(/\//g,"");
                var x = baseDIR.lastIndexOf("\\");
             } else {
                var x = baseDIR.lastIndexOf("/");
             }

            baseDIR = baseDIR.substr(0,x+1);

            var s = saveFile(baseDIR+ (config.browser.isWindows ? xfname1 : xfname1.replace(/\\/g,"\/")), 
                                          convertUnicodeToUTF8(boxtext1.value));
            if (!s) {
               alert("存檔失敗");
            }
        },

	GUICancelButtonOnclick: function(e,xtiddler1,xbox1,xfname1,xx1,yy1) {

            if (config.browser.isIE) {
               window.event.cancelBubble=true;
            } else {  
               e.cancelBubble = true;   
               if (e.stopPropagation)  
                  e.stopPropagation();
            }

            removeChildren(xbox1);

            var boxtool = createTiddlyElement(xbox1,"div",null,"toBalaFileToolBar",null,null);
            wikify("@@color:#841;border:2px dotted #841;padding:2px;檔案 : <nowiki>"+xfname1+"</nowiki>@@ ",boxtool);

	    createTiddlyButton(boxtool,this.editLabel,this.editTip,
                            function(e) { config.macros.toBalaFile.GUIEditButtonOnclick(e,xtiddler1,xbox1,xfname1,xx1,yy1);},
                            "toBalaFileEdit",null,null);

             var boxarea = createTiddlyElement(xbox1,"div",null,null,null,null);
	     wikify("{{{\n"+xtiddler1.text.substring(xx1,yy1)+"\n}}}",boxarea);
        },

	handler : function(place,macroName,params,wikifier,paramString,tiddler){

                if (!params[0]) {
                  alert("請給檔名");
                  return;
                } 

		var xtext=store.getTiddlerText(tiddler.title);
                var x1=xtext.indexOf("/"+"/"+"/"+"%" + params[0]);

                // 自動產生 TiddlyWiki 備註
                if (x1 == -1) { 
                   xtext=xtext+"\n\n/"+"/"+"/"+"%" + params[0] + "\n" + "/"+"/"+"%"+"/";
                   tiddler.text=xtext; 
                   story.refreshTiddler(tiddler.title,null,true);
                   saveChanges(false);
                   return;
                 }
                var x2=xtext.indexOf("/"+"/"+"%"+"/",x1);
                x1=x1+params[0].length+5;

		var box = createTiddlyElement(place,"div",tiddler.title+"-"+x1,"toBalaFile",null,null);
                var boxtool = createTiddlyElement(box,"div",null,"toBalaFileToolBar",null,null);
                wikify("@@color:#841;border:2px dotted #841;padding:2px;檔案 : <nowiki>"+params[0]+"</nowiki>@@ ",boxtool);

                var boxtext = createTiddlyElement(box,"div",null,null,null,null);
		wikify("{{{\n"+xtext.substring(x1,x2)+"\n}}}",boxtext);

                if (readOnly) {
                   return;
                }
		createTiddlyButton(boxtool,this.editLabel,this.editTip,
                            function(e) { config.macros.toBalaFile.GUIEditButtonOnclick(e,tiddler,box,params[0],x1,x2);},
                            "toBalaFileEdit",null,null);
	}		
};

/*
HTML 的 textarea 標籤, 對於換行在不同的瀏覽器有不同的處理方式

As you may know, the humble line break actually has three forms depending on which operating system is doing the breaking. On Unix machines, a single newline character ‘\n’ does the job. On Macs, a carriage return ‘\r’ is used. DOS and Windows use both: ‘\r\n’. It’s one of those relatively subtle issues that can bite you hard if you don’t know what to look out for.
*/

//}}}
!說明
{{{

<<toBalaFile "檔名">>

}}}
!範例
<<toBalaFile "xml\abc.xml">>


///%xml\abc.xml
<?xml version='1.0'?>
<root>
  <marble color="red"/>
  <marble color='red'/>
</root> 
//%/
/***
|''巨集名稱:''|toBalaFlashPlayer|
|''版本:''|1.0 (2008-03-06)|
|''原始檔:''||
|''作者:''|S L CHEN|
|''授權:''|BSD|
|''倚賴''||
|''TiddlyWiki 適用版本''|2.3+|
|''適用瀏覽器''|Firefox 1.5+, IE 6.0+|
|''使用語法''| |
***/
//{{{
config.macros.toBalaFlashPlayer = {};

config.macros.toBalaFlashPlayer.handler = function(place,macroName,params,wikifier,paramString,tiddler){

  var xname = params[0] || tiddler.title;
  var label = params[1] || "撥放 " + xname;
  var xwidth = params[2] || 600;
  var xheight = params[3] || 450;

  createTiddlyButton(place, label, label,
       function(e) { config.macros.toBalaFlashPlayer.show(e, xname, xwidth, xheight); },
       null, null, null);
}

config.macros.toBalaFlashPlayer.show = function(ev,fname,xw,xh) {

  if (config.browser.isIE) {
     window.event.cancelBubble=true;
  } else {  
     ev.cancelBubble = true;   
     if (ev.stopPropagation)  
        ev.stopPropagation();
  }

  if (config.browser.isIE)
     var URLtext = document.URL.replace(/\\/g,"\/");
  else 
     var URLtext = document.URL;
  //alert(URLtext);

  var x = URLtext.lastIndexOf("/");
  var baseDIR = URLtext.substr(0,x);
  var jsDIR = '<script type="text/javascript" src="' + baseDIR + '/jslib/swfobject/swfobject.js"></script>'
  //alert(jsDIR);

  var generator=window.open('','name','height=' + xh +',width=' + xw);
  generator.document.open();
  generator.document.write('<html><head><title>toBala Flash Player</title>');
  generator.document.write(jsDIR);
  generator.document.write('</head><body>');
  generator.document.write('<div id="flashTag" style="width:'+(xw-5)+'px;height:'+(xh-5)+'px;overflow:auto"></div>');
  generator.document.write('<script type="text/javascript">');
  generator.document.write('var xo = new SWFObject("' + baseDIR + '/' + fname + '","mymovie","'+(xw-5)+'","'+(xh-5)+'","8", "#336699");');
  //generator.document.write('xo.addParam("wmode", "transparent");');
  generator.document.write('xo.write("flashTag");');
  generator.document.write('</script>');
  generator.document.write('</body></html>');
  generator.document.close();

}
//}}}
使用 toBalaFlashPlayer 巨集, 來撥放指定的 Flash 檔, 命令格式如下 :
{{{
<<toBalaFlashPlayer "movie/infotree.swf" "" "820" "610">>
}}}

!實作

<<toBalaFlashPlayer "movie/infotree.swf" "" "820" "610">>

/***
|''巨集名稱:''|toBalaHTML|
|''版本:''|1.0 (2008-03-18)|
|''原始檔:''||
|''作者:''|S L CHEN|
|''授權:''|BSD|
|''倚賴''||
|''TiddlyWiki 適用版本''|2.3+|
|''適用瀏覽器''|Firefox 1.5+, IE 6.0+|
|''使用語法''|&lt;&lt;toBalaHTML  title  filename  label  tooltip  width  height&gt;&gt; |
***/

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

config.macros.toBalaHTML.handler = function(place,macroName,params,wikifier,paramString,tiddler){

  var title = params[0] || tiddler.title;
  var xfname = params[1] || "";          // 外部檔名
  var label = params[2] || "測試網頁";
  var tooltip = params[3] || "開啟另一個視窗, 檢視網頁";
  var xwidth = params[4] || 550;
  var xheight = params[5] || 400;

  createTiddlyButton(place, label, tooltip,
       function(e) { config.macros.toBalaHTML.show(e,title,xfname,xwidth,xheight); },
       null, null, null);
}

config.macros.toBalaHTML.show = function(ev,xtitle,xf,xw,xh) {

  if (config.browser.isIE) {
     window.event.cancelBubble=true;
  } else {  
     ev.cancelBubble=true;   
     if (ev.stopPropagation)  
        ev.stopPropagation();
  }

  // 將視窗置中
  var winl = (screen.width-xw)/2;
  var wint = (screen.height-xh)/2;
  if (winl < 0) winl = 0;
  if (wint < 0) wint = 0;
  var settings = 'height='  + xh +  ', width=' + xw  + ',top='  + wint  + ',left='  + winl;

  if (xf != "") {

     xf=xf.replace(/\\/mg,"/");

     // alert(xf+":"+settings);
     var xwin=window.open(xf,"HTMLWIN",settings);
     xwin.window.focus();

  } else {
    // alert(store.getTiddlerText(xtitle));
    xtext=store.getTiddlerText(xtitle);

    x1=xtext.indexOf("/*{{{*/");
    x2=xtext.indexOf("/*}}}*/");
    // alert(xtext.substring(x1+8,x2));
    xtext = xtext.substring(x1+8,x2);

    var xwin=window.open('','',settings);
    xwin.document.open();
    xwin.document.write(xtext);
    xwin.document.close();
  }
}
/*
window.open() 參數
----------------------------------------------
* width:定義新視窗的寬度。
* height:定義新視窗的高度。
* resizable:能否讓用戶調整視窗大小,可能的設定值為:yes或no(或者1與0)。
* menubar:是否要顯示主功能表,可能的設定值為:yes或no。
* toolbar:是否要顯示「標準按鈕」工具列,可能的設定值為:yes或no。
* location:是否要顯示網址欄位,可能的設定值為:yes或no。
* scrollbars:能否顯示捲軸,可能的設定值為:yes或no。
* status:是否要呈現狀態列,可能的設定值為:yes或no。
* directories:是否要呈現額外的按鈕(例如:「連結」列,以及「標準按鈕」以外的其他按鈕),可能的設定值為:yes或no。
* copyhistory:是否要複製原有瀏覽器視窗的瀏覽歷程(history),可能的設定值為:yes或no。
* fullscreen:是否要以全螢幕方式開啟新視窗(適用於IE瀏覽器),可能的設定值為:yes或no。
*/
//}}}
<<toBalaHTML "" "ajax/html/e4x.htm" "網頁測試 : ajax/html/e4x.htm">><<toBalaFile "ajax\html\e4x.htm">>

///%ajax\html\e4x.htm
<html>
<script type="text/javascript;e4x=1">
      myquestion = <question>          
      <display>Is it animal, vegetable, or mineral?</display>              
      <answerOption>Animal</answerOption>
      <answerOption>Vegetable</answerOption>
      <answerOption>Mineral</answerOption>
      </question>;
      alert("The question is '" + myquestion.display + "'");             
</script>
</html>
//%/
這範例程式可在 IE, Firefox, Opera  等瀏覽器中執行

<<toBalaHTML "" "ajax\html\contentEditableFF.htm">><<toBalaFile "ajax\html\contentEditableFF.htm">>

///%ajax\html\contentEditableFF.htm
<body>
<iFrame id="jia" src="about:blank"></iFrame>  
<script>  
  // window.onload   =   function(){  
  var jia = document.getElementById("jia");  
  jia.contentWindow.document.designMode="on";  
  jia.contentWindow.document.contentEditable=true;  
  jia.contentWindow.document.open();  
  jia.contentWindow.document.write("<html><head></head><body></body></html>");  
  jia.contentWindow.document.close();  
  // }  
</script>
</body>
//%/
必須關閉瀏覽器 [阻檔 POPUP 視窗] 功能, 以下程式才能執行

<<toBalaHTML "" "ajax\html\popup.htm">><<toBalaFile "ajax\html\popup.htm">>


///%ajax\html\popup.htm
<html>
<head>
<script type="text/javascript">
function show_popup()
{
   var p=window.createPopup();
   var pbody=p.document.body;
   pbody.style.backgroundColor="lime";
   pbody.style.border="solid black 1px";
   pbody.innerHTML="This is a pop-up! Click outside to close.";
   p.show(150,150,200,50,document.body);
}
</script>
</head>

<body>
<button onclick="show_popup()">Create pop-up!</button>
</body>

</html>
//%/
/***
|''巨集名稱:''|toBalaJava|
|''版本:''|1.0 (2008-04-01)|
|''原始檔:''||
|''作者:''|S L CHEN|
|''授權:''|BSD|
|''倚賴''|toBalaRun|
|''TiddlyWiki 適用版本''|2.3+|
|''適用瀏覽器''|Firefox 1.5+, IE 6.0+|
|''使用語法''|&lt;&lt;toBalaJava  "程式檔名"  "前置編譯參數"  "前置執行參數"  "後置執行參數" "按鈕提示資訊" "按鈕提示資訊"&gt;&gt; |
***/

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

config.macros.toBalaJava.handler = function(place,macroName,params,wikifier,paramString,tiddler){

  if (readOnly) {
     return;
  }

  if (!params[0].match(".java")) {
     alert("請給檔名或副檔名錯誤");
     return;
  }

  // 程式檔名
  var xfname = params[0]; 

  // 前置編譯參數 
  var cprearg = params[1] || "";

  // 前置執行參數 
  var eprearg = params[2] || "";

  // 後置執行參數 
  var postarg = params[3] || "";

  var cargs = (cprearg=="" ? "":cprearg+" ") + xfname;
  //alert(cargs);

  var p = xfname.indexOf(".java");
  yfname=xfname.substring(0,p);
  p=yfname.lastIndexOf("\\");
  yfname=yfname.substring(p+1,yfname.length);

  var rargs = (eprearg==""?"":eprearg+" ") + yfname + (postarg==""?"":" "+postarg);
  //alert(rargs);

  // 按鈕提示資訊
  var clabel = params[4] || "翻譯程式 :" + xfname;
  var rlabel = params[5] || "執行程式 :" + yfname;

  // 翻譯程式
  createTiddlyButton(place, clabel, clabel,
       function(e) { config.macros.toBalaRun.cmd(e,"tbjavac.exe",cargs,"yes"); },
       null, null, null);

  // 執行程式
  createTiddlyButton(place, rlabel, rlabel,
       function(e) { config.macros.toBalaRun.cmd(e,"tbjava.exe",rargs,"yes"); },
       null, null, null);
}
//}}}
!程式範例 

{{{
使用 toBalaFile 巨集, 編輯及儲存 Java 程式, 命令格式如下 :

<<toBalaFile "java\hello.java">>
}}}

<<toBalaFile "java\hello.java">>
----
{{{
使用 toBalaJava 巨集, 編譯及執行 Java 程式, 命令格式如下 :

<<toBalaJava "java\hello.java" "" "">>
}}}

<<toBalaJava "java\hello.java" "" "">>


!程式範例 : 輸入 [編譯] 及 [執行] 參數

<<toBalaFile "java\assertion.java">>
----
{{{
使用 toBalaJava 巨集, 編譯及執行 Java 程式, 命令格式如下 :
<<toBalaJava "java\assertion.java" "-source 1.4" "-ea">>

"-source 1.4" 是編譯參數
"-ea" 是執行參數

}}}

<<toBalaJava "java\assertion.java" "-source 1.4" "-ea">>


///%java\hello.java
public class hello {
  public static void main(String[] args){
     System.out.println("大家好好");
  }
}
//%/

///%java\assertion.java
class assertion {
  public static void main(String[] args){
    int i=-11;
    if (i%3==0) 
      { System.out.println("0"); }
    else if (i%3==1) 
      { System.out.println("1"); }
    else {
      assert((i%3)==2):i;
    }
  }
}
//%/
{{{
if (!window.toBala) window.toBala = {};

toBala.showMsg = function(msg,xw,xh) {
      var winl = (screen.width-xw)/2;
      var wint = (screen.height-xh)/2;
      if (winl < 0) winl = 0;
      if (wint < 0) wint = 0;
      var settings = 'height='  + xh +  ', width=' + xw  + ',top='  + wint  + ',left='  + winl;
      var xwin=window.open("","",settings);
      xwin.document.open();
      xwin.document.write(msg);
      xwin.document.close();
      return xwin;
};
}}}
/***
|''巨集名稱:''|toBalaManager|
|''版本:''|1.0 (2008-05-05)|
|''原始檔:''||
|''作者:''|S L CHEN|
|''授權:''|BSD|
|''倚賴''||
|''~TiddlyWiki 適用版本''|2.3+|
|''適用瀏覽器''|Firefox 1.5+, IE 6.0+|
|''使用語法''||
***/
//{{{
config.macros.toBalaManager={
	preText: "",
	save: function(e,ytiddler,yform) {
            //for (var i=0,str="";i<yform.elements.length;++i){
            //  str=str+yform.elements[i].type+":"+yform.elements[i].tagName+":"+yform.elements[i].value;
            //}
            //alert(str);  
      
            // 設定主標題
            var xt = store.getTiddler("SiteTitle");  
            xt.text=  yform.elements[0].value;

            // 設定次標題
            var xt = store.getTiddler("SiteSubtitle");  
            xt.text=  yform.elements[1].value;

            // 設定 MainMenu
            var xt = store.getTiddler("MainMenu");  
            xt.text=  yform.elements[2].value;

            // 設定 ToolBar
            var xt = store.getTiddler("ToolBar");  
            xt.text=  yform.elements[3].value;

            // 備份 SiteTitle, SiteSubtitle, ToolBar, MainMenu  
            ytiddler.text=preText; 
            saveChanges(false);   // 參數 false, 代表不管 Dirty 與否, 均要執行存檔動作
        },

	handler : function(place,macroName,params,wikifier,paramString,tiddler){

                if (readOnly) {
                   return;
                }

		createTiddlyButton(place,"儲存","儲存",
                          function(e) { config.macros.toBalaManager.save(e,tiddler,xform); },
                          "toBalaManagerSave",null,null);

		var xform = createTiddlyElement(place,"form",tiddler.title+"-form","toBalaManager",null,null);
                // 讀取主標題
                var xlabel1 = createTiddlyElement(xform,"label",null,"",null,null);
		wikify("''主標題 (~SiteTitle) :  ''",xlabel1);
                var xtitle1 = createTiddlyElement(xform,"input",null,"xManagerMT",null,null);
                var xt = store.getTiddler("SiteTitle");   
		xtitle1.value=xt.text;
		wikify("\n\n",xform);

                // 讀取次標題
                var xlabel2 = createTiddlyElement(xform,"label",null,"",null,null);
                wikify("''次標題 (~SiteSubtitle) :  ''",xlabel2);
                var xtitle2 = createTiddlyElement(xform,"input",null,"xManagerST",null,null);
                var xt = store.getTiddler("SiteSubtitle");   
		xtitle2.value=xt.text;
		wikify("\n\n",xform);

                // 讀取 MainMenu
                var xlabel4 = createTiddlyElement(xform,"label",null,"",null,null);
                wikify("''資訊樹 (TagsTree)''",xlabel4);
		wikify("\n",xform);
                var xmm = createTiddlyElement(xform,"textarea",null,"xManagerMM",null,null);
                var xt = store.getTiddler("MainMenu");   
                xmm.value=xt.text;
		wikify("\n\n",xform);

                // 讀取 ToolBar
                var xlabel3 = createTiddlyElement(xform,"label",null,"",null,null);
                wikify("''工具列 (~ToolBar)''",xlabel3);
		wikify("\n",xform);
                var xtb = createTiddlyElement(xform,"textarea",null,"xManagerTB",null,null);
                var xt = store.getTiddler("ToolBar");   
                xtb.value=xt.text;
		wikify("\n\n",xform);

                // 備份 SiteTitle, SiteSubtitle, ToolBar, MainMenu
	        var xtext=store.getTiddlerText(tiddler.title);
                var x1 = xtext.indexOf("/"+"/"+"/"+"%");
                xtext = ( x1 == -1 ? xtext : xtext.substring(0,x1) );

                preText=xtext+"\n\n/"+"/"+"/"+"%" ;
                preText=preText+"\n\n"+xtitle1.value;
                preText=preText+"\n\n"+xtitle2.value;
                preText=preText+"\n\n"+xmm.value;
                preText=preText+"\n\n"+xtb.value;
                preText=preText+"\n" + "/"+"/"+"%"+"/";

	}		
};

setStylesheet(".toBalaManager {background:#eee; font-size:12px;border:1px solid #ccc; padding:2px; margin:5px;}\n"+
".xManagerMT {width:550px;height:25px;}\n" +
".xManagerST {width:550px;height:25px;}\n" +
".xManagerTB {width:680px;height:150px;}\n" +
".xManagerMM {width:680px;height:250px;}\n" +
".toBalaManagerSave {border:1px solid #ccc;font-size:14px;padding:2px;margin-left:4px;margin-bottom:2px;}\n" ,
"toBalaManagerStyles");
//}}}
/***
|''巨集名稱:''|toBalaNotes|
|''版本:''|1.0 (2008-03-18)|
|''原始檔:''||
|''作者:''|S L CHEN|
|''授權:''|BSD|
|''倚賴''||
|''TiddlyWiki 適用版本''|2.3+|
|''適用瀏覽器''|Firefox 1.5+, IE 6.0+|
|''使用語法''||
***/

//{{{
config.macros.toBalaNotes={
	
	editLabel: "編輯",
	editTip: "編輯",
        saveLabel: "儲存",
	saveTip: "儲存",
        cancelLabel: "取消",
	cancelTip: "取消",
        heading: "@@font-size:12px;color:#841;註解@@",
    
	GUIEditButtonOnclick: function(e,xtiddler,xbox,xx,yy) {
            removeChildren(xbox);

            var boxtool = createTiddlyElement(xbox,"div",null,"toBalaNotesToolBar",null,null);
            var boxtext = createTiddlyElement(xbox,"textarea",null,null,null,null);
	    wikify(this.heading+" : ",boxtool);

            createTiddlyButton(boxtool,this.saveLabel,this.saveTip,
                            function(e) { config.macros.toBalaNotes.GUISaveButtonOnclick(e,xtiddler,xbox,boxtext,xx,yy); },
                            "toBalaNotesSave",null,null);
	    createTiddlyButton(boxtool,this.cancelLabel,this.cancelTip,
                            function(e) { config.macros.toBalaNotes.GUICancelButtonOnclick(e,xtiddler,xbox,xx,yy); },
                            "toBalaNotesCancel",null,null);

            // alert(xtitle+":"+xx+":"+yy);
            boxtext.setAttribute("rows",15);
            boxtext.setAttribute("cols",88);
            boxtext.value = xtiddler.text.substring(xx,yy);
        },

	GUISaveButtonOnclick: function(e,xtiddler1,xbox1,boxtext1,xx1,yy1) {
            removeChildren(xbox1);
            toptext=xtiddler1.text.substring(0,xx1);
            bottomtext=xtiddler1.text.substring(yy1);
            xtiddler1.text=toptext+boxtext1.value+bottomtext;
            story.refreshTiddler(xtiddler1.title,null,true);
            saveChanges(false);   // 參數 false, 代表不管 Dirty 與否, 均要執行存檔動作
        },

	GUICancelButtonOnclick: function(e,xtiddler1,xbox1,xx1,yy1) {
            removeChildren(xbox1);

            var boxtool = createTiddlyElement(xbox1,"div",null,"toBalaNotesToolBar",null,null);
	    wikify(this.heading+" : ",boxtool);

	    createTiddlyButton(boxtool,this.editLabel,this.editTip,
                            function(e) { config.macros.toBalaNotes.GUIEditButtonOnclick(e,xtiddler1,xbox1,xx1,yy1);},
                            "toBalaNotesEdit",null,null);

             var boxarea = createTiddlyElement(xbox1,"div",null,null,null,null);
	     wikify(xtiddler1.text.substring(xx1,yy1),boxarea);
        },

	handler : function(place,macroName,params,wikifier,paramString,tiddler){

		var xtext=store.getTiddlerText(tiddler.title);
                var x1=xtext.indexOf("/"+"/"+"/"+"%" + params[0]);

                // 自動產生 TiddlyWiki 備註
                if (x1 == -1) { 
                   xtext=xtext+"\n\n/"+"/"+"/"+"%" + params[0] + "\n" + "/"+"/"+"%"+"/";
                   tiddler.text=xtext; 
                   story.refreshTiddler(tiddler.title,null,true);
                   saveChanges(false);     // 參數 false, 代表不管 Dirty 與否, 均要執行存檔動作
                   clearMessage();
                   return;
                 }
                var x2=xtext.indexOf("/"+"/"+"%"+"/",x1);
                x1=x1+params[0].length+5;

		var box = createTiddlyElement(place,"div",tiddler.title+"-"+x1,"toBalaNotes",null,null);
                var boxtool = createTiddlyElement(box,"div",null,"toBalaNotesToolBar",null,null);
		wikify(this.heading+" : ",boxtool);

                var boxtext = createTiddlyElement(box,"div",null,null,null,null);
		wikify(xtext.substring(x1,x2),boxtext);

                if (readOnly) {
                   return;
                }

		createTiddlyButton(boxtool,this.editLabel,this.editTip,
                            function(e) { config.macros.toBalaNotes.GUIEditButtonOnclick(e,tiddler,box,x1,x2);},
                            "toBalaNotesEdit",null,null);
	}		
};

setStylesheet(".toBalaNotes {background:#eee; border:1px solid #ccc; padding:2px; margin:5px;}\n"+
".toBalaNotesEdit {border:1px solid #ccc;padding:2px;margin-top:2px;margin-bottom:2px;}\n" +
".toBalaNotesCancel {border:1px solid #ccc;padding:2px;margin-top:2px;margin-right:2px;margin-bottom:2px;}\n" +
".toBalaNotesToolBar {border-bottom: 2px dotted #556b2f;padding:1px 0px 5px 0px;margin:1px;}\n" +
".toBalaNotesSave {border:1px solid #ccc;padding:2px;margin-top:2px;margin-right:2px;margin-bottom:2px;}\n",
"toBalaNotesStyles");
//}}}
/***
|''巨集名稱:''|toBalaRun|
|''版本:''|1.0 (2008-04-01)|
|''原始檔:''||
|''作者:''|S L CHEN|
|''授權:''|BSD|
|''倚賴''||
|''TiddlyWiki 適用版本''|2.3+|
|''適用瀏覽器''|Firefox 1.5+, IE 6.0+|
|''使用語法''| |
***/

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

  if (readOnly) {
     return;
  }

  if (!params[0]) {
     alert("請給檔名");
     return;
  }
  var fname = params[0];                //  執行檔名
  var varg = params[1] || "";             //  執行參數
  var label = params[2] || "執行 : "+fname + " " + varg;
  var tooltip = params[3] || "執行檔名 : "+fname + " " + varg;
  var result = params[4] || "yes";

  window.status="";
  createTiddlyButton(place, label, tooltip,
       function(e) { config.macros.toBalaRun.cmd(e,fname,varg,result); },
       null, null, null);
}

config.macros.toBalaRun.cmd = function(ev,xfname,xarg,xresult) {

  if (!xfname.match(".bat")) {
      //var xwin = toBala.showMsg("<h1>執行中, 請稍後</h1>",250,50);
      window.status = xfname + " " + xarg + " 執行中, 請稍後";
  }

  if (config.browser.isIE) {
     window.event.cancelBubble=true;
  } else {  
     ev.cancelBubble = true;   
     if (ev.stopPropagation)  
        ev.stopPropagation();
  }

  var baseDIR = getLocalPath(document.URL);
  //alert(baseDIR);

   if (config.browser.isWindows) {
      var baseDIR = baseDIR.replace(/\//g,"");
      var x = baseDIR.lastIndexOf("\\");
      xfname = "\\" + xfname.replace(/\//g,"\\");
      xarg = xarg.replace(/\//g,"\\");
   } else {
      var x = baseDIR.lastIndexOf("/");
      xfname = "/" + xfname.replace(/\\/g,"/");
      xarg = xarg.replace(/\\/g,"/");
   }

   baseDIR = baseDIR.substr(0,x);
   //alert(baseDIR);

   if (config.browser.isIE) {
	var theShell = new ActiveXObject("WScript.Shell");
	if (theShell) {
            var runstr = baseDIR + xfname + " " + xarg;
            // alert(runstr);
	    try {
	        theShell.run(runstr,1, (xresult == "yes" ? true:false));
	    } catch (e) {
                try {          //  執行系統命令
                    var runstr = xfname.substring(1)+ " " + xarg;
                    theShell.run(runstr,1, (xresult == "yes" ? true:false));
                } catch(e) {
                   if (!xfname.match(".bat")) 
                      window.status="";
		   displayMessage("執行失敗 :" + runstr);
		   return;
                }
	    }
	} 
   } else if (config.browser.isGecko) { 
	netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
        var file = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile);

        try {
           var runstr = baseDIR +xfname; 
           // alert(runstr);
           file.initWithPath(runstr);
        }catch (e) {
           if (!xfname.match(".bat")) 
              window.status="";
           displayMessage("執行字串格式錯誤 : " + runstr);
           return;
        }

	try {
	   var process = Components.classes['@mozilla.org/process/util;1'].createInstance(Components.interfaces.nsIProcess);
           var Aargs = xarg.split(" ");
           // alert(Aargs);
           process.init(file);
           process.run((xresult == "yes" ? true:false), Aargs, Aargs.length);
	} catch (e) {
            try {    //  執行系統命令
                runstr=xfname.substring(1);
                file.initWithPath(runstr);
                process.init(file);
                process.run((xresult == "yes" ? true:false), Aargs, Aargs.length);
            } catch (e) {
                if (!xfname.match(".bat")) 
                    window.status="";
	        displayMessage("執行失敗 : " + runstr);
                return;
            }
	}
   }
   // 顯示執行結果
   if ( !xfname.match(".bat") && !xfname.match(".sh") && xresult == "yes") {
      window.status="";
      xf = baseDIR+xfname+".htm"
      // alert(xf);
      var xh = 400;
      var xw = 780;
      var winl = (screen.width-xw)/2;
      var wint = (screen.height-xh)/2;
      if (winl < 0) winl = 0;
      if (wint < 0) wint = 0;
      var settings = 'height='  + xh +  ', width=' + xw  + ',top='  + wint  + ',left='  + winl + ',scrollbars=yes';
      var ywin=window.open("file:///"+xf,"HTMLWIN",settings);
   }
}
//}}}
<<toBalaFile "xml\dtd01.xml">><<toBalaRun "java\jaxp\JAXPDTD.bat" "xml\dtd01.xml" "檢核">>

----

<<toBalaFile "xml\dtd02.xml">><<toBalaRun "java\jaxp\JAXPDTD.bat" "xml\dtd02.xml" "檢核">>


///%xml\dtd01.xml
<?xml version="1.0" encoding="big5"?>
<!DOCTYPE PersonData [
  <!ELEMENT PersonData (name,spouse)>
  <!ELEMENT name (#PCDATA)>
  <!ELEMENT spouse (#PCDATA)>
]>
<PersonData>
    <spouse>Teley</spouse>
    <name>Ryan</name>
</PersonData>
//%/

///%xml\dtd02.xml
<?xml version="1.0"?>
<!DOCTYPE user [
  <!ELEMENT user (name+,e-mail*,title?)>
  <!ELEMENT name (#PCDATA)>
  <!ELEMENT e-mail (#PCDATA)>
  <!ELEMENT title (#PCDATA)>
]>
<user>
  <name>Austin Sours</name>
  <e-mail>xchen@cmt.com.tw</e-mail>
  <e-mail>aaa@x,y,z</e-mail>
</user>
//%/
<<toBalaFile "xml\well01.xml">><<toBalaRun "java\jaxp\JAXPWell.bat" "xml\well01.xml" "檢核">>

----

<<toBalaFile "xml\well02.xml">><<toBalaRun "java\jaxp\JAXPWell.bat" "xml\well02.xml" "檢核">>


///%xml\well01.xml
<root>
  <marble color="red"/>
  <marble color='red'/>
</root>
//%/

///%xml\well02.xml
<first_tag>
  <second_tag>
     <third_tag>Contents of third tag
  </second_tag>
</First_tag>
//%/
<<toBalaFile "xml\stype.xsd">>


<<toBalaFile "xml\stype.xml">><<toBalaRun "java\jaxp\JAXPSchema.bat" "xml\stype.xml xml\stype.xsd" "檢核">>


///%xml\stype.xsd
<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" 
                  targetNamespace="http://xsdtesting">
    <xs:element name="author" type="xs:date"/>
</xs:schema>
//%/

///%xml\stype.xml
<?xml version="1.0"?>
<x:author xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
          xmlns:x="http://xsdtesting"
          xsi:schemaLocation="http://xsdtesting stype.xsd">
123.5
</x:author>
//%/
<<toBalaFile "xml\deftemp.xml">>
DOM Tree
----------------
{{{
       .
       |
       |--- <?xml-stylesheet  type="text/xsl"  .... ?>   
       |--- <root>
                |
                |--- <text>
                |
                |
                |--- <text>
                |
                |
                |--- <!-- abcd --> 

}}}


<<toBalaFile "xml\deftemp.xsl">><<toBalaRun "java\jaxp\JAXPXSLT.bat" "xml\deftemp.xml xml\deftemp.xsl" "轉換">>


///%xml\deftemp.xml
<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="deftemp.xsl"?>
<root>
  <text>
    Roses are <color>red</color>, violets are <color>blue</color>.
  </text>
  <text>
    My <color>green</color> and <color id="xxx">yellow</color> 
    sweater is just the right hue.
    <?name type="bebo"?>
  </text>
  <!-- abcd -->
</root>
//%/

///%xml\deftemp.xsl
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 

<!-- <xsl:template match="*|/">
</xsl:template>  -->

<!-- <xsl:template match="processing-instruction()">
  PI : <xsl:value-of select="."/>
</xsl:template> -->

<!-- <xsl:template match="root"/> -->

</xsl:stylesheet>
//%/
<<toBalaRun "tbzoomit.bat" "" "ZoomIt v1.8" "" "no">>

!~ZoomIt v1.8
By Mark Russinovich
Published: March 10, 2008
網址 : http://technet.microsoft.com/zh-tw/sysinternals/bb897434(en-us).aspx

''Introduction''
~ZoomIt is screen zoom and annotation tool for technical presentations that include application demonstrations. ~ZoomIt runs unobtrusively in the tray and activates with customizable hotkeys to zoom in on an area of the screen, move around while zoomed, and draw on the zoomed image. I wrote ~ZoomIt to fit my specific needs and use it in all my presentations.

~ZoomIt works on all versions of Windows and you can use pen input for ~ZoomIt drawing on tablet ~PCs.

''Using ~ZoomIt''
The first time you run ~ZoomIt it presents a configuration dialog that describes ~ZoomIt's behavior, let's you specify alternate hotkeys for zooming and for entering drawing mode without zooming, and customize the drawing pen color and size. I use the draw-without-zoom option to annotate the screen at its native resolution, for example. ~ZoomIt also includes a break timer feature that remains active even when you tab away from the timer window and allows you to return to the timer window by clicking on the ~ZoomIt tray icon.

!tbzoomit.bat 程式碼
{{{
@echo off

REM 取得這個 Batch File 的目錄
set toBalaPath=%~p0

REM 取得這個 Batch File 的磁碟代號
set toBalaDrv=%~d0

REM 轉換磁碟及目錄
call %toBalaDrv%
cd %toBalaPath%

REM 設定環境變數
REM -----------------
set PATH=.;%cd%\cmdtools;%PATH%
start /B zoomit.exe
exit

}}}
/***
|''巨集名稱:''|toBalaWrite|
|''版本:''|1.0 (2008-04-01)|
|''原始檔:''||
|''作者:''|S L CHEN|
|''授權:''|BSD|
|''倚賴''||
|''TiddlyWiki 適用版本''|2.3+|
|''適用瀏覽器''|Firefox 1.5+, IE 6.0+|
|''使用語法''| |
***/

//{{{
config.macros.toBalaWrite = {};
config.macros.toBalaWrite.handler = function(place, macroName, params, wikifier, paramString, tiddler) {
	var title = params[0];
	if(title == tiddler.title) {
            title = "Error: Can't use the same tiddler from which the macro is called (infinite recursion)!";
            alert(title);
            return;
	}
	var tiddler = store.getTiddler(title);
        var contents = tiddler.text;
	wikify(contents, place);
}
//}}}
/***
|''Name:''|DropDownMenuPlugin|
|''Description:''|Create dropdown menus from unordered lists|
|''Author:''|Saq Imtiaz ( lewcid@gmail.com )|
|''Source:''|http://tw.lewcid.org/#DropDownMenuPlugin|
|''Code Repository:''|http://tw.lewcid.org/svn/plugins|
|''Version:''|2.1|
|''Date:''|11/04/2007|
|''License:''|[[Creative Commons Attribution-ShareAlike 3.0 License|http://creativecommons.org/licenses/by-sa/3.0/]]|
|''~CoreVersion:''|2.2.5|

!!Usage:
* create a two-level unordered list using wiki syntax, and place {{{<<dropMenu>>}}} on the line after it.
* to create a vertical menu use {{{<<dropMenu vertical>>}}} instead.
* to assign custom classes to the list, just pass them as parameters to the macro {{{<<dropMenu className1 className2 className3>>}}}

!!Features:
*Supports just a single level of drop-downs, as anything more usually provides a poor experience for the user.
* Very light weight, about 1.5kb of JavaScript and 4kb of CSS.
* Comes with two built in css 'themes', the default horizontal and vertical. 

!!Customizing:
* to customize the appearance of the menu's, you can either add a custom class as described above or, you can edit the CSS via the StyleSheetDropDownMenu shadow tiddler.


***/
// /%
//!BEGIN-PLUGIN-CODE
config.macros.dropMenu={

	dropdownchar: "\u25bc",

	handler : function(place,macroName,params,wikifier,paramString,tiddler){
		list = findRelated(place.lastChild,"UL","tagName","previousSibling");
		if (!list)
			return;
		addClass(list,"suckerfish");
		if (params.length){
			addClass(list,paramString);
		}
		this.fixLinks(list);
	},
	
	fixLinks : function(el){
		var els = el.getElementsByTagName("li");
		for(var i = 0; i < els.length; i++) {
			if(els[i].getElementsByTagName("ul").length>0){
				var link = findRelated(els[i].firstChild,"A","tagName","nextSibling");
				if(!link){
					var ih = els[i].firstChild.data;
					els[i].removeChild(els[i].firstChild);
					var d = createTiddlyElement(null,"a",null,null,ih+this.dropdownchar,{href:"javascript:;"});
					els[i].insertBefore(d,els[i].firstChild);
				}
				else{
					link.firstChild.data = link.firstChild.data + this.dropdownchar;
					removeClass(link,"tiddlyLinkNonExisting");
				}
			}
			els[i].onmouseover = function() {
				addClass(this, "sfhover");
			};
			els[i].onmouseout = function() {
				removeClass(this, "sfhover");
			};
		}
	}	
};

config.shadowTiddlers["StyleSheetDropDownMenuPlugin"] = 
	 "/*{{{*/\n"+
	 "/***** LAYOUT STYLES -  DO NOT EDIT! *****/\n"+
	 "ul.suckerfish, ul.suckerfish ul {\n"+
	 "	margin: 0;\n"+
	 "	padding: 0;\n"+
	 "	list-style: none;\n"+
	 "	line-height:1.4em;\n"+
	 "}\n\n"+
	 "ul.suckerfish  li {\n"+
	 "	display: inline-block; \n"+
	 "	display: block;\n"+
	 "	float: left; \n"+
	 "}\n\n"+
	 "ul.suckerfish li ul {\n"+
	 "	position: absolute;\n"+
	 "	left: -999em;\n"+
	 "}\n\n"+
	 "ul.suckerfish li:hover ul, ul.suckerfish li.sfhover ul {\n"+
	 "	left: auto;\n"+
	 "}\n\n"+
	 "ul.suckerfish ul li {\n"+
	 "	float: none;\n"+
	 "	border-right: 0;\n"+
	 "	border-left:0;\n"+
	 "}\n\n"+
	 "ul.suckerfish a, ul.suckerfish a:hover {\n"+
	 "	display: block;\n"+
	 "}\n\n"+
	 "ul.suckerfish li a.tiddlyLink, ul.suckerfish li a, #mainMenu ul.suckerfish li a {font-weight:bold;}\n"+
	 "/**** END LAYOUT STYLES *****/\n"+
	 "\n\n"+
	 "/**** COLORS AND APPEARANCE - DEFAULT *****/\n"+
	 "ul.suckerfish li a {\n"+
	 "	padding: 0.5em 1.5em;\n"+
	 "	color: #FFF;\n"+
	 "	background: #0066aa;\n"+
	 "	border-bottom: 0;\n"+
	 "	font-weight:bold;\n"+
	 "}\n\n"+
	 "ul.suckerfish li:hover a, ul.suckerfish li.sfhover a{\n"+
	 "	background: #00558F;\n"+
	 "}\n\n"+
	 "ul.suckerfish li:hover ul a, ul.suckerfish li.sfhover ul a{\n"+
	 "	color: #000;\n"+
	 "	background: #eff3fa;\n"+
	 "	border-top:1px solid #FFF;\n"+
	 "}\n\n"+
	 "ul.suckerfish ul li a:hover {\n"+
	 "	background: #e0e8f5;\n"+
	 "}\n\n"+
	 "ul.suckerfish li a{\n"+
	 "	width:9em;\n"+
	 "}\n\n"+
	 "ul.suckerfish ul li a, ul.suckerfish ul li a:hover{\n"+
	 "	display:inline-block;\n"+
	 "	width:9em;\n"+
	 "}\n\n"+
	 "ul.suckerfish li {\n"+
	 "	border-left: 1px solid #00558F;\n"+
	 "}\n"+
	 "/***** END COLORS AND APPEARANCE - DEFAULT *****/\n"+
	 "\n\n"+
	 "/***** LAYOUT AND APPEARANCE: VERTICAL *****/\n"+
	 "ul.suckerfish.vertical li{\n"+
	 "	width:10em;\n"+
	 "	border-left: 0px solid #00558f;\n"+
	 "}\n\n"+
	 "ul.suckerfish.vertical ul li, ul.suckerfish.vertical li a, ul.suckerfish.vertical li:hover a, ul.suckerfish.vertical li.sfhover a {\n"+
	 "	border-left: 0.8em solid #00558f;\n"+
	 "}\n\n"+
	 "ul.suckerfish.vertical li a, ul.suckerfish.vertical li:hover a, ul.suckerfish.vertical li.sfhover a,  ul.suckerfish.vertical li.sfhover a:hover{\n"+
	 "	width:8em;\n"+
	 "}\n\n"+
	 "ul.suckerfish.vertical {\n"+
	 "	width:10em; text-align:left;\n"+
	 "	float:left;\n"+
	 "}\n\n"+
	 "ul.suckerfish.vertical li a {\n"+
	 "	padding: 0.5em 1em 0.5em 1em;\n"+
	 "	border-top:1px solid  #fff;\n"+
	 "}\n\n"+
	 "ul.suckerfish.vertical, ul.suckerfish.vertical ul {\n"+
	 "	line-height:1.4em;\n"+
	 "}\n\n"+
	 "ul.suckerfish.vertical li:hover ul, ul.suckerfish.vertical li.sfhover ul { \n"+
	 "	margin: -2.4em 0 0 10.9em;\n"+
	 "}\n\n"+
	 "ul.suckerfish.vertical li:hover ul li a, ul.suckerfish.vertical li.sfhover ul li a {\n"+
	 "	border: 0px solid #FFF;\n"+
	 "}\n\n"+
	 "ul.suckerfish.vertical li:hover a, ul.suckerfish.vertical li.sfhover a{\n"+
	 "	padding-right:1.1em;\n"+
	 "}\n\n"+
	 "ul.suckerfish.vertical li:hover ul li, ul.suckerfish.vertical li.sfhover ul li {\n"+
	 "	border-bottom:1px solid  #fff;\n"+
	 "}\n\n"+
	 "/***** END LAYOUT AND APPEARANCE: VERTICAL *****/\n"+
	 "/*}}}*/";
store.addNotification("StyleSheetDropDownMenuPlugin",refreshStyles);
//!END-PLUGIN-CODE
// %/
<<importTiddlers inline>>
/***
|''Name:''|LaunchApplicationPlugin|
|''Author:''|Lyall Pearce|
|''Source:''|http://www.Remotely-Helpful.com/TiddlyWiki/LaunchApplication.html|
|''License:''|[[Creative Commons Attribution-Share Alike 3.0 License|http://creativecommons.org/licenses/by-sa/3.0/]]|
|''Version:''|1.4.0|
|''~CoreVersion:''|2.3.0|
|''Requires:''| |
|''Overrides:''| |
|''Description:''|Launch an application from within TiddlyWiki using a button|
!!!!!Usage
<<<
{{{<<LaunchApplication "buttonLabel" "tooltip" "application" ["arguments" ...]>>}}}
{{{<<LaunchApplicationButton "buttonLabel" "tooltip" "application" ["arguments" ...]>>}}}
{{{<<LaunchApplicationLink "buttonLabel" "tooltip" "application" ["arguments" ...]>>}}}
* buttonLabel is anything you like
* tooltip is anything you like
* application is a path to the executable (which is Operating System dependant)
* arguments is any command line arguments the application requires.
* You must supply relative path from the location of the TiddlyWiki OR a fully qualified path
* Forward slashes works fine for Windows

{{{<<LaunchApplication...>>}}} functions the same as {{{<<LaunchApplicationButton...>>}}}

eg.

{{{
<<LaunchApplicationButton "Emacs" "Linux Emacs" "file:///usr/bin/emacs">>
}}}
<<LaunchApplicationButton "Emacs" "Linux Emacs" "file:///usr/bin/emacs">>

{{{
<<LaunchApplicationLink "LocalProgram" "Program relative to Tiddly html file" "localDir/bin/emacs">>
}}}
<<LaunchApplicationLink "LocalProgram" "Program relative to Tiddly html file" "localDir/bin/emacs">>
					     
{{{
<<LaunchApplicationButton "Open Notepad" "Text Editing" "file:///e:/Windows/notepad.exe">>
}}}
<<LaunchApplicationButton "Open Notepad" "Text Editing" "file:///e:/Windows/notepad.exe">>

{{{
<<LaunchApplicationLink "C Drive" "Folder" "file:///c:/">>
}}}
<<LaunchApplicationLink "C Drive" "Folder" "file:///c:/">>


!!!!!Revision History
* 1.1.0 - leveraged some tweaks from from Bradly Meck's version (http://bradleymeck.tiddlyspot.com/#LaunchApplicationPlugin) and the example text.
* 1.2.0 - Make launching work in Linux too and use displayMessage() to give diagnostics/status info.
* 1.3.0 - execute programs relative to TiddlyWiki html file plus fix to args for firefox.
* 1.3.1 - parameters to the macro are properly parsed, allowing dynamic paramters using {{{ {{javascript}} }}} notation.
* 1.4.0 - updated core version and fixed empty tooltip and added launch link capability
***/
{{{
ntdsutil
set dsrm password
reset password on server srv-cht-dc1.flatfish.local
// 改變遠端 DC 還原密碼
// null 代表本機
輸入兩次確認密碼
quit
quit
}}}
{{{
ntdsutil
restore
restore subtree ou=mis,dc=flatfish,dc=local
//只還原 mis 的 ou
}}}
**授權僅是將每個物件屬性的版本數加 100000,以確保最新
{{{
ntdsutil
files
move db to d:\db
move logs to d:\db
quit
quit
}}}

聯絡我: mailto:bearflatfish@gmail.com

<html><a href="../weblog/weblog.html" target="mainFrame"> 更多的 ''比目魚'' 請看 My Weblog </a></html>
/***
|<html><a name="Top"/></html>''Name:''|PartTiddlerPlugin|
|''Version:''|1.0.9 (2007-07-14)|
|''Source:''|http://tiddlywiki.abego-software.de/#PartTiddlerPlugin|
|''Author:''|UdoBorkowski (ub [at] abego-software [dot] de)|
|''Licence:''|[[BSD open source license]]|
|''CoreVersion:''|2.1.3|
|''Browser:''|Firefox 1.0.4+; InternetExplorer 6.0|
!Table of Content<html><a name="TOC"/></html>
* <html><a href="javascript:;" onclick="window.scrollAnchorVisible('Description',null, event)">Description, Syntax</a></html>
* <html><a href="javascript:;" onclick="window.scrollAnchorVisible('Applications',null, event)">Applications</a></html>
** <html><a href="javascript:;" onclick="window.scrollAnchorVisible('LongTiddler',null, event)">Refering to Paragraphs of a Longer Tiddler</a></html>
** <html><a href="javascript:;" onclick="window.scrollAnchorVisible('Citation',null, event)">Citation Index</a></html>
** <html><a href="javascript:;" onclick="window.scrollAnchorVisible('TableCells',null, event)">Creating "multi-line" Table Cells</a></html>
** <html><a href="javascript:;" onclick="window.scrollAnchorVisible('Tabs',null, event)">Creating Tabs</a></html>
** <html><a href="javascript:;" onclick="window.scrollAnchorVisible('Sliders',null, event)">Using Sliders</a></html>
* <html><a href="javascript:;" onclick="window.scrollAnchorVisible('Revisions',null, event)">Revision History</a></html>
* <html><a href="javascript:;" onclick="window.scrollAnchorVisible('Code',null, event)">Code</a></html>
!Description<html><a name="Description"/></html>
With the {{{<part aPartName> ... </part>}}} feature you can structure your tiddler text into separate (named) parts. 
Each part can be referenced as a "normal" tiddler, using the "//tiddlerName//''/''//partName//" syntax (e.g. "About/Features").  E.g. you may create links to the parts (e.g. {{{[[Quotes/BAX95]]}}} or {{{[[Hobbies|AboutMe/Hobbies]]}}}), use it in {{{<<tiddler...>>}}} or {{{<<tabs...>>}}} macros etc.


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


![[AD 系統安裝與操作|AD系統 (Active Directory)]] 課程大綱
*[[Chap 1 - 建置AD系統]]
*[[Chap 2 - 網域用戶端系統]]
*[[Chap 3 - 管理組織單位 (Organization Unit)]]
*[[Chap 4 - 管理網域使用者帳號]]
*[[Chap 5 - 管理網域群組]]
*[[Chap 6 - 群組原則 (GPO) 規劃與應用]]
*[[Chap 7 - AD 委派授權 (Delegation)]]
*[[Chap 8 - AD 線上維護]]

!Windows server 2003 目錄架構規劃、實作與維護