<!--{{{-->
<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>>
--Bash也是可以支持gettext以实现i18n的。比如
{{{
LANG=zh_CN.utf8
TEXTDOMAIN="test"
TEXTDOMAINDIR="/usr/share/locale"
echo $"Add"
}}}
这里在显示Add的时候,会先去/usr/share/locale/zh_CN/~LC_MESSAGES/test.mo搜索,看看能否将Add翻译成汉语显示出来。根据这个脚本很容易可以生成相应的.po文件以供翻译者翻译,用法如下
{{{
bash --dump-op-strings <脚本名>
}}}
这很类似于python的pygettext。这里有个小问题,dump出来的.po文件中不包含codeset等信息,放在poedit里会出现乱码,所以还要自己加一个头,形如
{{{
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR ORGANIZATION
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
msgid ""
msgstr ""
"Project-Id-Version: zh_CN\n"
"POT-Creation-Date: 2008-05-22 00:15+EDT\n"
"PO-Revision-Date: 2008-05-22 18:41-0500\n"
"Last-Translator: laborer <laborer@126.com>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: pygettext.py 1.5\n"
}}}
另外有资料说xgettext也可以用于从bash脚本生成.po文件。

这里还有一个辅助翻译的emacs脚本,很简单的东西,就是选定字符串中要翻译的部分以后按F4,emacs会在选定的部分开头和结尾分别加上__"$"__和__""__,这样选定的这部分就从原来的字符串中独立出来,并且被标记为可翻译
{{{
(add-hook 'sh-mode-hook
	  (lambda () 
	    (local-set-key 
	     [f4]
	     (lambda () 
	       (interactive)
	       (insert-pair nil "\"$\"" "\"\"")))))
}}}

PuppyLinux 4.0自带的bash不支持自动翻译,需要用自己编译的。--

很不幸,上述的方法已经deprecated了。另外更加不幸的是,我这一段已经写过一遍,结果没有保存,现在还要返工,郁闷。。。

这个方法被标记过时的原因是bash的$""语法有潜在的安全隐患,翻译者有可能自己加入代码到$""中间去执行。另外由于$""一直都是bash没有公开的特性,虽然可以这么用,但它从来没有出现在任何正式的文档中。所以出了这样的隐患,似乎大家都没有兴趣直接在bash里修理这个问题,而是用了eval_gettext来替代,方法如下:
{{{
LANG=zh_CN.utf8
TEXTDOMAIN="test"
TEXTDOMAINDIR="/usr/share/locale"
. /usr/bin/gettext.sh
echo "`eval_gettext "Add"`"
}}}
eval_gettext是在第四行的gettext.sh脚本中定义的,所以需要先载入这个脚本。后面eval_gettext部分看似也就比$""方法复杂了一点点,但在实际使用中要复杂了很多。因为字符串中的一些符号会在第一个双引号中被bash解析一遍,之后又被eval_gettext解释一遍,所以很多都需要加额外的escape character,比如,原来在字符串中使用的__\"__要写成__\\\"___,__$X__要写成__\\\$X__。单引号似乎不需要做什么改变,至少我测试的结果是这样,虽然很多文档上说也要用\修饰。由于各个脚本解释器可能在解析字符串中的内容时有所差别。所以使用这个方法有可能降低程序的可移植性。

生成.po的方法也有所不同,因为bash不认得eval_gettext语法,{{{--dump-po-strings}}}也就无法获得想要的结果。这里就需要前面提到的xgettext,方法如下
{{{
xgettext -L Shell -o SCRIPT_NAME.po SCRIPT_NAME 
}}}
生成出的.po文件已经包含头了,不需要另外再加。不过还是需要自己填写一下头中的charset字段。用这个方法就不需要再另外编译bash了。

由于用eval_gettext方法,字符串里的某些字符需要额外的escape处理,这就使得标记需翻译段落的emacs脚本复杂了很多。用法还是和前面的一样。另外,标记过的字符串中会产生一大堆\\\,看上去可读性下降了一些。
{{{
(add-hook 'sh-mode-hook
	  (lambda () 
	    (local-set-key 
	     [f4]
	     (lambda (beg end) 
	       (interactive "r")
	       (when mark-active
		 (setq bound (max beg end))
		 (setq start (min beg end))
		 (goto-char start)
		 (while (search-forward "\\\"" bound t)
		   (setq pos (point))
		   (replace-match "\\\\\\\\\\\\\"")
		   (setq bound (+ bound (- (point) pos))))
		 (goto-char start)
		 (while (search-forward "$" bound t)
		   (setq pos (point))
		   (replace-match "\\\\\\\\\\\\$")
		   (setq bound (+ bound (- (point) pos))))
		 (goto-char start)
		 (push-mark start)
		 (goto-char bound)
		 (insert-pair nil "\"\"`eval_gettext \"" "\"`\"\"")
		 )))))
}}}
下面这个emacs脚本是搜寻程序中形如
{{{
MSG="`Xdialog ...`"
}}}
并替换为可以使用eval_gettext的形式
{{{
MSG="Xdialog ..."
MSG="`$MSG`"
}}}
{{{
(global-set-key 
 [f5]
 (lambda () 
   (interactive)
   (let ((var nil)
	 (start nil)
	 (bound nil)
	 (pos nil))
     (transient-mark-mode nil)
     (search-forward "=\"`Xdialog")
     (search-backward "=")
     (setq start (point))
     (beginning-of-line)
     (setq var (buffer-substring-no-properties (point) start))
     (push-mark)
     (search-forward "`\"\n")
     (transient-mark-mode t)
     
     (when (y-or-n-p "fix this? ")
       (setq bound (- (point) 1))
       (open-line 1)
       (insert var "=\"`$" (car (split-string var)) "`\"")
       (goto-char (- bound 2))
       (delete-char 1)
       (goto-char (+ start 2))
       (delete-char 1)
       (setq start (+ start 2))
       (setq bound (- bound 3))
       (goto-char start)
       (while (re-search-forward "[^\\]\"" bound t)
	 (backward-char 1)
	 (insert "\\")
	 (setq bound (+ bound 1))
	 )
       )
     )))
}}}
为PuppyLinux 4.0制作的中文包,是从[[ly2101所做的中文包|http://e-pup.5d6d.com/thread-173-1-1.html]]改编而来。其功能有:
* 支持locale为zh_CN.~UTF-8;
* 中文输入法fcitx-3.5-070713;
* 支持中文的虚拟终端rxvt-unicode;
* pmount支持中文cd和ntfs/fat分区;
* pmount支持通过fstab自定义挂载点,见PMountPatch;
* 修正了geany不能输入中文和新文件中输入中文后不能保存的问题;
* 修正了jwm菜单和窗口标题栏不能显示中文的问题;
* 修正了didiwiki不能新建页面的问题;

此包可以在[[这里|http://www.fs2you.com/files/926b20fd-245d-11dd-abaa-00142218fc6e/]]下载。相关技术细节请参考ChinesePackDetail
这里是[[chinese_pack-0.4包|ChinesePack]]的一些技术细节。


! 一些国际化支持文件
gconv,用来做编码间转换用的,fcitx需要用到,大概是为了解开那个~GB2312编码的配置文件。其他比如geany中编码转化也需要用到。
{{{
./usr/lib/gconv/*
}}}

libc的locale支持文件
{{{
./usr/lib/locale/zh_CN.utf8/*
}}}
Puppy4自带的i18n数据不包含足以生成中文locale的信息,这个包里所用的数据都来自[[GNU libc|http://ftp.gnu.org/gnu/glibc/]]。解开glibc包之后,将{{{localedata/charmaps}}}和{{{localedata/locales}}}两个目录复制到{{{/usr/share/i18n/}}}中,然后运行:
{{{
localedef -v -c -i zh_CN -f UTF-8 /usr/lib/locale/zh_CN.utf8
}}}
注意,最后一个参数一定要用目录形式。这里还有一个版本的问题,Puppy4使用的是glibc-2.6.1,但是用2.6.1源码包中的i18n数据生成的中文locale在Puppy4下使用却有很多问题,比如如果pidgin中的好友用中英文混合的nickname会导致pidgin崩溃,使用bash的tab键自动扩展的时候也会导致rxvt崩溃。我发现用glibc-2.3.6中的i18n数据就没有问题,这背后估计有Puppy4中的一些库的版本的问题。

X11用的locale支持文件,不太清楚是做什么用的,fcitx需要。
{{{
./usr/X11R7/lib/X11/locale/compose.dir
./usr/X11R7/lib/X11/locale/locale.alias
./usr/X11R7/lib/X11/locale/locale.dir
./usr/X11R7/lib/X11/locale/zh_CN.UTF-8/XLC_LOCALE
./usr/X11R7/lib/X11/locale/zh_CN.UTF-8/XI18N_OBJS
./usr/X11R7/lib/X11/locale/zh_CN.UTF-8/Compose
}}}

! fcitx,小企鹅输入法
config被修改过了,改了字体和字号
{{{
./usr/bin/fcitx
./usr/share/fcitx/data/AutoEng.dat
./usr/share/fcitx/data/pyphrase.mb
./usr/share/fcitx/data/pySym.mb
./usr/share/fcitx/data/sp.dat
./usr/share/fcitx/data/punc.mb
./usr/share/fcitx/data/tables.conf
./usr/share/fcitx/data/gbks2t.tab
./usr/share/fcitx/data/pybase.mb
./usr/share/fcitx/data/config
./usr/share/fcitx/data/vk.conf
}}}

! rxvt-unicode,支持utf8的终端模拟软件
{{{
./usr/bin/rxvt
./usr/bin/urxvt
./usr/share/terminfo/r/rxvt-unicode
./usr/share/applications/chinese_pack.desktop
}}}
这里用rxvt(就是rxvt-unicode)覆盖了Puppy4自带的rxvt,另外符号链接urxvt指向rxvt,这是为了使terminfo正常工作,否则Home和End两个键不能正常工作。

编译rxvt-unicode所用的参数
{{{
./configure --prefix=/usr \
	--disable-unicode3 \
	--disable-combining \
	--enable-xft \
	--enable-font-styles \
	--disable-afterimage \
	--disable-transparency \
	--disable-fading \
	--enable-rxvt-scroll \
	--disable-next-scroll \
	--disable-xterm-scroll \
	--disable-perl \
	--enable-xim \
	--enable-backspace-key \
	--enable-delete-key \
	--enable-resources \
	--disable-8bitctrls \
	--disable-swapscreen \
	--disable-iso14755 \
	--disable-frills \
	--disable-keepscrolling \
	--enable-selectionscrolling \
	--enable-mousewheel \
	--enable-slipwheeling \
	--enable-smart-resize \
	--enable-text-blink \
	--enable-pointer-blank \
	--disable-utmp \
	--disable-wtmp \
	--disable-lastlog \
	--with-codesets= \
	--with-x
}}}

! 中文字体
{{{
./usr/share/fonts/default/misc/wenquanyi_10ptb.pcf
./usr/share/fonts/default/misc/wenquanyi_10pt.pcf
}}}

! JWM
增加了一个叫Chinese的主题,此主题使用Wenquanyi Bitmap Song字体,使得JWM可以正确显示汉字
{{{
./root/.jwm
./root/.jwm/jwm_colors
./root/.jwm/jwmrc-theme
./root/.jwm/themes
./root/.jwm/themes/Chinese-tray.png
./root/.jwm/themes/Chinese-window.png
./root/.jwm/themes/Chinese-jwmrc
./root/.jwm/themes/Chinese-colors
}}}

! geany
修正geany不能输入汉字的问题,是因为geany占用了ctrl-space,小企鹅就呼不出来了。
{{{
./root/.geany/keybindings.conf
}}}

! pmount
[[补丁过的pmount|PMountPatch]],可以挂载有中文文件名的ntfs分区和cd,另外它可以根据fstab选择挂载点,而不仅仅是设备名称。
{{{
./usr/sbin/pmount
}}}

! 安装/卸载:
* 启动fcitx({{{/root/.xinitrc}}});
* 去掉{{{/root/.Xdefaults}}}中设置urxvt背景色彩的一段;
* 将geany新建文件的编码改为utf-8,这样才能保存包含中文字符的新文件;
* 重新构建/usr/share/fonts/default/misc中的fonts.dir和fonts.scale;
* 重建xterm指向rxvt的符号链接,为的是方便rox中按`键启动终端;
* 自动恢复chinese_pack-0.2卸载时删除的/usr/share/fcitx/data/tables.conf,这样就不需要重新安装chinese_pack_extra;
* 设置/root/spot/.didiwiki的拥有着为spot:spot,这样didiwiki才可以新建页面;
* fc-cache -fv
* fcitx-3.5-070713在检测到~/.fcitx/config不存在时会自动建一个配置文件,有时候是从/usr/share/fcitx/data/config拷贝过来,有时候是一个不知哪来的配置,这个配置会弄得fcitx字体很难看。所以在fcitx启动前加了一段检测,如果发现是那个讨厌的配置,则用/usr/share/fcitx/data/config覆盖掉;
* 设置~LC_CTYPE之前做检测,如果已经被设为其他zh_CN的locale就不改这个变量了。
{{{
./pinstall.sh
./puninstall.sh
}}}
这个安装包提供一些额外的中文字体和补丁,使系统更好的支持中文。其主要功能有:
* 增加五笔、仓颉和二笔输入法
* 安装从svn下载编译的epdfview(系统自带的按page-down会segment fault)
* 安装AR PL Uming CN和Wenquanyi Bitmap Song字体
* 支持中文pdf文件浏览
* Abiword新建文件中可以输入中文
安装此包前,请先安装ChinesePack。相关技术细节请参考ChinesePackExtraDetail。
这里是[[chinese_pack_extra-0.2包|ChinesePackExtra]]的一些技术细节。

! 字体及其配置
安装了AR PL ~UMing CN字体,它是从ubuntu中的uming.ttc中分离出来,去掉了其中的bitmap字体,而由新安装的Wenquanyi Bitmap Song来代替其中pixelsize介于11~18之间的字体。注意,这里WQY没有包含10号字,因为它已经包含在ChinesePack中了。
{{{
./etc/fonts/local.conf
./usr/share/fonts/default/TTF/UMingCN.ttf
./usr/share/fonts/default/misc
./usr/share/fonts/default/misc/wenquanyi_12pt.pcf
./usr/share/fonts/default/misc/wenquanyi_11pt.pcf
./usr/share/fonts/default/misc/wenquanyi_9ptb.pcf
./usr/share/fonts/default/misc/wenquanyi_12ptb.pcf
./usr/share/fonts/default/misc/wenquanyi_9pt.pcf
./usr/share/fonts/default/misc/wenquanyi_11ptb.pcf
}}}

! 输入法
n种fcitx用的额外的输入法
{{{
./usr/share/fcitx/data/tables.conf
./usr/share/fcitx/data/wbx.mb
./usr/share/fcitx/data/erbi.mb
./usr/share/fcitx/data/cj.mb
./usr/share/fcitx/data/wbpy.mb
./usr/share/fcitx/data/qxm.mb
./usr/share/fcitx/data/wanfeng.mb
}}}

fcitx的文档
{{{
./usr/share/fcitx/doc/cjkvinput.txt
./usr/share/fcitx/doc/pinyin.txt
./usr/share/fcitx/doc/fcitx3.pdf
./usr/share/fcitx/doc/wb_fh.htm
}}}

fcitx的工具
{{{
./usr/bin/txt2mb
./usr/bin/readPYMB
./usr/bin/pyjj2fcitx
./usr/bin/readPYBase
./usr/bin/mb2org
./usr/bin/jd2fcitx
./usr/bin/mb2txt
./usr/bin/createPYMB
./usr/bin/epdfview
./usr/bin/win2fcitx
}}}

! GBK编码
{{{
./usr/X11R7/lib/X11/locale/zh_CN.gbk/XLC_LOCALE
./usr/X11R7/lib/X11/locale/zh_CN.gbk/Compose
./usr/X11R7/lib/X11/locale/zh_CN.gbk/XI18N_OBJS
./usr/lib/locale/zh_CN.gbk/LC_COLLATE
./usr/lib/locale/zh_CN.gbk/LC_MEASUREMENT
./usr/lib/locale/zh_CN.gbk/LC_NUMERIC
./usr/lib/locale/zh_CN.gbk/LC_IDENTIFICATION
./usr/lib/locale/zh_CN.gbk/LC_MONETARY
./usr/lib/locale/zh_CN.gbk/LC_TELEPHONE
./usr/lib/locale/zh_CN.gbk/LC_MESSAGES/SYS_LC_MESSAGES
./usr/lib/locale/zh_CN.gbk/LC_PAPER
./usr/lib/locale/zh_CN.gbk/LC_ADDRESS
./usr/lib/locale/zh_CN.gbk/LC_NAME
./usr/lib/locale/zh_CN.gbk/LC_CTYPE
./usr/lib/locale/zh_CN.gbk/LC_TIME
}}}

! Abiword
默认字体为中文字体,这样新建的文件就直接可以输入中文了,不过老的文件还是要全选然后改字体才能正确显示。总得来说Abiword对中文支持不好。
{{{
./root/.AbiSuite/templates/normal.awt
}}}

! epdfview
使用了svn中的版本,系统自带的按page-down会crash。
{{{
./usr/bin/epdfview
}}}

! 中文pdf浏览
使用了ubuntu中的poppler-data包,去掉了其中日文和韩文的支持。
{{{
./usr/share/poppler/*
}}}

! 安装/卸载
刷新fonts.dir、fonts.scale和fc-cache
{{{
./pinstall.sh
./puninstall.sh
}}}
/***
|''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);
};


}
//}}}
MovedPermanently
/***
|''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");

}
//}}}
E-PUP是基于PuppyLinux的中文发行版,目前发布的版本基于PuppyLinux 2.17。
!链接
*E-PUP的[[Blog|http://hi.baidu.com/puppylinux]]、[[论坛|http://e-pup.5d6d.com/]]和[[聊天室|http://embed.mibbit.com/?server=irc.us.freenode.net&channel=%23e-pup]]
这段elisp程序的作用是搜寻并标记Shell脚本中可被翻译的字符串。在Shell脚本中按F7后,这个程序从光标所在位置开始搜寻脚本中可被翻译的字符串,找到后询问是否要将此字符串标记为可翻译。如果得到肯定回答,则将此字符串放入{{{$(eval_gettext "")}}}中,然后继续搜寻下一个可翻译的字符串。

如果用户选择错误,或者emacs没有能正确的找到字符串(emacs的语法分析有时候还是会出错的,特别是在语法特别复杂的shell上),可以按Esc或者ctrl-g停止。然后可以undo上一次标记的动作,或者用鼠标手动选出需要翻译的字符串,然后按F6自动加上{{{eval_gettext}}}标记。

这是我写的第一个像点样子的elisp程序。目前感觉elisp用起来还是比较痛苦的,语法到不是问题,实际上lisp的语法超级简单。主要是找不到所需要的函数,因为所有的函数都在一个平面上,不像现代一些的语言都是用名字空间/包/类等概念将函数分门别类。另外有些时候函数名称的意义也不太好猜。也许用多了、熟悉了之后会好一些。当然,现在还没有多用它的念头。
{{{
;;; find a string
(defun translatable-search ()
  (let ((start nil)
        (end nil))
    (while (and (not (eq ?\" (nth 3 (syntax-ppss))))
                (search-forward "\"" nil t)))
    (when (setq start (nth 8 (syntax-ppss)))
      (while (and (search-forward "\"" nil t)
                  (eq ?\" (nth 3 (syntax-ppss)))))
      (when (not (eq ?\" (nth 3 (syntax-ppss))))
        (list (+ start 1) (- (point) 1))))))

;;; find a string which is embedded in another string
(defun translatable-search-embedded (limit)
  (let ((start nil)
        (end nil))
    (when (re-search-forward 
           (concat "\\\\\"\\([^\000]*?\\)\\\\\"" "\\|"
                   "[^\\\\]\"\\(\\|[^\000]*?[^\\\\]\\)\"" "\\|"
                   "<label>\\([^\000]*?\\)</label>" "\\|"
                   "<wtitle>\\([^\000]*?\\)</wtitle>" "\\|"
                   "<frame \\([^\000]*?\\)>")
           limit t)
      (dolist (elt '(1 2 3 4 5) (list start end))
        (setq start (or start (match-beginning elt)))
        (setq end (or end (match-end elt)))))))

;;; analyze whether a string needs to be translated
(defun translatable-analyze (start end)
  (let ((score 0)
        (str nil))
    (save-excursion
      (setq str (buffer-substring start end))
      (goto-char start)

      (when (or (looking-back "<label>")
                (looking-back "<wtitle>")
                (looking-back "<window[[:blank:]]+title=\\\\\"")
                (looking-back "<frame ")
                (looking-back "[[:blank:]]+-?-title[[:blank:]]+[\\\\]?\""))
        (setq score (+ score 100)))
      (when (or (looking-back "[[:alnum:]]*MSG[[:alnum:]]*=\""))
        (setq score (+ score 50)))

      (when (= start end)
        (setq score (- score 100)))
      (when (or (string-match "\\`[[:blank:]]*`" str)
                (string-match "\\`[[:blank:]]*\\$(" str)
                (string-match "\\`\\$[[:alnum:]_]+\\'" str)
                (string-match "\\`\\${[[:alnum:]_]+}\\'" str)
                (string-match "\\`[^[:alpha:]]+\\'" str)
                )
        (setq score (- score 100)))
      (when (or (looking-back (concat "[^[:alnum:]]\\(?:" 
                                      "icon-name" "\\|"
                                      "type" "\\|"
                                      "icon" "\\|"
                                      "stock" "\\|"
                                      "use-markup"
                                      "\\)=\\\\\""))
                (looking-back (concat "[[:blank:]]+-?-\\(?:"
                                      "bg" "\\|"
                                      "font"
                                      "\\)[[:blank:]]+[\\\\]?\""))
                (and (looking-back " = \"")
                     (save-excursion
                       (goto-char end)
                       (looking-at "\" \\]")))
                (looking-back " | grep \"")
                (string= "true" str)
                (string= "false" str)
                (and (string-match "\\([^\000]*<\\)\\{10\\}" str)
                     (string-match "\\([^\000]*>\\)\\{10\\}" str))
                )
        (setq score (- score 50)))
      (>= score 0)
      )))

;;; mark a string translatable by putting it in a eval_gettext clause
(defun translatable-mark (start end)
  (interactive "r")
  (let ((limit (copy-marker end)))
    (save-excursion
      (undo-boundary)
      (setq buffer-undo-list (cons (point) buffer-undo-list))
      (goto-char start)
      (while (search-forward "$" limit t)
        (replace-match "\\\\$"))
      (goto-char limit)
      (insert "\")")
      (goto-char start)
      (insert "$(eval_gettext \""))))

;;; highlight a region
(defun translatable-highlight (start end)
  (goto-char start)
  (transient-mark-mode nil)
  (push-mark)
  (goto-char end)
  (transient-mark-mode t))

;;; search and mark translatable string
(defun translatable ()
  (interactive)
  (let ((ret nil)
        (start nil)
        (limit nil)
        (start2 nil)
        (limit2 nil))
    (while (setq ret (translatable-search))
      (save-excursion
        (setq start (car ret))
        (setq limit (copy-marker (cadr ret)))
        (translatable-highlight start limit)
        (if (and (translatable-analyze start limit)
                 (y-or-n-p "Mark this string translatable? "))
            (translatable-mark start limit)
          (progn 
            (goto-char start)
            (while (setq ret (translatable-search-embedded limit))
              (save-excursion
                (setq start2 (car ret))
                (setq limit2 (copy-marker (cadr ret)))
                (translatable-highlight start2 limit2)
                (when (and (translatable-analyze start2 limit2)
                           (y-or-n-p "Mark this string translatable? "))
                  (translatable-mark start2 limit2))
                ))))
        (kill-region start limit)
        (yank)
        ))))


(add-hook 
 'sh-mode-hook
 (lambda () 
   (local-set-key [f6] 'translatable-mark)
   (local-set-key [f7] 'translatable)))


(provide 'translatable)
}}}
Geany中是可以输入中文的,只要把Geany中的Ctrl-Space快捷键定义去掉就可以了。或者用修改配置文件的方法,把{{{/root/.geany/keybindings.conf}}}中的
{{{
edit_autocomplete=<Ctrl>space
}}}
改为
{{{
edit_autocomplete=<Alt>slash #其他也行
}}}
如果keybindings.conf不存在,或者没有edit_autocomplete定义,只要加入上面一行就行了。

Geany是相当不错的软件,以后汉化的版本就没有必要另外装别的文本编辑软件了。
存放pup_xxx.sfs、pup_save.2fs等文件的分区是在启动阶段被挂载的(可以在/mnt/home中看到)。默认情况下,如果该分区是FAT格式,那么这个分区上的中文文件名将均显示为?????,chinese_pack中的pmount补丁对此也无能为力。如果遇到了这样的情况,可以试试这个补丁。

需要先解开原来的initrd.gz,方法如下
{{{
$ mkdir initrd
$ cd initrd
$ zcat ../initrd.gz | sudo cpio -id
}}}
补丁为
{{{
--- ../old_initrd/init	2008-05-18 23:01:02.000000000 -0400
+++ init	2008-05-18 17:46:34.000000000 -0400
@@ -62,9 +62,7 @@
 }
 
 mntfunc() {
- if [ "`echo "$*" | grep 'ntfs'`" = "" ];then
-  mount $@
- else
+ if [ "`echo "$*" | grep 'ntfs'`" != "" ];then
   #screen out -o and -t options...
   MNTPRMS="`echo -n "$*" | tr '\t' ' ' | tr -s ' ' | tr ' ' '\n' | grep '^/' | tr '\n' ' '`"
   #v4.00 new ntfs-3g version...
@@ -81,6 +79,14 @@
   else
    ntfs-3g $MNTPRMS -o umask=0,no_def_opts,noatime,rw,force 2>/dev/null
   fi
+ elif [ "`echo "$*" | grep 'vfat'`" != "" ];then
+  MNTPRMS="`echo -n "$*" | tr '\t' ' ' | tr -s ' ' | tr ' ' '\n' | grep '^/' | tr '\n' ' '`"
+  #echo "*=$*" >/dev/console
+  #echo "MNTPRMS=$MNTPRMS" >/dev/console
+  #sleep 10
+  mount $MNTPRMS -o noatime,utf8
+ else
+  mount $@
  fi
  return $?
 }
}}}
打完补丁以后重新制作initrd.gz包
{{{
$ find ./ | cpio -H newc -o | gzip -9 >../initrd.gz
}}}
JWM是一个轻量级的窗口管理器。

! 一些问题
* 我发现如果~/.jwm/jwmrc-theme文件中所指定的字体是系统上存在的英文字体,那么jwm中出现的中文将不能被正确显示。估计这是因为jwm实现得比较简陋,没有很好的使用fontconfig字体选择机制。目前最简单的解决方案就是把~/.jwm/jwmrc-theme连同~/.jwm/themes/*中的字体全换成中文字体。或者只允许使用Original主题,因为那个里面指定的是Sans,一种系统上不存在的英文字体,所以中文可以被正确显示。
* 对~XRandR支持得不好,panel不能自动根据屏幕大小自动改变位置或尺寸。
与我联系:laborer 126 com
/***
|''Name:''|LoadRemoteFileThroughProxy (previous LoadRemoteFileHijack)|
|''Description:''|When the TiddlyWiki file is located on the web (view over http) the content of [[SiteProxy]] tiddler is added in front of the file url. If [[SiteProxy]] does not exist "/proxy/" is added. |
|''Version:''|1.1.0|
|''Date:''|mar 17, 2007|
|''Source:''|http://tiddlywiki.bidix.info/#LoadRemoteFileHijack|
|''Author:''|BidiX (BidiX (at) bidix (dot) info)|
|''License:''|[[BSD open source license|http://tiddlywiki.bidix.info/#%5B%5BBSD%20open%20source%20license%5D%5D ]]|
|''~CoreVersion:''|2.2.0|
***/
//{{{
version.extensions.LoadRemoteFileThroughProxy = {
 major: 1, minor: 1, revision: 0, 
 date: new Date("mar 17, 2007"), 
 source: "http://tiddlywiki.bidix.info/#LoadRemoteFileThroughProxy"};

if (!window.bidix) window.bidix = {}; // bidix namespace
if (!bidix.core) bidix.core = {};

bidix.core.loadRemoteFile = loadRemoteFile;
loadRemoteFile = function(url,callback,params)
{
 if ((document.location.toString().substr(0,4) == "http") && (url.substr(0,4) == "http")){ 
  url = store.getTiddlerText("SiteProxy", "/proxy/") + url;
 }
 return bidix.core.loadRemoteFile(url,callback,params);
}
//}}}
!!!站点导航
[[PuppyLinux|puppy]]
[[Puppy软件包|pet]]
[[软件翻译|translate]]
[[随手笔记|RandomNotes]]
[[与我联系|Labrador]]
!!!有用的链接
@@font-size:0.8em;[[E-PUP聊天室|http://embed.mibbit.com/?server=irc.us.freenode.net&channel=%23e-pup]]
[[Ubuntu中文论坛|forum.ubuntu.org.cn]]
[[PuppyLinux论坛|http://www.murga-linux.com/puppy/]]
[[PuppyLinux中文项目|http://sites.google.com/site/cnpuppy/]]@@
本站的内容已经移至[[http://puppy.cnbits.com|http://puppy.cnbits.com]]
这个补丁的主要作用是使pmount
* 正确挂载有中文文件名的cd和ntfs/fat分区
* 根据fstab中的设定,选取设备的挂载点

使用方法很简单。比如,在/etc/fstab中添加一行:
{{{
/dev/hda1    /root/C盘    auto    noauto,rw    0 0
}}}
之后使用打过补丁的pmount就可以将{{{/dev/hda1}}}挂载到{{{/root/C盘}}},而不是默认的{{{/mnt/hda1}}}。如果要挂载到别的地方,后面"{{{auto noauto,rw 0 0}}}"几个参数不需要改动,只要改第二个参数就可以了。

如果想将U盘挂载到某一个指定的地方,方法稍微复杂一点。因为U盘可能因为插入的顺序不同使其设备名发生变化,所以我们需要先知道所要挂在U盘分区的UUID,而UUID是永远不变的,除非你重新格式化。此ID可以通过运行blkid获得。比如在终端下运行blkid后得到
{{{
# blkid
/dev/loop1: UUID="52f8f4ce-245b-426c-972c-d0a580efcade" TYPE="ext2" 
/dev/sda1: UUID="F057-D3D4" TYPE="vfat" 
/dev/sdb1: SEC_TYPE="msdos" LABEL="STAPLES" UUID="D837-7888" TYPE="vfat" 
}}}
其中{{{/dev/sda1}}}是我经常使用的kingston的U盘,我想每次都将它挂载到{{{/mnt/kingston}}},那么就在{{{etc/fstab}}}中加入一行:
{{{
UUID=F057-D3D4    /mnt/kingston    auto    noauto,rw    0 0
}}}
这样插入那个U盘以后,运行pmount就可以将它挂载到指定目录。

需要注意的是挂载目录名''不能''包含空格,另外fstab中的UUID字符串''不需要''加双引号。

以下是这个补丁的内容:
{{{
--- /initrd/pup_ro2/usr/sbin/pmount	2008-04-07 06:11:00.000000000 -0400
+++ pmount	2008-05-17 19:35:05.000000000 -0400
@@ -205,19 +205,39 @@
  DODEV="`echo -n "$EXIT" | cut -f 2 -d '_'`"
  DEVNAME="`echo -n "$DODEV" | cut -f 3 -d '/'`"
  DOFS="`echo -n "$EXIT" | cut -f 3 -d '_'`"
- mkdir -p /mnt/$DEVNAME
+
+ MNTPT="`cat /etc/fstab | awk -v "DEV=$DODEV" '$1==DEV {print $2; exit}'`"
+ if [ -z "$MNTPT" ]; then
+  UUID="`blkid | grep "^$DODEV:" | grep -o 'UUID=\"[^\"]*' | sed 's/\"//g'`"
+  MNTPT="`cat /etc/fstab | awk -v "DEV=$UUID" 'toupper($1)==toupper(DEV) {print $2; exit}'`"
+ fi
+ if [ -z "$MNTPT" ]; then
+  MNTPT=/mnt/$DEVNAME
+ else
+  MNTPT="`echo -n "$MNTPT" | sed 's/\\\\040/ /g'`"
+  # It seems that mount in PUP4 doesn't work if the mountpoint contains space character,
+  # so we fall back to old mountpoint in this case. If PUP4 fixes this problem in future,
+  # remove the following line, and this comment, of course.
+  echo -n "$MNTPT" | grep " " && MNTPT=/mnt/$DEVNAME  
+ fi
+
+ mkdir -p "$MNTPT"
  case $DOFS in
   ntfs)
    #'mount' is a script that takes care of mounting ntfs...
-   mount -t ntfs $DODEV /mnt/$DEVNAME
+   mount -t ntfs -o nls=utf8 $DODEV "$MNTPT"
    RETVAL1=$?
    ;;
   vfat)
-   mount -t vfat -o shortname=mixed $DODEV /mnt/$DEVNAME
+   mount -t vfat -o shortname=mixed,utf8 $DODEV "$MNTPT"
+   RETVAL1=$?
+   ;;
+  iso9660)
+   mount -t iso9660 -o utf8 $DODEV "$MNTPT"
    RETVAL1=$?
    ;;
   *)
-   mount -t $DOFS $DODEV /mnt/$DEVNAME
+   mount -t $DOFS $DODEV "$MNTPT"
    RETVAL1=$?
    ;;
  esac
@@ -230,7 +250,7 @@
   done
   usleep 100000
   #v3.95 -x option to rescan...
-  exec rox -x /mnt/$DEVNAME -d /mnt/$DEVNAME #want this window on top.
+  exec rox -x "$MNTPT" -d "$MNTPT" #want this window on top.
   #exit
  else
   xmessage -bg red -center -title "Pmount" "ERROR: unable to mount $DEVNAME"
}}}
自动翻译po的python程序,可以支持多个代理服务器轮流向google translate发出请求,以免被google封锁,哈哈。
{{{
#!/usr/bin/python
# -*- coding: utf-8 -*-

import sys
import httplib
import urllib
import urllib2
import traceback
import re
import random


def translate(text):
    addr = "http://www.google.com/translate_t?sl=en&tl=zh-CN"

    proxies = [
        "72.247.52.10:80",
        "72.246.132.10:80",
        #"210.19.150.9:3128",
        #"proxy.otgserv.com:8080",
        # "compression01.stkn.mdsg-pacwest.com:80",
        "m20677151197.austincc.edu:80",
        #"72.51.39.224:3128",
        "72.247.76.10:80"
        ]
    random.shuffle(proxies)
    proxies.append(None)
    
    for proxy in proxies:
        try:
            req = urllib2.Request(addr)
            req.add_header("User-Agent", "Mozilla/5.0")
            req.add_data(urllib.urlencode({"text": text}))
            if proxy:
                req.set_proxy(proxy, "http")
            trans = urllib2.urlopen(req).read()
            trans = re.search("<div id=result_box dir=\"ltr\">(.*?)</div>", 
                              trans).group(1)
            trans = re.sub("&#(\d+);", 
                           lambda s: chr(int(s.group(1))), 
                           trans)
            trans = re.sub("&([a-z]+);", 
                           lambda s: {"lt":"<", "gt":">", "amp":"&"}[s.group(1)],
                           trans)
            return trans
        except:
            print >>sys.stderr, "Proxy: %s" % proxy
            traceback.print_exc()

    return None
            

def translate_fixed(text):
    signature = random.random()
    notrans = []
    def replace(match):
        notrans.append(match.group(0))
        return "%018.12f" % (signature + len(notrans) - 1)
    text = re.sub("\${[\w_]+}|\$[\w_]+", replace, text)
    text = re.sub("\\\\\"|\\\\$|\\\\\\\\n", replace, text)
    text = re.sub("\\\\", replace, text)
    text = re.sub("[A-Z]{2,100}", replace, text)
    text = re.sub("<\w+>|</\w+>", replace, text)

#     print text

    trans = translate(text)

    for i in range(len(notrans)):
        trans = re.sub("0 ?%017.12f" % (signature + i), lambda x: notrans[i], trans)

    return trans


random.seed()

input = [s.rstrip() for s in open(sys.argv[1]).readlines()]
input.append("")

for i in range(0, len(input)):
    print input[i]
    if not input[i]:
        break;

i += 1
trans = []
buf = ""
while i < len(input):
    if input[i].startswith("#,"):
        print input[i] + ", fuzzy"
    elif input[i].startswith("#"):
        print input[i]
    elif input[i].startswith("msgid "):
        print "msgid",
        input[i] = input[i][6:]
    elif input[i].startswith("msgstr "):
        print "msgstr",
        if buf:
            trans.append(translate_fixed(buf))
            buf = ""
        for s in trans:
            print "\"" + s + "\""
        print
        while input[i]:
            i += 1
        trans = []

    if input[i].startswith("\""):
        print input[i]
        buf += input[i][1:-1]
        if buf.endswith("\\n"):
            trans.append(translate_fixed(buf[:-2])+"\\n")
            buf = ""
    
    i += 1
}}}
做了一个poedit的pet包,在PuppyLinux 4.0上测试可以正常使用。这个包是由ubuntu 8.04上的poedit、gettext、libwxbase2.6-0和libwxgtk2.6-0四个deb包合并而成,没有做其他改动。

之前还尝试自己在PuppyLinux 4.0上编译poedit,结果问题很多,poedit所依赖的wxwidget都没有编译成功。居然ubuntu上的拿来就能用,太幸运了。

[[下载地址|http://www.fs2you.com/files/a70b72c0-2d0e-11dd-84c7-00142218fc6e/]]
PuppyLinux是一个小型化的Linux发行版,最新的4.0版大小仅有87M。虽然身材小巧,PuppyLinux的功能却一点不含糊,它包含了包括网络、办公、图像处理,影音娱乐等多种软件,完全可以满足一般应用的需要。而小巧的体积使得其可以被完全装载进内存中运行,这很大程度上优化了程序的运行速度,PuppyLinux所附带的大部分程序都可以在弹指之间启动完成。PuppyLinux的另一个优点是它可以被安装到许多不同种类的介质上启动运行,比如:CD,U盘,存储卡,硬盘等等。

! 介绍
* PuppyLinux由Barry Kauler从2003起开发。
* 它使用的窗口管理器是轻量级(简陋的另一种说法)的[[JWM]]。
* 那个[[简约的狗脸图标|http://www.murga-linux.com/puppy/viewtopic.php?t=19591]]最初由rastapax设计,afgs以前作为基础改进制作了[[4.0版的中的狗脸图标|http://murga-linux.com/puppy/viewtopic.php?t=28748]](都是粉可爱粉可爱的呀)。
* 包含了pure-ftpd作为文件共享服务器。

! 评价
''优点''
* 速度快,体积小,功能全,软件新(相对其它小型Linux发行版而言)。
* 可以被安装到各种介质上。
''缺点''
* 软件包比较缺乏。

! 八卦
* “[[Puppy|http://www.puppylinux.com/amy/index.html]]”是Barry Kauler养的一只吉娃娃狗的名字(哈哈,好没创意的狗名),后来这只可怜的小狗不幸走失,Barry Kauler说可能是被别的动物捉去了;
* PuppyLinux默认的root密码是woofwoof,不过绝大部分情况下用不着就是了。

!链接
* PuppyLinux[[官方网站|http://www.puppylinux.com]]和[[英文论坛|http://www.murga-linux.com/puppy/]]
* Ownlinux.cn上一篇[[PuppyLinux 4.0介绍|http://www.ownlinux.cn/2008/05/06/puppy-linux-400-experience/]]
开发的话需要安装linux-header-2.6.19.1
----
启动时不能用参数psubdir=puppy400,否则save personal session files to a parition就不起作用了。只能去掉psubdir让initrd/init脚本自动去找.sfs文件的位置。
----
.pet中的pinstall.sh所使用的目录必须是./usr/local/bin这种形式,之前必须要有一个".",因为在unleashed环境中运行它时,它应该把修改写入rootfs-complete/目录,而不是/目录。
----
运行puninstall.sh时的当前目录为/root/.packages
----
echo abc >>/mnt/samba/text.txt,如果text.txt是一个在samba服务器上的文件,这个命令会把abc覆盖到text.txt的开头,而不是复制到text.txt的末尾
----
注册irc聊天室:
/cs register <channel> <password>
/cs set <channel> url <web address>
/cs set <channel> guard on
/cs level #e-pup set AUTOOP 10
----
/etc/rc.d/*要加到/etc/rc.d/rc.local才能启动
----
A="`echo x; echo; echo`", A的值只是等于x,后面有多少个echo都不管用。
----
在虚拟机上/etc/fstab不能写,不然unionfs就会出内核异常。
----
如需让fcitx在en_US的locale下支持中文输入,修改{{{/etc/gtk-2.0/gtk.immodules}}},将
{{{
"xim" "X Input Method" "gtk20" "/usr/share/locale" "ko:ja:th:zh" 
}}}
最后一栏改为{{{"en:ko:ja:th:zh"}}}
----
在ChinesePack包中加了修改/root/.geany/gean.conf的程序,使得geany新建文件的默认编码为utf-8,如果默认编码是那个iso8859-1,在新文件中输入中文以后会无法保存。
----
emacs必需要用zh_CN的~LC_CTYPE才能使用中文输入法
----
puppy4上的didiwiki不能create
----
fontforge
open dejavu sans and uming
change the em of uming to unify the coordinates
merge uming to dejavu sans
rename dejavu sans to dejavu song
correct bad gryphs, such as (1)(2)
create a new font and import wqy
generate bdf(s) from the new font
import the bdf fonts to dejavu song
generate ttf with in-ttf bitmap fonts from dejavu song
----
JWM很傻,TTF内嵌的bitmap字用不了
----
Barry Kauler说:
<<<
... Essentially I just put together a lot of individual items that other people have created. Ok, it is put together in a nice way, but really there are thousands of people who are behind the creation of Puppy and I'm just one of the cogs in the machine.
<<<
老大真谦虚啊。
----
chinese_pack-0.5
* 增加[[自动挂载补丁|http://e-pup.5d6d.com/thread-358-1-1.html]]
* [[QQ群补丁|http://forum.ubuntu.org.cn/viewtopic.php?t=128169]]
* [[SeaMonkey光标跳转补丁|http://e-pup.5d6d.com/viewthread.php?tid=424]]
----
{{{
df -hx tmpfs
}}}
----
{{{
luit -encoding gbk
}}}
----
看上去以后要把[[unionfs改为aufs了|http://www.murga-linux.com/puppy/viewtopic.php?p=203922]]
----
{{{
$ echo "Hh1hH2Hh" | sed "s/./\u&/g" 
HH1HH2HH
}}}
Labrador的Linux笔记
当小狗遇上企鹅
/***
|''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);
	}
};


}
//}}}
/*{{{*/
.editor textarea { height: 35em; }
/*}}}*/
/***

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

!Demo
<<toggleSideBar "Toggle Sidebar">>

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

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

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

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

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

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

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

     return false;
}

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

//}}}
/***
Contains the stuff you need to use Tiddlyspot
Note you must also have UploadPlugin installed
***/
//{{{

// edit this if you are migrating sites or retrofitting an existing TW
config.tiddlyspotSiteId = 'labrador';

// make it so you can by default see edit controls via http
config.options.chkHttpReadOnly = false;
window.readOnly = false; // make sure of it (for tw 2.2)
window.showBackstage = true; // show backstage too

// disable autosave in d3
if (window.location.protocol != "file:")
	config.options.chkGTDLazyAutoSave = false;

// tweak shadow tiddlers to add upload button, password entry box etc
with (config.shadowTiddlers) {
	SiteUrl = 'http://'+config.tiddlyspotSiteId+'.tiddlyspot.com';
	SideBarOptions = SideBarOptions.replace(/(<<saveChanges>>)/,"$1<<tiddler TspotSidebar>>");
	OptionsPanel = OptionsPanel.replace(/^/,"<<tiddler TspotOptions>>");
	DefaultTiddlers = DefaultTiddlers.replace(/^/,"[[WelcomeToTiddlyspot]] ");
	MainMenu = MainMenu.replace(/^/,"[[WelcomeToTiddlyspot]] ");
}

// create some shadow tiddler content
merge(config.shadowTiddlers,{

'WelcomeToTiddlyspot':[
 "This document is a ~TiddlyWiki from tiddlyspot.com.  A ~TiddlyWiki is an electronic notebook that is great for managing todo lists, personal information, and all sorts of things.",
 "",
 "@@font-weight:bold;font-size:1.3em;color:#444; //What now?// &nbsp;&nbsp;@@ Before you can save any changes, you need to enter your password in the form below.  Then configure privacy and other site settings at your [[control panel|http://" + config.tiddlyspotSiteId + ".tiddlyspot.com/controlpanel]] (your control panel username is //" + config.tiddlyspotSiteId + "//).",
 "<<tiddler TspotControls>>",
 "See also GettingStarted.",
 "",
 "@@font-weight:bold;font-size:1.3em;color:#444; //Working online// &nbsp;&nbsp;@@ You can edit this ~TiddlyWiki right now, and save your changes using the \"save to web\" button in the column on the right.",
 "",
 "@@font-weight:bold;font-size:1.3em;color:#444; //Working offline// &nbsp;&nbsp;@@ A fully functioning copy of this ~TiddlyWiki can be saved onto your hard drive or USB stick.  You can make changes and save them locally without being connected to the Internet.  When you're ready to sync up again, just click \"upload\" and your ~TiddlyWiki will be saved back to tiddlyspot.com.",
 "",
 "@@font-weight:bold;font-size:1.3em;color:#444; //Help!// &nbsp;&nbsp;@@ Find out more about ~TiddlyWiki at [[TiddlyWiki.com|http://tiddlywiki.com]].  Also visit [[TiddlyWiki.org|http://tiddlywiki.org]] for documentation on learning and using ~TiddlyWiki. New users are especially welcome on the [[TiddlyWiki mailing list|http://groups.google.com/group/TiddlyWiki]], which is an excellent place to ask questions and get help.  If you have a tiddlyspot related problem email [[tiddlyspot support|mailto:support@tiddlyspot.com]].",
 "",
 "@@font-weight:bold;font-size:1.3em;color:#444; //Enjoy :)// &nbsp;&nbsp;@@ We hope you like using your tiddlyspot.com site.  Please email [[feedback@tiddlyspot.com|mailto:feedback@tiddlyspot.com]] with any comments or suggestions."
].join("\n"),

'TspotControls':[
 "| tiddlyspot password:|<<option pasUploadPassword>>|",
 "| site management:|<<upload http://" + config.tiddlyspotSiteId + ".tiddlyspot.com/store.cgi index.html . .  " + config.tiddlyspotSiteId + ">>//(requires tiddlyspot password)//<br>[[control panel|http://" + config.tiddlyspotSiteId + ".tiddlyspot.com/controlpanel]], [[download (go offline)|http://" + config.tiddlyspotSiteId + ".tiddlyspot.com/download]]|",
 "| links:|[[tiddlyspot.com|http://tiddlyspot.com/]], [[FAQs|http://faq.tiddlyspot.com/]], [[blog|http://tiddlyspot.blogspot.com/]], email [[support|mailto:support@tiddlyspot.com]] & [[feedback|mailto:feedback@tiddlyspot.com]], [[donate|http://tiddlyspot.com/?page=donate]]|"
].join("\n"),

'TspotSidebar':[
 "<<upload http://" + config.tiddlyspotSiteId + ".tiddlyspot.com/store.cgi index.html . .  " + config.tiddlyspotSiteId + ">><html><a href='http://" + config.tiddlyspotSiteId + ".tiddlyspot.com/download' class='button'>download</a></html>"
].join("\n"),

'TspotOptions':[
 "tiddlyspot password:",
 "<<option pasUploadPassword>>",
 ""
].join("\n")

});
//}}}
| !date | !user | !location | !storeUrl | !uploadDir | !toFilename | !backupdir | !origin |
| 03/06/2008 11:10:59 | Labrador | [[/|http://labrador.tiddlyspot.com/]] | [[store.cgi|http://labrador.tiddlyspot.com/store.cgi]] | . | [[index.html | http://labrador.tiddlyspot.com/index.html]] | . |
| 03/06/2008 22:54:26 | Labrador | [[/|http://labrador.tiddlyspot.com/]] | [[store.cgi|http://labrador.tiddlyspot.com/store.cgi]] | . | [[index.html | http://labrador.tiddlyspot.com/index.html]] | . |
| 04/06/2008 19:05:07 | Labrador | [[/|http://labrador.tiddlyspot.com/]] | [[store.cgi|http://labrador.tiddlyspot.com/store.cgi]] | . | [[index.html | http://labrador.tiddlyspot.com/index.html]] | . |
| 04/06/2008 22:33:29 | Labrador | [[/|http://labrador.tiddlyspot.com/]] | [[store.cgi|http://labrador.tiddlyspot.com/store.cgi]] | . | [[index.html | http://labrador.tiddlyspot.com/index.html]] | . | ok |
| 04/06/2008 22:52:02 | Labrador | [[/|http://labrador.tiddlyspot.com/]] | [[store.cgi|http://labrador.tiddlyspot.com/store.cgi]] | . | [[index.html | http://labrador.tiddlyspot.com/index.html]] | . |
| 10/06/2008 20:09:12 | Labrador | [[/|http://labrador.tiddlyspot.com/]] | [[store.cgi|http://labrador.tiddlyspot.com/store.cgi]] | . | [[index.html | http://labrador.tiddlyspot.com/index.html]] | . |
| 14/06/2008 00:34:51 | Labrador | [[/|http://labrador.tiddlyspot.com/]] | [[store.cgi|http://labrador.tiddlyspot.com/store.cgi]] | . | [[index.html | http://labrador.tiddlyspot.com/index.html]] | . |
| 20/06/2008 00:49:30 | Labrador | [[/|http://labrador.tiddlyspot.com/#BashGettext%20PuppyLinux]] | [[store.cgi|http://labrador.tiddlyspot.com/store.cgi]] | . | [[index.html | http://labrador.tiddlyspot.com/index.html]] | . |
| 24/06/2008 01:44:35 | Labrador | [[/|http://labrador.tiddlyspot.com/]] | [[store.cgi|http://labrador.tiddlyspot.com/store.cgi]] | . | [[index.html | http://labrador.tiddlyspot.com/index.html]] | . |
| 06/07/2008 13:50:45 | Labrador | [[/|http://labrador.tiddlyspot.com/]] | [[store.cgi|http://labrador.tiddlyspot.com/store.cgi]] | . | [[index.html | http://labrador.tiddlyspot.com/index.html]] | . |
/***
|''Name:''|PasswordOptionPlugin|
|''Description:''|Extends TiddlyWiki options with non encrypted password option.|
|''Version:''|1.0.2|
|''Date:''|Apr 19, 2007|
|''Source:''|http://tiddlywiki.bidix.info/#PasswordOptionPlugin|
|''Author:''|BidiX (BidiX (at) bidix (dot) info)|
|''License:''|[[BSD open source license|http://tiddlywiki.bidix.info/#%5B%5BBSD%20open%20source%20license%5D%5D ]]|
|''~CoreVersion:''|2.2.0 (Beta 5)|
***/
//{{{
version.extensions.PasswordOptionPlugin = {
	major: 1, minor: 0, revision: 2, 
	date: new Date("Apr 19, 2007"),
	source: 'http://tiddlywiki.bidix.info/#PasswordOptionPlugin',
	author: 'BidiX (BidiX (at) bidix (dot) info',
	license: '[[BSD open source license|http://tiddlywiki.bidix.info/#%5B%5BBSD%20open%20source%20license%5D%5D]]',
	coreVersion: '2.2.0 (Beta 5)'
};

config.macros.option.passwordCheckboxLabel = "Save this password on this computer";
config.macros.option.passwordInputType = "password"; // password | text
setStylesheet(".pasOptionInput {width: 11em;}\n","passwordInputTypeStyle");

merge(config.macros.option.types, {
	'pas': {
		elementType: "input",
		valueField: "value",
		eventName: "onkeyup",
		className: "pasOptionInput",
		typeValue: config.macros.option.passwordInputType,
		create: function(place,type,opt,className,desc) {
			// password field
			config.macros.option.genericCreate(place,'pas',opt,className,desc);
			// checkbox linked with this password "save this password on this computer"
			config.macros.option.genericCreate(place,'chk','chk'+opt,className,desc);			
			// text savePasswordCheckboxLabel
			place.appendChild(document.createTextNode(config.macros.option.passwordCheckboxLabel));
		},
		onChange: config.macros.option.genericOnChange
	}
});

merge(config.optionHandlers['chk'], {
	get: function(name) {
		// is there an option linked with this chk ?
		var opt = name.substr(3);
		if (config.options[opt]) 
			saveOptionCookie(opt);
		return config.options[name] ? "true" : "false";
	}
});

merge(config.optionHandlers, {
	'pas': {
 		get: function(name) {
			if (config.options["chk"+name]) {
				return encodeCookie(config.options[name].toString());
			} else {
				return "";
			}
		},
		set: function(name,value) {config.options[name] = decodeCookie(value);}
	}
});

// need to reload options to load passwordOptions
loadOptionsCookie();

/*
if (!config.options['pasPassword'])
	config.options['pasPassword'] = '';

merge(config.optionsDesc,{
		pasPassword: "Test password"
	});
*/
//}}}

/***
|''Name:''|UploadPlugin|
|''Description:''|Save to web a TiddlyWiki|
|''Version:''|4.1.0|
|''Date:''|May 5, 2007|
|''Source:''|http://tiddlywiki.bidix.info/#UploadPlugin|
|''Documentation:''|http://tiddlywiki.bidix.info/#UploadPluginDoc|
|''Author:''|BidiX (BidiX (at) bidix (dot) info)|
|''License:''|[[BSD open source license|http://tiddlywiki.bidix.info/#%5B%5BBSD%20open%20source%20license%5D%5D ]]|
|''~CoreVersion:''|2.2.0 (#3125)|
|''Requires:''|PasswordOptionPlugin|
***/
//{{{
version.extensions.UploadPlugin = {
	major: 4, minor: 1, revision: 0,
	date: new Date("May 5, 2007"),
	source: 'http://tiddlywiki.bidix.info/#UploadPlugin',
	author: 'BidiX (BidiX (at) bidix (dot) info',
	coreVersion: '2.2.0 (#3125)'
};

//
// Environment
//

if (!window.bidix) window.bidix = {}; // bidix namespace
bidix.debugMode = false;	// true to activate both in Plugin and UploadService
	
//
// Upload Macro
//

config.macros.upload = {
// default values
	defaultBackupDir: '',	//no backup
	defaultStoreScript: "store.php",
	defaultToFilename: "index.html",
	defaultUploadDir: ".",
	authenticateUser: true	// UploadService Authenticate User
};
	
config.macros.upload.label = {
	promptOption: "Save and Upload this TiddlyWiki with UploadOptions",
	promptParamMacro: "Save and Upload this TiddlyWiki in %0",
	saveLabel: "save to web", 
	saveToDisk: "save to disk",
	uploadLabel: "upload"	
};

config.macros.upload.messages = {
	noStoreUrl: "No store URL in parmeters or options",
	usernameOrPasswordMissing: "Username or password missing"
};

config.macros.upload.handler = function(place,macroName,params) {
	if (readOnly)
		return;
	var label;
	if (document.location.toString().substr(0,4) == "http") 
		label = this.label.saveLabel;
	else
		label = this.label.uploadLabel;
	var prompt;
	if (params[0]) {
		prompt = this.label.promptParamMacro.toString().format([this.destFile(params[0], 
			(params[1] ? params[1]:bidix.basename(window.location.toString())), params[3])]);
	} else {
		prompt = this.label.promptOption;
	}
	createTiddlyButton(place, label, prompt, function() {config.macros.upload.action(params);}, null, null, this.accessKey);
};

config.macros.upload.action = function(params)
{
		// for missing macro parameter set value from options
		var storeUrl = params[0] ? params[0] : config.options.txtUploadStoreUrl;
		var toFilename = params[1] ? params[1] : config.options.txtUploadFilename;
		var backupDir = params[2] ? params[2] : config.options.txtUploadBackupDir;
		var uploadDir = params[3] ? params[3] : config.options.txtUploadDir;
		var username = params[4] ? params[4] : config.options.txtUploadUserName;
		var password = config.options.pasUploadPassword; // for security reason no password as macro parameter	
		// for still missing parameter set default value
		if ((!storeUrl) && (document.location.toString().substr(0,4) == "http")) 
			storeUrl = bidix.dirname(document.location.toString())+'/'+config.macros.upload.defaultStoreScript;
		if (storeUrl.substr(0,4) != "http")
			storeUrl = bidix.dirname(document.location.toString()) +'/'+ storeUrl;
		if (!toFilename)
			toFilename = bidix.basename(window.location.toString());
		if (!toFilename)
			toFilename = config.macros.upload.defaultToFilename;
		if (!uploadDir)
			uploadDir = config.macros.upload.defaultUploadDir;
		if (!backupDir)
			backupDir = config.macros.upload.defaultBackupDir;
		// report error if still missing
		if (!storeUrl) {
			alert(config.macros.upload.messages.noStoreUrl);
			clearMessage();
			return false;
		}
		if (config.macros.upload.authenticateUser && (!username || !password)) {
			alert(config.macros.upload.messages.usernameOrPasswordMissing);
			clearMessage();
			return false;
		}
		bidix.upload.uploadChanges(false,null,storeUrl, toFilename, uploadDir, backupDir, username, password); 
		return false; 
};

config.macros.upload.destFile = function(storeUrl, toFilename, uploadDir) 
{
	if (!storeUrl)
		return null;
		var dest = bidix.dirname(storeUrl);
		if (uploadDir && uploadDir != '.')
			dest = dest + '/' + uploadDir;
		dest = dest + '/' + toFilename;
	return dest;
};

//
// uploadOptions Macro
//

config.macros.uploadOptions = {
	handler: function(place,macroName,params) {
		var wizard = new Wizard();
		wizard.createWizard(place,this.wizardTitle);
		wizard.addStep(this.step1Title,this.step1Html);
		var markList = wizard.getElement("markList");
		var listWrapper = document.createElement("div");
		markList.parentNode.insertBefore(listWrapper,markList);
		wizard.setValue("listWrapper",listWrapper);
		this.refreshOptions(listWrapper,false);
		var uploadCaption;
		if (document.location.toString().substr(0,4) == "http") 
			uploadCaption = config.macros.upload.label.saveLabel;
		else
			uploadCaption = config.macros.upload.label.uploadLabel;
		
		wizard.setButtons([
				{caption: uploadCaption, tooltip: config.macros.upload.label.promptOption, 
					onClick: config.macros.upload.action},
				{caption: this.cancelButton, tooltip: this.cancelButtonPrompt, onClick: this.onCancel}
				
			]);
	},
	refreshOptions: function(listWrapper) {
		var uploadOpts = [
			"txtUploadUserName",
			"pasUploadPassword",
			"txtUploadStoreUrl",
			"txtUploadDir",
			"txtUploadFilename",
			"txtUploadBackupDir",
			"chkUploadLog",
			"txtUploadLogMaxLine",
			]
		var opts = [];
		for(i=0; i<uploadOpts.length; i++) {
			var opt = {};
			opts.push()
			opt.option = "";
			n = uploadOpts[i];
			opt.name = n;
			opt.lowlight = !config.optionsDesc[n];
			opt.description = opt.lowlight ? this.unknownDescription : config.optionsDesc[n];
			opts.push(opt);
		}
		var listview = ListView.create(listWrapper,opts,this.listViewTemplate);
		for(n=0; n<opts.length; n++) {
			var type = opts[n].name.substr(0,3);
			var h = config.macros.option.types[type];
			if (h && h.create) {
				h.create(opts[n].colElements['option'],type,opts[n].name,opts[n].name,"no");
			}
		}
		
	},
	onCancel: function(e)
	{
		backstage.switchTab(null);
		return false;
	},
	
	wizardTitle: "Upload with options",
	step1Title: "These options are saved in cookies in your browser",
	step1Html: "<input type='hidden' name='markList'></input><br>",
	cancelButton: "Cancel",
	cancelButtonPrompt: "Cancel prompt",
	listViewTemplate: {
		columns: [
			{name: 'Description', field: 'description', title: "Description", type: 'WikiText'},
			{name: 'Option', field: 'option', title: "Option", type: 'String'},
			{name: 'Name', field: 'name', title: "Name", type: 'String'}
			],
		rowClasses: [
			{className: 'lowlight', field: 'lowlight'} 
			]}
}

//
// upload functions
//

if (!bidix.upload) bidix.upload = {};

if (!bidix.upload.messages) bidix.upload.messages = {
	//from saving
	invalidFileError: "The original file '%0' does not appear to be a valid TiddlyWiki",
	backupSaved: "Backup saved",
	backupFailed: "Failed to upload backup file",
	rssSaved: "RSS feed uploaded",
	rssFailed: "Failed to upload RSS feed file",
	emptySaved: "Empty template uploaded",
	emptyFailed: "Failed to upload empty template file",
	mainSaved: "Main TiddlyWiki file uploaded",
	mainFailed: "Failed to upload main TiddlyWiki file. Your changes have not been saved",
	//specific upload
	loadOriginalHttpPostError: "Can't get original file",
	aboutToSaveOnHttpPost: 'About to upload on %0 ...',
	storePhpNotFound: "The store script '%0' was not found."
};

bidix.upload.uploadChanges = function(onlyIfDirty,tiddlers,storeUrl,toFilename,uploadDir,backupDir,username,password)
{
	var callback = function(status,uploadParams,original,url,xhr) {
		if (!status) {
			displayMessage(bidix.upload.messages.loadOriginalHttpPostError);
			return;
		}
		if (bidix.debugMode) 
			alert(original.substr(0,500)+"\n...");
		// Locate the storeArea div's 
		var posDiv = locateStoreArea(original);
		if((posDiv[0] == -1) || (posDiv[1] == -1)) {
			alert(config.messages.invalidFileError.format([localPath]));
			return;
		}
		bidix.upload.uploadRss(uploadParams,original,posDiv);
	};
	
	if(onlyIfDirty && !store.isDirty())
		return;
	clearMessage();
	// save on localdisk ?
	if (document.location.toString().substr(0,4) == "file") {
		var path = document.location.toString();
		var localPath = getLocalPath(path);
		saveChanges();
	}
	// get original
	var uploadParams = Array(storeUrl,toFilename,uploadDir,backupDir,username,password);
	var originalPath = document.location.toString();
	// If url is a directory : add index.html
	if (originalPath.charAt(originalPath.length-1) == "/")
		originalPath = originalPath + "index.html";
	var dest = config.macros.upload.destFile(storeUrl,toFilename,uploadDir);
	var log = new bidix.UploadLog();
	log.startUpload(storeUrl, dest, uploadDir,  backupDir);
	displayMessage(bidix.upload.messages.aboutToSaveOnHttpPost.format([dest]));
	if (bidix.debugMode) 
		alert("about to execute Http - GET on "+originalPath);
	var r = doHttp("GET",originalPath,null,null,null,null,callback,uploadParams,null);
	if (typeof r == "string")
		displayMessage(r);
	return r;
};

bidix.upload.uploadRss = function(uploadParams,original,posDiv) 
{
	var callback = function(status,params,responseText,url,xhr) {
		if(status) {
			var destfile = responseText.substring(responseText.indexOf("destfile:")+9,responseText.indexOf("\n", responseText.indexOf("destfile:")));
			displayMessage(bidix.upload.messages.rssSaved,bidix.dirname(url)+'/'+destfile);
			bidix.upload.uploadMain(params[0],params[1],params[2]);
		} else {
			displayMessage(bidix.upload.messages.rssFailed);			
		}
	};
	// do uploadRss
	if(config.options.chkGenerateAnRssFeed) {
		var rssPath = uploadParams[1].substr(0,uploadParams[1].lastIndexOf(".")) + ".xml";
		var rssUploadParams = Array(uploadParams[0],rssPath,uploadParams[2],'',uploadParams[4],uploadParams[5]);
		bidix.upload.httpUpload(rssUploadParams,convertUnicodeToUTF8(generateRss()),callback,Array(uploadParams,original,posDiv));
	} else {
		bidix.upload.uploadMain(uploadParams,original,posDiv);
	}
};

bidix.upload.uploadMain = function(uploadParams,original,posDiv) 
{
	var callback = function(status,params,responseText,url,xhr) {
		var log = new bidix.UploadLog();
		if(status) {
			// if backupDir specified
			if ((params[3]) && (responseText.indexOf("backupfile:") > -1))  {
				var backupfile = responseText.substring(responseText.indexOf("backupfile:")+11,responseText.indexOf("\n", responseText.indexOf("backupfile:")));
				displayMessage(bidix.upload.messages.backupSaved,bidix.dirname(url)+'/'+backupfile);
			}
			var destfile = responseText.substring(responseText.indexOf("destfile:")+9,responseText.indexOf("\n", responseText.indexOf("destfile:")));
			displayMessage(bidix.upload.messages.mainSaved,bidix.dirname(url)+'/'+destfile);
			store.setDirty(false);
			log.endUpload("ok");
		} else {
			alert(bidix.upload.messages.mainFailed);
			displayMessage(bidix.upload.messages.mainFailed);
			log.endUpload("failed");			
		}
	};
	// do uploadMain
	var revised = bidix.upload.updateOriginal(original,posDiv);
	bidix.upload.httpUpload(uploadParams,revised,callback,uploadParams);
};

bidix.upload.httpUpload = function(uploadParams,data,callback,params)
{
	var localCallback = function(status,params,responseText,url,xhr) {
		url = (url.indexOf("nocache=") < 0 ? url : url.substring(0,url.indexOf("nocache=")-1));
		if (xhr.status == httpStatus.NotFound)
			alert(bidix.upload.messages.storePhpNotFound.format([url]));
		if ((bidix.debugMode) || (responseText.indexOf("Debug mode") >= 0 )) {
			alert(responseText);
			if (responseText.indexOf("Debug mode") >= 0 )
				responseText = responseText.substring(responseText.indexOf("\n\n")+2);
		} else if (responseText.charAt(0) != '0') 
			alert(responseText);
		if (responseText.charAt(0) != '0')
			status = null;
		callback(status,params,responseText,url,xhr);
	};
	// do httpUpload
	var boundary = "---------------------------"+"AaB03x";	
	var uploadFormName = "UploadPlugin";
	// compose headers data
	var sheader = "";
	sheader += "--" + boundary + "\r\nContent-disposition: form-data; name=\"";
	sheader += uploadFormName +"\"\r\n\r\n";
	sheader += "backupDir="+uploadParams[3] +
				";user=" + uploadParams[4] +
				";password=" + uploadParams[5] +
				";uploaddir=" + uploadParams[2];
	if (bidix.debugMode)
		sheader += ";debug=1";
	sheader += ";;\r\n"; 
	sheader += "\r\n" + "--" + boundary + "\r\n";
	sheader += "Content-disposition: form-data; name=\"userfile\"; filename=\""+uploadParams[1]+"\"\r\n";
	sheader += "Content-Type: text/html;charset=UTF-8" + "\r\n";
	sheader += "Content-Length: " + data.length + "\r\n\r\n";
	// compose trailer data
	var strailer = new String();
	strailer = "\r\n--" + boundary + "--\r\n";
	data = sheader + data + strailer;
	if (bidix.debugMode) alert("about to execute Http - POST on "+uploadParams[0]+"\n with \n"+data.substr(0,500)+ " ... ");
	var r = doHttp("POST",uploadParams[0],data,"multipart/form-data; boundary="+boundary,uploadParams[4],uploadParams[5],localCallback,params,null);
	if (typeof r == "string")
		displayMessage(r);
	return r;
};

// same as Saving's updateOriginal but without convertUnicodeToUTF8 calls
bidix.upload.updateOriginal = function(original, posDiv)
{
	if (!posDiv)
		posDiv = locateStoreArea(original);
	if((posDiv[0] == -1) || (posDiv[1] == -1)) {
		alert(config.messages.invalidFileError.format([localPath]));
		return;
	}
	var revised = original.substr(0,posDiv[0] + startSaveArea.length) + "\n" +
				store.allTiddlersAsHtml() + "\n" +
				original.substr(posDiv[1]);
	var newSiteTitle = getPageTitle().htmlEncode();
	revised = revised.replaceChunk("<title"+">","</title"+">"," " + newSiteTitle + " ");
	revised = updateMarkupBlock(revised,"PRE-HEAD","MarkupPreHead");
	revised = updateMarkupBlock(revised,"POST-HEAD","MarkupPostHead");
	revised = updateMarkupBlock(revised,"PRE-BODY","MarkupPreBody");
	revised = updateMarkupBlock(revised,"POST-SCRIPT","MarkupPostBody");
	return revised;
};

//
// UploadLog
// 
// config.options.chkUploadLog :
//		false : no logging
//		true : logging
// config.options.txtUploadLogMaxLine :
//		-1 : no limit
//      0 :  no Log lines but UploadLog is still in place
//		n :  the last n lines are only kept
//		NaN : no limit (-1)

bidix.UploadLog = function() {
	if (!config.options.chkUploadLog) 
		return; // this.tiddler = null
	this.tiddler = store.getTiddler("UploadLog");
	if (!this.tiddler) {
		this.tiddler = new Tiddler();
		this.tiddler.title = "UploadLog";
		this.tiddler.text = "| !date | !user | !location | !storeUrl | !uploadDir | !toFilename | !backupdir | !origin |";
		this.tiddler.created = new Date();
		this.tiddler.modifier = config.options.txtUserName;
		this.tiddler.modified = new Date();
		store.addTiddler(this.tiddler);
	}
	return this;
};

bidix.UploadLog.prototype.addText = function(text) {
	if (!this.tiddler)
		return;
	// retrieve maxLine when we need it
	var maxLine = parseInt(config.options.txtUploadLogMaxLine,10);
	if (isNaN(maxLine))
		maxLine = -1;
	// add text
	if (maxLine != 0) 
		this.tiddler.text = this.tiddler.text + text;
	// Trunck to maxLine
	if (maxLine >= 0) {
		var textArray = this.tiddler.text.split('\n');
		if (textArray.length > maxLine + 1)
			textArray.splice(1,textArray.length-1-maxLine);
			this.tiddler.text = textArray.join('\n');		
	}
	// update tiddler fields
	this.tiddler.modifier = config.options.txtUserName;
	this.tiddler.modified = new Date();
	store.addTiddler(this.tiddler);
	// refresh and notifiy for immediate update
	story.refreshTiddler(this.tiddler.title);
	store.notify(this.tiddler.title, true);
};

bidix.UploadLog.prototype.startUpload = function(storeUrl, toFilename, uploadDir,  backupDir) {
	if (!this.tiddler)
		return;
	var now = new Date();
	var text = "\n| ";
	var filename = bidix.basename(document.location.toString());
	if (!filename) filename = '/';
	text += now.formatString("0DD/0MM/YYYY 0hh:0mm:0ss") +" | ";
	text += config.options.txtUserName + " | ";
	text += "[["+filename+"|"+location + "]] |";
	text += " [[" + bidix.basename(storeUrl) + "|" + storeUrl + "]] | ";
	text += uploadDir + " | ";
	text += "[[" + bidix.basename(toFilename) + " | " +toFilename + "]] | ";
	text += backupDir + " |";
	this.addText(text);
};

bidix.UploadLog.prototype.endUpload = function(status) {
	if (!this.tiddler)
		return;
	this.addText(" "+status+" |");
};

//
// Utilities
// 

bidix.checkPlugin = function(plugin, major, minor, revision) {
	var ext = version.extensions[plugin];
	if (!
		(ext  && 
			((ext.major > major) || 
			((ext.major == major) && (ext.minor > minor))  ||
			((ext.major == major) && (ext.minor == minor) && (ext.revision >= revision))))) {
			// write error in PluginManager
			if (pluginInfo)
				pluginInfo.log.push("Requires " + plugin + " " + major + "." + minor + "." + revision);
			eval(plugin); // generate an error : "Error: ReferenceError: xxxx is not defined"
	}
};

bidix.dirname = function(filePath) {
	if (!filePath) 
		return;
	var lastpos;
	if ((lastpos = filePath.lastIndexOf("/")) != -1) {
		return filePath.substring(0, lastpos);
	} else {
		return filePath.substring(0, filePath.lastIndexOf("\\"));
	}
};

bidix.basename = function(filePath) {
	if (!filePath) 
		return;
	var lastpos;
	if ((lastpos = filePath.lastIndexOf("#")) != -1) 
		filePath = filePath.substring(0, lastpos);
	if ((lastpos = filePath.lastIndexOf("/")) != -1) {
		return filePath.substring(lastpos + 1);
	} else
		return filePath.substring(filePath.lastIndexOf("\\")+1);
};

bidix.initOption = function(name,value) {
	if (!config.options[name])
		config.options[name] = value;
};

//
// Initializations
//

// require PasswordOptionPlugin 1.0.1 or better
bidix.checkPlugin("PasswordOptionPlugin", 1, 0, 1);

// styleSheet
setStylesheet('.txtUploadStoreUrl, .txtUploadBackupDir, .txtUploadDir {width: 22em;}',"uploadPluginStyles");

//optionsDesc
merge(config.optionsDesc,{
	txtUploadStoreUrl: "Url of the UploadService script (default: store.php)",
	txtUploadFilename: "Filename of the uploaded file (default: in index.html)",
	txtUploadDir: "Relative Directory where to store the file (default: . (downloadService directory))",
	txtUploadBackupDir: "Relative Directory where to backup the file. If empty no backup. (default: ''(empty))",
	txtUploadUserName: "Upload Username",
	pasUploadPassword: "Upload Password",
	chkUploadLog: "do Logging in UploadLog (default: true)",
	txtUploadLogMaxLine: "Maximum of lines in UploadLog (default: 10)"
});

// Options Initializations
bidix.initOption('txtUploadStoreUrl','');
bidix.initOption('txtUploadFilename','');
bidix.initOption('txtUploadDir','');
bidix.initOption('txtUploadBackupDir','');
bidix.initOption('txtUploadUserName','');
bidix.initOption('pasUploadPassword','');
bidix.initOption('chkUploadLog',true);
bidix.initOption('txtUploadLogMaxLine','10');


/* don't want this for tiddlyspot sites

// Backstage
merge(config.tasks,{
	uploadOptions: {text: "upload", tooltip: "Change UploadOptions and Upload", content: '<<uploadOptions>>'}
});
config.backstageTasks.push("uploadOptions");

*/


//}}}


为PuppyLinux 4.0 (kernel 2.6.21)制作的~VirtualBox Guest Addition包。其他版本的我没有试过,不过因为这个东西和内核相关,所以其他PuppyLinux多半用不了。安装完成之后,会提示设置分辨率,然后重启一下X就可以用了。

''目前可以用的功能:''
* 使用host机器上共享的硬盘,使用方法:
{{{
mount -t vboxsf <共享名> <本地目录>
}}}
* 鼠标可以自由出入vbox窗口
* 自动与host同步时间

''还不能用的功能:''
* 自动改变X尺寸。这有两方面原因,一是~VBoxClient表现不太正常,重启X后它不能退出,而且会占用100%的cpu,所以我没让它默认启动;二是jwm还不能支持~RandR,改变屏幕尺寸以后panel不会自动改变位置。
* 不能使用剪贴板共享,因为没有运行~VBoxClient

这个包可以在[[这里|http://www.fs2you.com/files/fc7ace63-1f1d-11dd-be99-00142218fc6e/]]下载。相关技术细节请看VBoxAddDetail
介绍一下[[virtualbox-guest-addition-1.6.0.1包|VBoxAdd]]的一些技术细节。

! ~VirtualBox安装程序
很可惜,这个程序在PuppyLinux下运行的不好,需要做大量的修改。为了编译~VirtualBox的内核模块,需要找来[[PuppyLinux 4.0所使用的内核|http://www.kernel.org/pub/linux/kernel/v2.6/linux-2.6.21.7.tar.bz2]]。解压到{{{/usr/src/linux-2.6.21.7/}}}目录中,并建立一个符号连接{{{/usr/src/linux}}}指向这个目录。然后运行
{{{
make scripts
}}}
接着再安装一个[[kernel头文件包|http://distro.ibiblio.org/pub/linux/distributions/puppylinux/pet_packages-4/linux-header-2.6.19.1.pet]](很多软件编译都需要这个包),之后~VirtualBox就可以正确编译内核模块了。但安装时还会出不少问题。由于当时没有记录,我现在有点记不请楚了。我记得有个比较大的问题是~VirtualBox没有办法建立一个vboxadd组,我直接修改了~VirtualBox的脚本,让它用root组替代。要从~VirtualBox的安装程序中解开所有的脚本,在运行那个程序时加参数{{{--keep --noexec}}}(?)。另外,{{{/var/log/}}}中会有~VirtualBox的安装log,非常有帮助。

install.sh的patch
{{{
diff -uN install/install.sh install_modified/install.sh
--- install/install.sh	2008-05-30 22:00:56.000000000 -0400
+++ install_modified/install.sh	2008-06-06 14:52:16.000000000 -0400
@@ -16,7 +16,7 @@
 
 # Find the version of X installed
 # The last of the three is for the X.org 6.7 included in Fedora Core 2
-xver=`X -version 2>&1`
+xver=`Xorg -version 2>&1`
 x_version=`echo "$xver" | sed -n 's/^X Window System Version \([0-9.]\+\)/\1/p'``echo "$xver" | sed -n 's/^XFree86 Version \([0-9.]\+\)/\1/p'``echo "$xver" | sed -n 's/^X Protocol Version 11, Revision 0, Release \([0-9.]\+\)/\1/p'``echo "$xver" | sed -n 's/^X.Org X Server \([0-9.]\+\)/\1/p'`
 # Version of Redhat or Fedora installed.  Needed for setting up selinux policy.
 redhat_release=`cat /etc/redhat-release 2> /dev/null`
@@ -305,7 +305,7 @@
 if [ "$install_x11" != "" ]; then
     log "Installing the X Window System user service."
     install -o 0 -g 0 -m 0755 VBoxClient /usr/bin/VBoxClient
-    chown vboxadd:1 /usr/bin/VBoxClient
+    chown root:root /usr/bin/VBoxClient
     chmod 04755 /usr/bin/VBoxClient
     install -o 0 -g 0 -m 0755 VBoxRandR.sh /usr/bin/VBoxRandR
     if [ ! -z "$x_version" ]; then
Common subdirectories: install/module and install_modified/module
diff -uN install/vboxadd.sh install_modified/vboxadd.sh
--- install/vboxadd.sh	2008-05-30 22:00:56.000000000 -0400
+++ install_modified/vboxadd.sh	2008-06-06 14:43:17.000000000 -0400
@@ -113,8 +113,8 @@
 dev=/dev/vboxadd
 modname=vboxadd
 module=$kdir/$modname
-owner=vboxadd
-group=1
+owner=root
+group=root
 
 fail() {
     if [ "$system" = "gentoo" ]; then
}}}

最后一阵折腾我们可以得到下面几个文件:
{{{
/etc/rc.d/rc.vboxadd
/etc/rc.d/rc.vboxvfs
/etc/rc.d/rc.vboxadd-timesync
/sbin/mount.vboxsf
/usr/bin/VBoxRandR
/usr/bin/VBoxClient
/usr/sbin/vboxadd-timesync
/usr/lib/xorg/modules/drivers/vboxvideo_drv.so
/usr/lib/xorg/modules/input/vboxmouse_drv.so
/lib/modules/2.6.21.7/misc/vboxadd.ko
/lib/modules/2.6.21.7/misc/vboxvfs.ko
}}}
其中前三个文件{{{/etc/rc.d/rc.*}}}需要被修改以支持PuppyLinux。相应的我还修改了PuppyLinux自带的{{{/etc/rc.d/functions}}},因为这个脚本有个bug,它运行pidof命令时指定了错误的目录。这可能是因为过去版本的PuppyLinux确实把pidof放在那个目录,而修改后由于其他启动脚本都不需要这个脚本,以至于没人发现这个bug。

! X系统所需要做的修改
vboxvideo驱动依赖于{{{/usr/lib/xorg/modules/libshadowfb.so}}},但这个文件在默认安装的PuppyLinux中没有,它可以在[[这里|http://www.puppylinux.ca/ttuuxxx/Libs/xorg/modules/libshadowfb.so]]下载。

另外还需要将{{{/usr/X11R7/bin/X}}}指向Xorg,在没有装vboxvideo驱动之前,Xorg是不能启动的,所以原来这个文件肯定是指向Xvesa的。最后将{{{/etc/X11/xorg.conf}}}文件的Device部分的Driver设为vboxvideo,并且这个文件中必须包含一行
{{{
#PuppyHardwareProfile=VirtualBox_VBE_BIOS
}}}
否则xwin会自动去重新构建一个xorg.conf文件,导致X启动失败。
|''PuppyLinux用的软件包''|c
|[[VirtualBox Guest Additions|VBoxAdd]]|
|[[中文支持|ChinesePack]]|
|[[更多中文支持|ChinesePackExtra]]|
PuppyLinux是一个小型化的Linux发行版。它小巧身材下包含了多种常用软件,可以满足一般应用的需要。其运行速度也非常惊人,大部分附带的程序都可以在弹指之间启动完成。另外,它可以被很方便的安装到许多不同种类的介质上启动运行。
有关软件翻译技术的一些文章