Thursday, June 07, 2007

无法访问 Flickr

朋友告诉我 Blog 上的照片很多都看不到,开始很奇怪,以为是 Flickr 服务器出了问题,深究之下,怀疑是被 G-F-W 了…… 通过 Solidot 证实,真的是这样……

具体情况好像是,如果访问了厦门 PX 事件某敏感照片,则会有一段时间访问不了。但据我自己和朋友的情况看,Flickr 网站可以访问,但是照片无论如何都是红叉叉,因此推测被封的应该是 *.static.flickr.com。

唉,这年头,要用点网络服务还真难,我可是上个月刚刚付费成为 Flickr 的 Pro 用户啊!去欧洲 6G 多的照片正在准备整理上传呢!真的是很无言……

套用 Solidot 的话;到底做错了什么……?

Tuesday, February 13, 2007

MySQL 的自动断开连接问题

最近发现 MySQL 会自动断开 IDLE 时间超过 8 小时的数据库连接,从而导致一些基于数据库连接的应用程序,特别是 WEB 应用程序出错。

有两个办法可以解决这个问题:

第一个办法是修改 MySQL 的配置参数。这个参数的名称是 wait_timeout,其默认值为 28800(单位秒),刚好就是 8 小时。其意义为关闭一个连接之前在这个连接上等到行动的秒数,也就是说,如果一个连接闲置超过这个选项所设置的秒数,MySQL 会主动断开这个连接。

有实践表明,没有办法把这个值设置成无限大,即永久。因此如果你无法保证你的应用程序必定在设定的秒数内至少有一次操作,那么最好用第二个方法解决这个问题。

第二个办法是如下修改 JDBC 连接的 URL:
jdbc:mysql://hostaddress:3306/schemaname?autoReconnect=true

添加 autoReconnect=true 这个参数,即能解决这个问题。

另外,对于 Java 的应用程序,据说第三方的数据库连接池应用 Proxool 能够对断开的数据库连接发起自动重连,不过我没有用过,有兴趣的朋友可以尝试一下。

Monday, January 08, 2007

不再厌恶中文版 Windows XP

一直很厌恶简体中文版的 Windows XP,而尽可能的用英文版,不是我为了炫耀英文——其实刚开始使用英文版的时候真的有种找不到北的感觉——之所以会厌恶,完全是因为字体!

厌恶 Windows 系统“宋体”的默认西文字体已经有年头了,我是不会在任何场合下使用其对应的西文字体的,只要有可能我就会用 Tahoma 或者 Verdana 来替代。诚然,宋体在 12px 以及 14px 下作为正文字体是非常合适的,也很入眼,但是在比 12px 更小或者比 14px 更大的场合,这款字体就不那么好看了,加上它没有很好的支持 Anti-Aliasing 和 ClearType,因此在 Windows Vista 中才会替换成了以前说过的“微软雅黑”。

通常中文版的 Windows XP 装好后,大部分的字体都可以通过“显示属性”对话框中“外观”选项卡下的“高级”选项对话框来设置。然而,登录界面以及登录后屏幕左下角“开始”按钮上偌大的“开始”两个字,可以说要多难看有多难看。经过一番 Google 和琢磨,现在终于找到办法来将这两处的字体换掉。这样一来,我就可以比价舒服的用中文版的 Windows XP了。以下是修改方法:

修改登录界面字体
登录界面是由 C:\Windows\System32\logonui.exe 来控制的,其所有的内容和资源都被编译打包到这个可执行文件里头。为了能够改变它,我们需要用到 ResHacker 这款小工具(点击这里下载,版本 3.4.0.79,若需更新版本请自行 Google)。

先将 C:\Windows\System32\logonui.exe 文件备份,然后用 ResHacker 打开这个文件,可以看到左边列出了一些可展开的树状目录。打开“String Table”,这个目录下为程序需要用到的字符串。打开第一个名字为“1”的目录,再点击“2052”项,会发现右边的窗口列出了一些字符串,注意到标号为 1, 2 和 3 的文字即是“宋体”,这就是控制字体的地方了。将这三项改成你要设置的字体的名称就可以了,比如“微软雅黑”。注意设置之前一定要确保目标字体存在,建议先到“控制面板”的“字体”管理中确认。设置完了以后,要点击一下右边窗口上访的“Compile Script”按钮。

