Skip to content

twitter 和 friendfeed 同时下线

08-五-09

5/8/2009 对于依赖非 IM 即时通讯的网上用户来说,是黑色的一天。

twitter 计划在这一天的本地时间(PDT)2:00pm 进行一小时的下线维护。twitter 的服务器一直不很稳定,时常有连不上的问题,遇到这种情况,很多 twitter 用户会使用  friendfeed 来互通消息。

不幸的是,这一天 twitter 并未能在一小时后准时上线,3:oopm 以后,friendfeed 也掉线了,网站完全失去响应。用户在两个即时通讯服务均下线的情况下,体验到了无法获取准确消息的黑暗期。

4:10pm 过后,twitter 用户在连线状况非常糟糕的情况下,终于收到来自了 friendfeed 官方高层的消息,Paul Buchheit (@paultoo)  宣布 friendfeed 下线是因为服务器所在的数据中心停电(“The entire svcolo datacenter lost power. They expect to have it restored in 10min, but it will take at bit to bring up all systems.”)

一个技术论坛上技术含量最高的文章

03-四-09

工作需要为 VMWare Virtual Center 写一些接口模块,而 VMWare 不支持我们使用的编程语言,不得不在网上拼命 Google 碰到的出错信息,搜索结果列出了一个 vmware.cn 网站,我以为是中国 VMWare 的官方技术论坛,就注了册进去看看。

进去以后觉得不太对,网站论坛里面充斥着很多找 VMWare 软件破解或者许可的帖子,想想中国的实际情况也见怪不怪,于是直奔论坛的高级板块 “ VMWARE企业高级应用 ”,去读置顶 FAQ。

置顶 FAQ 是该论坛板块的版主写的,开始部分是到哪里下载软件,如何破解,这也都无可厚非。

但其中一句话引起我的注意:

“我一直都认为这个贴,是论坛最精华,技术含量最高的贴。”

各位看官,说的这个帖子是什么呢?原来是一个名叫“VI3 (ESX3) 破解/授权历史回顾”的帖子,有兴趣的话可以看看:

http://bbs.vmware.cn/thread-10155-1-1.html

这个帖子的技术含量到底有多足我就不评价了,但是这样一个帖子居然是论坛最精华、技术含量最高的帖(而且“一直”说明了这个结论是经过时间考验的),那么这个论坛的技术含量我也就不敢抱太多希望了。

快速建立 ipv6 安全管道访问 ipv6 网站

29-三-09

目前有很多网站支持 ipv6 连接,比如

http://ipv6.google.com

但对大部分人来说,这个网址是不能访问的,因为没有设置好 ipv6 。目前 ISP 很少提供 ipv6 连接,用户一般需要使用 ipv6 tunnel broker 来建立管道来访问 ipv6 站点。

在 Linux 下这个工作很简单,以 Debian 为例,安装 miredo 包(包的名字是”多来咪”反过来):

# sudo apt-get install miredo

后输入

# /sbin/ifconfig

看到 teredo 这个虚拟网卡就可以用它访问 ipv6 了:

# ping6 ipv6.google.com

PING ipv6.google.com(2001:4860:b002::68) 56 data bytes
64 bytes from 2001:4860:b002::68: icmp_seq=1 ttl=56 time=874 ms
64 bytes from 2001:4860:b002::68: icmp_seq=2 ttl=56 time=322 ms
现在应该可以访问  http://ipv6.google.com 了,如果成功访问的话,你会看到在 ipv4 下面熟悉的 Google 搜索界面,但 Google Logo 是动画的。

使用 sixxs.org 提供的 ipv4/ipv6 交换门,可以实现在 ipv4 环境下访问 ipv6 站点,或者在 ipv6 环境下访问 ipv4 站点,方法是:

. ipv4 环境下,在 ipv6 网站后面添加 .ipv4.sixxs.org:

http://ipv6.google.com/   —>   http://ipv6.google.com.ipv4.sixxs.org/

而在 ipv6 环境下,在 ipv4 网站后面添加 sixxs.org 或者 .ipv6.sixxs.org:

http://wikipedia.org/   —>   http://wikipedia.org.sixxs.org/

从理论上来说,所有正常使用 80 端口的 ipv4 网站均可以在 ipv6 环境下使用 ipv6交换门来访问。

这台安装并能正确访问 ipv6 的 Linux 机器,可以安装 polipo (支持 ipv6 的代理)后让不支持 ipv6 的 Windows 系统访问 ipv6 站点:

# sudo apt-get install polipo

# vi /etc/polipo/config

找到 proxyAddress 改成允许 Windows 系统访问即可:

proxyAddress=”0.0.0.0″

#sudo /etc/init.d/polipo restart

polipo 的默认端口是 8123,把 Windows 系统的代理改成 LinuxIP:8123 就可以访问 ipv6 站点了。

全部使用 https:// 协议的 TwitterFox

19-三-09

TwitterFox 是个 Firefox 扩展,据作者说,TwitterFox 和 twitter 服务器之间均为加密通讯,但查看 TwitterFox 的源程序,里面仍有几处直接使用  http:// 协议连接 twitter.com,最明显的例子就是,如果你双击 TwitterFox 的状态图标去 twitter.com 官方页面,将会是用  http://twitter.com/home 打开页面,并且该页面下所有 twitter.com 引用页面链接也都是使用 http:// 协议。在 twitter.com 上充满低俗内容的今天,某些数据通讯无疑会让墙不太高兴。

向作者提出过将 http:// 协议全部改成  https:// 协议的建议,但未被采纳(我个人比较奇怪,因为作者似乎很在乎通讯隐私,要不也不会把 TwitterFox 改成强制使用 SSL 收发 tweets,而不是像早期版本那样允许用户自己设置是否使用 SSL)。

下面这个版本是从官方 subversion repository 里面取得最新源代码,修改全部 http:// 协议引用到  https:// 后的编制版本,目前版本为 1.8b1,和官方发布的最新版 1.7.7.1 的区别只是上述修改和版本号:

https://dl.getdropbox.com/u/106561/TwitterFox-lxl-https.xpi

我会定期监察官方 subverion repository 里面的源代码,如果发现更新,也会相应更新这个版本,一直到官方版本完全使用 https:// 协议为止。

如果你还在用不安全的 TwitterFox 官方版进行低俗推发,那么建议你使用这个版本。如果你对这个版本不是很放心,可以下载 xpi 文件后,改名到 zip 文件,然后解开该文件和官方的正式发布版比较一下看看差异,确认没有恶意代码后再安装。

安装之后如果你双击 TwitterFox 的小图标,应该去 https://twitter.com/home ,也就是使用 https:// 协议访问你的个人页面。

Linux 命令行下用 Gmail SMTP 发信

18-二-09

最近没有注意清理硬盘空间,每天半夜的备份把外接硬盘填满了还不知道,由于这个外接硬盘是用 automount 挂载的,平时一般处于卸载状态,所以没有及时发现。由此 Linux 系统命令行发送邮件的需求重新提到日程上来。

几年前安装 Linux 系统时顺手配置 Email Server 很常见,但是近来大家都选择不安装了,因为

1、用家里ISP分配的动态IP运行的 SMTP 服务器发信往往会被别人当作 spam 拒收(因为这种动态IP无法经过域名反查证实是我们自己设定的域名);

2、现在免费信箱很多,与其自己费心维护还不如直接用 Gmail 提供的 SMTP 服务。

经过比较后,我决定使用 ssmtp 来实现发信,原因是

1、我并不需要收信,只需要发信;

2、ssmtp 比 exim 小很多,比较一下安装包,ssmtp 大约 50KB,exim 大约 1.7MB