另外,和“1”目录并列的“4”目录下还有一个“宋体”字符串项,也改成你要的字体吧。修改完成后,选择菜单中“File -> Save”保存,然后退出即可。

注意,通常修改 Windows 的系统文件,人们一般都会建议到安全模式的 DOS 命令方式下去替换,这样可以避免因为文件正在被使用而无法写入,或者修改后导致正在运行的系统出现问题。不过这个 logonui.exe 可以无须这么做,在 Windows 正常运行过程中是可以被写入的,只是被写入后,Windows 会立即报告发现文件被修改为不可识别的版本,并建议用 Windows 安装盘修复。这时取消掉这个建议,并确认使用目前的无法识别版本就可以了。

修改并保存后,立即注销一下,或者用切换用户的命令(快捷键 Win+L)回到登录界面,发现修改已经生效了。以下是我修改后的截图(点击可查看大图)。

修改过字体后的登录界面
ResHacker 不但可以修改 exe 文件中的字符串,还可以修改 Bitmap 图片以及程序中各元素出现的位置坐标等,通过这一点完全可以自定义出截然不同的登录界面来。各位有兴趣可以自行研究。注销和关闭 Windows 的对话框也可以修改,分别对应 Shell32.dll 和 msgina.dll。修改之前记得一定要先把原来的文件备份好,以防出现不测。

修改“开始”按钮字体
“开始”菜单和任务栏所对应的应用程序为 C:\Windows\Explorer.exe,如果要将“开始”这两个字替换成别的内容或者修改别的相关的字符串,可以用上面的办法通过 ResHacker 打开这个文件(记得做好备份)。不过,控制字体的地方却不在这个文件中。要修改“开始”按钮这两个字的字体,需要修改注册表。

打开注册表的
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\FontAssoc\Associated DefaultFonts

将 AssocSystemSwiss 改成你需要的字体名称即可。然后退出重新启动系统使得改动生效。

以下是我修改后“开始”按钮的效果:

更改过字体的“开始”按钮

Saturday, January 06, 2007

Blogger 自定义域名

昨天 Blogger Buzz 放出消息,声称 Blogger 现在可以支持自定义域名。对于自己喜欢的 *.blogspot.com 域名已经被注册,或者难以使用 FTP 发布的国内 Blogger 用户来讲,这是个好消息。根据这篇帮助的提示,只需注册一个域名,简单的设置一个 CNAME 记录,就可以用 BlogSpot 托管空间而使用自己的域名。

我新建了一个域名来发布上次测试用的 Blog,地址是:http://blogtest.windia.net

Blogger 提供的新的模版编辑体系还是很实用的,关键是相对传统的模版,新模版加入了很多新的功能和特性,这些对于 FTP 发布使用传统模版的用户是无法使用的。

不过,值得担心的是,如果 Blogger 和其托管站点 *.blogspot.com 一旦再被封,自定义的域名是否也会同样失效?目前 Blogger 要求自定域名的 CNAME 记录指向 ghs.google.com,这个域名和 *.blogspot.com 的 IP 地址是不相同的,希望能够在 *.blogspot.com 万一再次遭殃的时候能够幸免于难。

Friday, January 05, 2007

用 JSON 实现侧边栏的最新评论列表

上个月 21 号 Google 发出消息,声称 GData API 开始支持以 JSON (JavaScript Object Notation,中文介绍) 的形式提供数据,并且给出了对应的 API 文档,同时 Blogger Buzz 网站也告知广大用户,JSON 支持的 GData API 中同样也包括 Blogger。

在这之前,由于 JavaScript 先天的限制,我们不能通过 JavaScript 代码打开当前域以外的远程文件,这也就限制了我们通过传统的 AJAX 技术利用 GData API 的 Atom Feed 来实现 Blogger 页面上最新帖子、评论列表的即使更新,因为我们无法在某个 *.blogspot.com 域名下打开 www.blogger.com 下的 XML 文档。当然,新的 Blogger 支持在自己的域名下,也就是以 yourname.blogspot.com/feeds/ 的形式访问 Atom Feed 解决了这个问题,但是对于通过 FTP/sFTP 发布的非 blogspot 用户,还是无法绕过这个问题。

现在,Google GData API 除了可以在原来的地址后面加 alt=json 参数来以 JSON 的格式组织数据以外,还可以用 alt=json-in-script&callback=myFunction (其中 myFunction 是自己用来处理 JSON 数据的函数) 的方式使得 Feed 返回的 JS 代码内容直接是对 myFunction 函数的调用,这样就绕过了以上 JavaScript 不能远程调用本域以外资源的限制。

通过这个办法,我修改了自己 Blogger 侧边栏的最新评论列表。虽然原来有一个,不过只是根据 Blogger Help 上的这篇介绍开启的,原理还是利用 <Blogger> 标签的循环,只输出评论的部分,也就是说,原来的方法输出的只是当前页面最新评论列表,没有在首页列出的文章,其评论是不会出现的。而且,在默认情况下,评论的排序方式是先按帖子先后顺序,再按时间顺序。我自己另外写了一个 JavaScript 函数来对它们重新排序,并只保留最新的 10 条。

现在,通过 GData API 的 JSON 回调支持,我写了一个真正意义上的最新评论列表。看到这位网友提供了一个 blogspot 用户适用的办法,对于非 blogspot 发布,特别是 FTP/sFTP 发布的用户,可以用我的办法:

<div id="sidebar-recent-comments">
<p id="comment-loading">Loading Data...</p>
<dl id="comments-block">
<dt class="comment-data" name="comment-data">
<a href=""></a><span>, </span>
<span class="comment-poster">
<a href="" rel="nofollow"></a></span>
<span> said...</span></dt>
<dd class="comment-body" name="comment-body"><p></p></dd>
</dl></div>

<script type="text/javascript">

// Fetch the recent comments from Blogger Feed with JSON code and
// the callback func is "dispComments".
function getComments(blogId, counts) {

// Temporarily hide it
var dl = document.getElementById("comments-block");
dl.style.display = "none";

// Retrieve the JSON feed.
var script = document.createElement('script');
script.setAttribute('src', 'http://www2.blogger.com/feeds/' + blogId +
'/comments/default?alt=json-in-script&callback=' +
'dispComments&start-index=1&max-results=' + counts);
script.setAttribute('id', 'jsonScript-recent-comments');
script.setAttribute('type', 'text/javascript');
document.documentElement.firstChild.appendChild(script);
}

// Translate the date
function transDate(dateStr) {
dateStr = dateStr.substring(0, dateStr.indexOf("."));
dateStr = dateStr.replace("T", " ");
dateStr = dateStr.replace(/\-/g, "/");
return dateStr;
}

// Display the comment entries onto the web page.
function dispComments(json) {
var dl = document.getElementById("comments-block");

// get entry template
var dt = dl.getElementsByTagName("dt")[0];
var dd = dl.getElementsByTagName("dd")[0];

dl.removeChild(dt);
dl.removeChild(dd);

for (var i = 0; i < json.feed.entry.length; i++) {
var entry = json.feed.entry[i];
var curDt = dt.cloneNode(true);
var curDd = dd.cloneNode(true);

// Time
curDt.childNodes[0].href = entry.link[0].href;
curDt.childNodes[0].appendChild(
document.createTextNode(transDate(entry.published.$t)));

// Author
curDt.childNodes[2].childNodes[0].appendChild(
document.createTextNode(entry.author[0].name.$t));
if (entry.author[0].uri) {
curDt.childNodes[2].childNodes[0].href = entry.author[0].uri.$t;
}
else {
curDt.childNodes[2].childNodes[0].removeAttribute("href");
}
dl.appendChild(curDt);
dl.appendChild(curDd);

//Content
curDd.childNodes[0].appendChild(
document.createTextNode(entry.title.$t));
}

dl.style.display = "block";
var commentLoading = document.getElementById("comment-loading");
commentLoading.style.display = "none";
}

getComments('yourBlogId', entryCount);
</script>

注意最后一行调用的 getComments 函数的两个参数,yourBlogId 是你当前这个 Blog 的 blogId,每个 Blog 都是不同的。打开自己帖子的评论页面,从 URL 上就可以找到自己的 blogId。第二个参数 entryCount 是要显示的评论条数,例如 10。

另外,为了保持页面整洁,我只使用了评论的第一行,也就是 title 部分的内容。如果需要显示完整,将以上代码中蓝色的 title 改成 content 即可。

为了简洁起见,也可以把 getComments 和 dispComments 两个函数放到外部的 .js 文件中去定义,页面只用引入这个 .js 文件,然后调用 getComments 即可。