选择 Gmail 是因为它提供加密的 SMTP 服务,首先去 Gmail 申请一个帐号(sender@gmail.com),专门用来发信。

使用 sudo apt-get install ssmtp 安装 ssmtp 后,修改设置文件 /etc/ssmtp/ssmtp.conf,改成

root=sender@gmail.com
mailhub=smtp.gmail.com:587
UseSTARTTLS=YES
RewriteDomain=
Hostname=sender@gmail.com
AuthUser=sender@gmail.com
AuthPass=password
FromLineOverride=YES

反查表文件 /etc/ssmtp/revaliases 里面设置

root:sender@gmail.com:smtp.gmail.com:587

这时就可以用 ssmtp 通过 Gmail SMTP 来发信了,假如我们要发一封试验信给 myacct@myemail.com,可以这样写

echo “This is a test email” | mail -s “test email” myacct@myemail.com

用脚本可以写出更加复杂的邮件(包括一些命令的执行结果),如

#!/bin/sh

DATESTR=`date +”%m/%d%Y”`

(echo -e “this is current disk usage: \n”; df -h ; echo -e “\n\nPlease cleanup if necessary.\n”) | mail -s “[my server notification] $DATESTR” myacct@myemail.com

用 KeePass 实现远程控制的自动登录

11-二-09

我经常要登录多个远程系统进行维护,输入用户名和密码是一件很烦的事情,但如果将用户密码保存在远程控制软件中又会造成安全隐患,尤其是如果该远程控制软件是放在 U 盘上的便携版,一旦 U 盘遗失,可能会被别人轻易侵入系统,我的几个 Linux 帐号都有 sudo 权限,被窃取后基本上就等同 root 帐号被攻克了。

比较安全的自动登录可以用 KeePass 配合适当的远程控制软件来实现。

首先远程控制软件必须允许在命令行设定远程登录的信息,如远程系统IP/域名,端口,用户名,密码等等。我最常用的几款都可以:

登录 SSH 服务器使用 putty:putty.exe -ssh $username@$host:$port -pw $password

登录 SFTP 服务器使用 winscp:winscp.exe” sftp://$username:$password@$host:$port

远程桌面使用 UltraVNC viewer:vncviewer.exe” $host:$port -password $password

远程桌面使用 TeamViewer:Teamviewer.exe” -i $ID -P $password

如果想在 U 盘上使用 KeePass 便携版的话,这几款远程控制软件都有便携版或者便携的替代版,如 putty 可以用 kitty 来替代。

这里用 KeePass 1.14 中的 URL field 配合 cmd:// 链接来启上述动远程控制软件,传入登录信息,就可以无需输入用户名/密码自动登录到远程系统上了。由于远程系统的登录信息是由 KeePass 加密保存的,远程软件中可完全不需要保存远程系统的信息(可手动逐一删除目前已经保存的信息),并且设置不要记录登录历史,这样即使把 KeePass + 远程控制软件便携版保存在 Dropbox 这样的网盘上也可以放心了。

假定我们把远程软件便携版(kitty.exe, winscp.exe, vncviewer.exe, teamviewer.exe)保存在 KeePass 的目录下(和 KeePass.exe 在同一目录),则 URL field 和相应 field 可以这样设置:

kitty 自动登录 URL:

cmd://”{APPDIR}\kitty.exe” -ssh {USERNAME} -pw {PASSWORD}

(”User name” field: username@host:port, “Password” field: password)

winscp 自动登录 URL:

cmd://”{APPDIR}\winscp.exe” sftp://{USERNAME}:{PASSWORD}@{TITLE}

(”Title” field: host:port, “User name” field: username, “Password” field: password)

UltraVNC viewer 自动登录 URL:

cmd://”{APPDIR}\vncviewer.exe” {USERNAME} -password {PASSWORD}

(”User name” field: host:port, “Password” field: password)

TeamViewer 自动登录 URL:

cmd://”{APPDIR}\Teamviewer.exe” -i “{USERNAME}” -P {PASSWORD}

(”User name” field: ID, “Password” field: password)

这种自动登录目前的局限是:

1、SSH (putty, winscp) 还无法用密钥登录,KeePass 1.14 可考虑用 “Notes” field 保存 private key,然后写一个 batch,把 {NOTES} 保存成一个临时文件,用 -i 传给 putty 登录后马上删除;KeePass 2.0 则可以使用 custom field;

2、SSH (putty, winscp) 会记录远程系统的IP或域名及公钥(但这些信息只要用 putty/winscp 连接一次 SSH 服务器就能取得)


编辑:听说 KeePass 2.x 可以保存文件附件了,那么,使用密钥登录的问题也就解决了。


修改 Firefox 的 Google搜索栏 icon

16-一-09

Google 最近两次修改自己的 favicon,但是 Firefox 并没有跟进修改 Google 搜索栏中的服务 icon。

Firefox 的搜索设置在其安装目录(默认 c:\program files\mozilla firefox)下的 searchplugins 目录下。Firefox 自带了几个搜索引擎的设置,Google 在 google.xml 中。打开这个文件,会看到一行

<Image width=”16″ height=”16″>data:image/x-icon;base64, … </Image>

就是存放 Google 服务 icon 数据的地方。编辑该处,可以换上任何 16×16 的 icon 替换 Google 的默认 G icon。

我个人不喜欢 Google 新换的 favicon,倒是觉得 可能吧 新换的 favicon 很得搜索的真谛,所以就把它偷来作为我的 Google 搜索服务图标 :P

这是修改后的效果图:

kicon1

kicon2

base64 编码可以使用 Linux coreutils 包里的 base64 生成,或者使用这个在线服务

修改过的 google.xml

==============================

<SearchPlugin xmlns=”http://www.mozilla.org/2006/browser/search/”>
<ShortName>Google</ShortName>
<Description>Google Search</Description>
<InputEncoding>UTF-8</InputEncoding>
<Image width=”16″ height=”16″>data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAACey3r/wd6q/8Heqv/B3qr/wd6q/8Heqv/B3qr/wd6q/8Heqv/B3qr/wd6q/8Heqv/B3qr/wd6q/8Heqv+ey3r/wd6q////////////////////////////////////////////////////////////////////////////wd6q/8Heqv///////////83qzv91xXf/5PPk///////+/v7/9PT8/+Li+f/OzvX/u7vx/6io7f+UlOn/wsLy/8Heqv/B3qr///////////+Oz5D/NKo3/7Hesv/KyvT/jo7o/3Bw4v9aWt7/RUXZ/zAw1f8aGtH/CAjN/1JS3P/B3qr/wd6q////////////9Pr0/8Tmxf/8/fz/5fTl//////////////////////////////////7+/v//////wd6q/8Heqv////////////z8/P/09PT//v7+/9Dr0f+a1Zz/+Pz4/////////////////////////////////8Heqv/B3qr////////////CwsL/AAAA/+Li4v//////1e3W/2W+Z//W7db////////////////////////////B3qr/wd6q////////////2dnZ/wAAAP9WVlb/7u7u///////d8N3/TLRO/5nUmv/7/fv/////////////////wd6q/8Heqv////////////////+ampr/FBQU/w4ODv94eHj/+fn5/+Pz4/9NtFD/Xbtf/93w3f///////////8Heqv/B3qr///////////////////////X19f+QkJD/CQkJ/4SEhP//////6PXp/1S3Vv86rD3/otij//3+/f/B3qr/wd6q//7+/v/+/v7//////////////////////2xsbP9BQUH////////////t9+3/W7pe/zSqN/+r3Kz/wd6q/8Heqv9JSUn/bW1t//////////////////////+Hh4f/MDAw//////////////////T69P+Z1Jv/3fHe/8Heqv/B3qr/SUlJ/1tbW///////////////////////d3d3/zw8PP/////////////////////////////////B3qr/wd6q/4WFhf8NDQ3/jY2N/6mpqf+srKz/kpKS/xQUFP98fHz/////////////////////////////////wd6q/8Heqv/5+fn/goKC/zc3N/8bGxv/GRkZ/y8vL/92dnb/9fX1/////////////////////////////////8Heqv+ey3r/wd6q/8Heqv/B3qr/wd6q/8Heqv/B3qr/wd6q/8Heqv/B3qr/wd6q/8Heqv/B3qr/wd6q/8Heqv+ey3r/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==</Image>
<Url type=”application/x-suggestions+json” method=”GET” template=”http://suggestqueries.google.com/complete/search?output=firefox&amp;client=firefox&amp;hl={moz:locale}&amp;q={searchTerms}”/>
<Url type=”text/html” method=”GET” template=”http://www.google.com/search”>
<Param name=”q” value=”{searchTerms}”/>
<Param name=”ie” value=”utf-8″/>
<Param name=”oe” value=”utf-8″/>
<Param name=”aq” value=”t”/>
<!– Dynamic parameters –>
<Param name=”rls” value=”{moz:distributionID}:{moz:locale}:{moz:official}”/>
<MozParam name=”client” condition=”defaultEngine” trueValue=”firefox-a” falseValue=”firefox”/>
</Url>
<SearchForm>http://www.google.com/firefox</SearchForm>
</SearchPlugin>
==============================

把 delicious 改造成 blinklist

09-十二-08

blinklist 的升级令人失望,决定用 Greasemonkeydelicious 改进一下,让它至少看上去和旧版的 blinklist 有些相像。

改造之处:

1、点击 delicious 显示的书签时让它在新的 tab 里面显示;

2、显示书签网站的缩略图和 favicon。

Yamamaya 的脚本已经完成了2,我就在此基础上增加了1。

脚本代码如下:

// ==UserScript==
// @name Delicious Thumbnail & Favicon
// @namespace Yamamaya
// @include http://delicious.com/*
// @version 2.00
// ==/UserScript==

(function(){
var insertEle = document.getElementById(”sidebar”);
var toggle = document.createElement(”div”);
toggle.id = “toggleBox”;
toggle.style.cursor = “pointer”;
var h3 = document.createElement(”h3″);
toggle.appendChild(h3);
var span = document.createElement(”span”);
span.className = “toggle-button”;
span.innerHTML = “Thumbnail Size”;
h3.appendChild(span);

var setBox = document.createElement(”div”);
setBox.id = “sizeSetBox”;
setBox.style.display = GM_getValue(”display”);

var sele = document.createElement(”a”);
sele.href=”#”;
sele.innerHTML = “Small”;
setBox.appendChild(sele);

var seleM = document.createElement(”a”);
seleM.href=”#”;
seleM.innerHTML = “Medium”;
setBox.appendChild(seleM);

var seleL = document.createElement(”a”);
seleL.href=”#”;
seleL.innerHTML = “Large”;
setBox.appendChild(seleL);

if(setBox.style.display == “none”) span.style.backgroundPosition = “3px -359px”;

h3.addEventListener(”click”,function(){
setBox.style.display == “” ? setBox.style.display = “none”: setBox.style.display = “”;
setBox.style.display == “” ? span.style.backgroundPosition = “” : span.style.backgroundPosition = “3px -359px”;
GM_setValue(”display”,setBox.style.display);
},false);
var addImg = function(link){
if(link.parentNode.nodeName.toLowerCase() != “h4″) return;
// favicon
var fBox = document.createElement(”div”);
var fStyle = fBox.style;
fStyle.cssFloat = “left”;
fStyle.minWidth = “16px”;
fStyle.minHeight = “16px”;
fStyle.margin = “0px 7px”;
fStyle.backgroundImage = ‘url(”chrome://global/skin/icons/folder-item.png”)’;
var favi = document.createElement(”img”);
favi.src=”http://” + link.hostname + “/favicon.ico”;
favi.width = “16″;

// No favicon
favi.removeEventListener(’error’, revertIcon, false);
favi.addEventListener(’error’, revertIcon, false);

var parent = link.parentNode;
fBox.appendChild(favi);
parent.insertBefore(fBox,link);

// Thumbnail
if (parent.parentNode.parentNode.firstChild.nextSibling.nodeName.toLowerCase() != “a”) {
var tBox = document.createElement(”div”);
tBox.style.cssFloat = “left”;
tBox.style.margin = “0px 3px 3px 0px”;
var a = document.createElement(”a”);
a.href = link.href;
a.target = “_blank”;
var thumb = document.createElement(”img”);
thumb.src=”http://open.thumbshots.org/image.pxf?url=” + link.href;
thumb.alt = “thumb”;
thumb.width = GM_getValue(”width”, 90);
thumb.height = GM_getValue(”height”, 70);
thumb.style.border = “1px solid #c4c4c4″;
a.appendChild(thumb);
tBox.appendChild(a);
parent.parentNode.insertBefore(tBox, parent);

insertEle.insertBefore(toggle, insertEle.firstChild);
insertEle.insertBefore(setBox, insertEle.firstChild.nextSibling);

switch(thumb.width){
case 70:
sele.style.color = “#fff”;
sele.style.backgroundColor = “#6C6C6C”;
break;
case 90:
seleM.style.color = “#fff”;
seleM.style.backgroundColor = “#6C6C6C”;
break;
case 120:
seleL.style.color = “#fff”;
seleL.style.backgroundColor = “#6C6C6C”;
break;
};
};

link.style.display = “block”;
link.style.paddingLeft = “5px”;
var linkContainer = document.createElement(”div”);
linkContainer.style.marginLeft = “30px”;
parent.insertBefore(linkContainer,link.nextSibling);
linkContainer.appendChild(link);

sele.addEventListener(”click”,function(e){
thumb.width = “70″;
thumb.height = “60″;
this.style.color = “#fff”;
this.style.backgroundColor = “#6C6C6C”;
seleM.style.color = “#666666″;
seleM.style.backgroundColor = “#fff”;
seleL.style.color = “#666666″;
seleL.style.backgroundColor = “#fff”;
set(thumb);
e.preventDefault();
},false);

seleM.addEventListener(”click”,function(e){
thumb.width = “90″;
thumb.height = “70″;
this.style.color = “#fff”;
this.style.backgroundColor = “#6C6C6C”;
sele.style.color = “#666666″;
sele.style.backgroundColor = “#fff”;
seleL.style.color = “#666666″;
seleL.style.backgroundColor = “#fff”;
set(thumb);
e.preventDefault();
},false);

seleL.addEventListener(”click”,function(e){
thumb.width = “120″;
thumb.height = “90″;
this.style.color = “#fff”;
this.style.backgroundColor = “#6C6C6C”;
sele.style.color = “#666666″;
sele.style.backgroundColor = “#fff”;
seleM.style.color = “#666666″;
seleM.style.backgroundColor = “#fff”;
set(thumb);
e.preventDefault();
},false);

// lxl added: open link in a new tab
link.target = “_blank”;
// lxl added: open link in a new tab

};

var addStyle = (function(){
var style = “ul.bookmarks li.post h4 a {background-color: #EFF5FB;}”;
style += “ul.bookmarks li.post h4 a:hover {color: #fff; text-decoration: none; background-color: #3472D0;}”;
style += “ul.bookmarks li.post .description {margin-left: 130px; width: 84%;}”;
style += “.main #popular ul.bookmarks li.post .bookmark {padding-left:80px;}”;
style += “ul li.post .bookmark .full-url {margin: 5px 3px;}”;
style += “ul.bookmarks li.post .TITLEONLY h4 a.taggedlink, ul.bookmarks li.post .TITLEONLY h4 .editdel {float: none;}”;
style += “ul.bookmarks li.post h4 .editdel a.action {padding: 0px 5px;}”;
style += “ul li.post .bookmark .full-url {margin: 5px 5px 5px 110px;}”;
style += “#sidenav-title {margin-top:20px;}”;
style += “#toggleBox h3 {width:190px; margin:0px 0px 10px 30px;}”;
style += “#sizeSetBox {margin:0px 0px 5px 30px;}”;
style += “#sizeSetBox a {color:#666666; margin:0px 3px 0px 0px; padding:2px 0px 2px 16px; display:block; border-bottom:1px solid #E3E3E3;}”;
GM_addStyle(style);
})();

var faviThumb = function(){
var path = [
'.//h4/a[@class="inlinesave action" or @class="action" or @class="inlinesave"]‘,
‘.//span[@class="saved"]‘,
‘.//h4/div[@class="editdel"]‘,
].join(” | “);
forEachMatch(’.//a[@class="taggedlink"]‘, addImg);
forEachMatch(path,addSave);
};
faviThumb();

window.AutoPagerize&&window.AutoPagerize.addFilter(
function(docs){
docs.forEach(faviThumb);
});

function revertIcon(event) {
this.src=”http://media.aruko.net/favicon/m/file.gif”;
};

function set(t){
GM_setValue(”width”,t.width);
GM_setValue(”height”,t.height);
};

function addSave(links){
if (!links) return;
if (links.parentNode.nodeName.toLowerCase() == ‘div’) return;
var saveBox = document.createElement(”div”);
saveBox.style.marginTop = “5px”;
saveBox.style.marginLeft = “30px”;
var boxParent = links.parentNode;
saveBox.appendChild(links);
boxParent.appendChild(saveBox);
};

function forEachMatch(path, f, root) {
var el;
var root = (root == null) ? document : root;
var matches = root.evaluate(
path, root, null,
XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);
for (var i=0;el=matches.snapshotItem(i);i++)
f(el);
};

})();

blinklist.com 2.0 终于发布了,但是……

01-十二-08

盼星星盼月亮,终于盼来了 blinklist 2.0 发布了。

对比 blinklist delicious, blinklist 更符合我的个人习惯,包括在新 tab 里面打开书签连接,快速转换网页快照和列表显示方式,favorite 方式,tag cloud 方式等等功能(我的 delicious 需要用 greasemonkey+custom script 来实现其中一些功能,当然,只能在 Firefox 里面才可以)。

但是 blinklist 1.0 一直有个问题,就是速度慢(而且越来越慢),慢到无法忍受的地步。官方论坛上 Mike 一直吹 2.0 多么多么地改进了速度、界面,让人无法不期待。

星期六终于丑媳妇见公婆了,我的近千条书签居然只剩下90条,私密的书签也被公开,龟速依旧,原有的特色功能被大幅裁减,甚至连官方提供的 Firefox addon 也无法 blink 新书签,omg,别的网站做到这种程度恐怕连 alpha 都不好意思讲,blinklist.com 居然敢发布。

To be honest, now I feel embarrassed to tell people I am using blinklist as my primary social bookmark manager, maybe it’s time to dismiss blinklist douban group.

12/4后续:和网站支持沟通了几次之后,终于把书签全找回来了,目前在适应新版中。由于引入了 Google Gears 插件,速度确有提高,但有些功能还未开启,暂时还看不见朋友。

1/5后续:终于放弃了 blinklist。

软件运行文件越小越好吗?

26-九-08

这篇文章是读过善用佳软“超级小巧的5款免费款树状笔记软件”后,关于软件运行文件大小的一些感想。

在其他条件都相同的理想情况下,当然同样尺寸的软件,实现功能越多越好,这是没有疑问的。

不过……

首先,其他条件都相同这个情况,本身就非常不容易满足;

其次,即使满足了其他条件都相同 ,如何衡量和比较不同软件的实现功能呢?如果两个软件的运行文件大小一样,A 软件实现了 10 个功能,完成每个功能各需要 1 分钟,B 软件实现了 8 个功能,完成每个功能各需要 30 秒,虽然 A 软件的实现功能比 B 软件多,但用户对 A 软件的评价是否一定比 B 软件高呢?

我们现在来看看,软件运行文件的大小都受什么因素影响。

1、编译器优化方面的因素

以 C 为例, 编译器提供了 inline function(或者用 #define 的变种),就是牺牲文件运行代码的尺寸来换取运行速度的提高(这在需要实时快速反应的软件来说尤其重要),使用了 inline function 的运行文件,尺寸比较大;

现代的高级语言编译器,都有各种优化选项,供程序员选择,比如 gcc 中的 -O 选项就相当复杂,可参看 info gcc 中的 Optimize Options 一节,-O 默认的优化目标是产生的代码小,运行效率高,但实际情况中,这两方面往往是互相矛盾的。由于优化技术已经很成熟,用高级语言编程的代码,经编译器优化后,不同程序员之间的差别越来越小,所以高手间代码本身尺寸大小的对决,往往是汇编这一层次的较量,在高级语言层次,除非实现方法完全不同,否则很难从文件尺寸上分出高下。

2、 软件运行环境的因素

同样一个 hello world 的实现,如果用 perl 来写,一行字符的脚本就能搞定,而用 C 写一个简单的程序编译成可执行代码则要2KB多,表面上看来,用 perl 写出来的代码小,但是 perl 脚本需要有 perl 解释环境才能运行,如果把 perl 解释环境都加入考虑的范畴,那么 perl 脚本的尺寸要比 C 编译出来的可执行代码要大很多了。

类似的软件环境还有 .NET,  JRE, python, PHP…… 等等。脱离了软件运行环境,只比较运行软件文件的大小,得出的结果意义并不大。

3、 动态库的因素

现在一般用户接触到的软件,已经很少能找到不加载动态库的了,用 Microsoft Visual C++ 写 Windows GUI 界面软件,最常见的就是使用 MFC,如果选择动态连接的话,生成的可执行代码会很小,但运行过程中系统必须加载相应版本的 MFC dll。如果只比较可执行代码,而不是同时也使用 depends (Windows) 或者 ldd (Linux) 来考虑它们需要加载的动态库的话,就有失偏颇了。

有时为了满足特定系统的需求或者运行稳定性要求,程序员也会编译出静态连接的可执行代码,比如

. 系统不支持动态库,如 DOS

. 某些低层软件可能在动态库系统还未建立时就需要运行,如用不含 initrd 的嵌入式 Linux 小系统中的 busybox/init,在它开始执行时包含动态库文件系统可能还未加载

. 为避免不同版本动态库的冲突而故意编译成静态连接软件,这种软件不依赖系统中的动态库,可以不考虑不同版本之间的兼容性,有时能大大节省技术支持部门的开销。

4、跟程序员有关的附加信息

这一部分也许和一般用户关系不大,但有时它也是影响软件可执行文件大小的因素

. Debug 版本,这类软件含有调试信息,在软件出现问题时对程序员非常宝贵,尤其是在这个 beta 满天飞的时代

. paranoid 型容错编程风格,假如两个程序员写出的程序是这样的:

程序员 A 的:

function foo()

{

try {

job1();

job2();

job3();

} catch exception(e)

{ exception_handler(e);}

}

程序员 B 的:

function foo()

{

job1();

job2();

job3();
}

程序员 B 的版本一定会比程序员 A 的版本小,但是说实话,我宁可要尺寸较大的程序员 A 的版本。