<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/" xmlns:georss="http://www.georss.org/georss" xmlns:gd="http://schemas.google.com/g/2005" gd:etag="W/&quot;Dk8CRHoycSp7ImA9WxNWGEs.&quot;"><id>tag:blogger.com,1999:blog-7286295415331143255</id><updated>2009-10-18T19:21:05.499+08:00</updated><title>派・索尼客</title><subtitle type="html">A Pythonic Blog</subtitle><link rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml" href="http://py.thonic.org/feeds/posts/default" /><link rel="alternate" type="text/html" href="http://py.thonic.org/" /><link rel="hub" href="http://pubsubhubbub.appspot.com/" /><link rel="next" type="application/atom+xml" href="http://www.blogger.com/feeds/7286295415331143255/posts/default?start-index=26&amp;max-results=25&amp;redirect=false&amp;v=2" /><author><name>wyt</name><uri>http://www.blogger.com/profile/04947921907676762514</uri><email>noreply@blogger.com</email></author><generator version="7.00" uri="http://www.blogger.com">Blogger</generator><openSearch:totalResults>137</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><link rel="self" href="http://feeds.feedburner.com/pythonic" type="application/atom+xml" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com" /><entry gd:etag="W/&quot;A0UNRXw_eSp7ImA9WxNTGU4.&quot;"><id>tag:blogger.com,1999:blog-7286295415331143255.post-6275430457267193926</id><published>2009-07-10T19:05:00.004+08:00</published><updated>2009-08-22T19:08:14.241+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-08-22T19:08:14.241+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="devede" /><category scheme="http://www.blogger.com/atom/ns#" term="gentoo" /><category scheme="http://www.blogger.com/atom/ns#" term="linux" /><category scheme="http://www.blogger.com/atom/ns#" term="howto" /><category scheme="http://www.blogger.com/atom/ns#" term="dvd" /><title>怎样用 DeVeDe 制作视频 DVD</title><content type="html">&lt;h3&gt;DeVeDe &lt;strong&gt;介绍&lt;/strong&gt;&lt;/h3&gt;&lt;a id="uuhb" title="DeVeDe" href="http://www.rastersoft.com/programas/devede.html" target="_blank"&gt;DeVeDe&lt;/a&gt; 是一个 Linux 下为数不多的轻量级的视频 DVD 制作软件。DeVeDe 能够将多个 &lt;a id="so.b" title="Mplayer" href="http://www.mplayerhq.hu/" target="_blank"&gt;Mplayer&lt;/a&gt; 支持的视频文件（比如 MPEG、AVI、MOV 等格式），转换成家用 DVD 机可以播放的 DVD 和 VCD（包括VCD、超级 VCD 和 CVD）。DeVeDe 有一个优点是依赖性很小，只需要 Mplayer、&lt;a id="m5f0" title="MEncoder" href="http://en.wikipedia.org/wiki/MEncoder" target="_blank"&gt;MEncoder&lt;/a&gt;、&lt;a id="x88b" title="DVDAuthor" href="http://dvdauthor.sourceforge.net/" target="_blank"&gt;DVDAuthor&lt;/a&gt;、&lt;a id="z-_r" title="MKisofs" href="http://en.wikipedia.org/wiki/Cdrtools" target="_blank"&gt;MKisofs&lt;/a&gt;、&lt;a id="qrxp" title="Python" href="http://www.python.org/" target="_blank"&gt;Python&lt;/a&gt; 和 &lt;a id="cg9." title="PyGTK" href="http://www.pygtk.org/" target="_blank"&gt;PyGTK&lt;/a&gt; 等，基本都是 Linux （至少 GTK 环境）的标配。&lt;br /&gt;
&lt;br /&gt;
因为硬盘上的 NBC 版的北京奥运会开幕式已经积灰了一段时间，我想到在电视上看会比较爽，所以想在 &lt;a id="h90c" title="Gentoo Linux" href="http://www.gentoo.org/" target="_blank"&gt;Gentoo Linux&lt;/a&gt; 下用 DeVeDe 转换成视频 DVD 镜像，并用 &lt;a id="v-ga" title="Xfburn" href="http://www.xfce.org/projects/xfburn/" target="_blank"&gt;Xfburn&lt;/a&gt; 烧制出一张可以在家用 DVD 机上播放的 DVD 光盘。图文以记之。&lt;br /&gt;
&lt;h3&gt;&lt;strong&gt;安装 DeVeDe&lt;/strong&gt;&lt;/h3&gt;首先我们需要安装 DeVeDe。如果你是 Gentoo 用户，输入&lt;br /&gt;
&lt;pre&gt;$ sudo emerge -av devede&lt;/pre&gt;如果你是 Fedora 用户，输入&lt;br /&gt;
&lt;pre&gt;$ sudo yum install devede&lt;/pre&gt;如果你是 Ubuntu or Debian 用户，输入&lt;br /&gt;
&lt;pre&gt;$ sudo apt-get install devede&lt;/pre&gt;安装完成后，我们还要设置一下字幕用的字体。比如我用&lt;a id="mkvl" title="文泉驿正黑" href="http://wenq.org/?ZenHei" target="_blank"&gt;文泉驿正黑&lt;/a&gt;，输入&lt;br /&gt;
&lt;pre&gt;$ cd ~/.spumux
$ rm devedesans.ttf
$ ln -s /usr/share/fonts/wqy-zenhei/wqy-zenhei.ttc devedesans.ttf&lt;/pre&gt;&lt;h3&gt;&lt;strong&gt;启动 DeVeDe&lt;/strong&gt;&lt;/h3&gt;&lt;div id="x0:a" style="text-align: left;"&gt;安装完成后，我们启动 DeVeDe，首先会出现下面这样一个窗口，问你想要创建哪一种格式的光盘。我们应该选择 DVD，毫不犹豫的。&lt;br /&gt;
&lt;br /&gt;
&lt;a href="http://docs.google.com/File?id=ds3pqnf_1534cfpxvtfg_b" target="_blank"&gt;&lt;img style="width: 400px; height: 301.935px;" src="http://docs.google.com/File?id=ds3pqnf_1534cfpxvtfg_b" alt="" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;h3&gt;&lt;strong&gt; &lt;/strong&gt;&lt;strong&gt;添加视频文件&lt;/strong&gt;&lt;/h3&gt;一张视频 DVD 分为多个标题（Title）和章节（Chapter）。一个标题通常对应一部电影，你可以在一个标题下添加任意数量的文件（File），并把它们分成多个章节方便搜索。&lt;br /&gt;
&lt;br /&gt;
DeVeDe 的主界面上，我们首先会看到标题栏（Titles）和文件栏（Files）。标题栏中的将会显示在 DVD 主菜单上供用户选择，所以最好能用一眼看明白的名字，比如“第十四话 漫无止境的八月 3”。&lt;br /&gt;
&lt;div id="c4wg" style="text-align: left;"&gt;&lt;div id="koql" style="text-align: left;"&gt;&lt;a href="http://docs.google.com/File?id=ds3pqnf_1537dbgpxngn_b" target="_blank"&gt;&lt;img style="width: 400px; height: 335.286px;" src="http://docs.google.com/File?id=ds3pqnf_1537dbgpxngn_b" alt="" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;DeVeDe 会自动生成一个名为 Title 1 的默认标题。如果想要添加更多标题，可以点击标题栏下面的“添加”（Add）按钮，DeVeDe 会创建另一个名为 Title N 的新标题。&lt;br /&gt;
&lt;br /&gt;
这次，我们只有一段开幕式的影片，所以没有其他的标题了，接下来点击“属性”（Properties）按钮，修改标题的名称。输入“播放奥运会开幕式”。&lt;br /&gt;
&lt;div id="pnea" style="text-align: left;"&gt;&lt;a href="http://docs.google.com/File?id=ds3pqnf_1536d9xvxgd8_b" target="_blank"&gt;&lt;img style="width: 400px; height: 271.111px;" src="http://docs.google.com/File?id=ds3pqnf_1536d9xvxgd8_b" alt="" /&gt;&lt;/a&gt;&lt;/div&gt;我们还可以选择当标题所对应的视频播放完成后的动作，默认的动作是返回 DVD 主菜单，这也是我们想要的。其他的选项还有播放前一个/后一个标题，播放第一个/最后一个标题，和重放当前标题。&lt;br /&gt;
&lt;br /&gt;
接下来，我们该添加视频文件了，点击文件栏下面的“添加”（Add）按钮，DeVeDe 会弹出“文件属性”（File Properties）的对话框。选择好要添加的视频以后，我们会在文件信息栏（File info）看到视频的原始尺寸、原始长度、最终尺寸等信息。&lt;br /&gt;
&lt;div id="o:8:" style="text-align: left;"&gt;&lt;div id="dj72" style="text-align: left;"&gt;&lt;div id="a_-l" style="text-align: left;"&gt;&lt;a href="http://docs.google.com/File?id=ds3pqnf_1538dzkwh6dv_b" target="_blank"&gt;&lt;img style="width: 400px; height: 355.337px;" src="http://docs.google.com/File?id=ds3pqnf_1538dzkwh6dv_b" alt="" /&gt;&lt;/a&gt;&lt;/div&gt;接下来，我们可以设置视频制式，PAL or NTSC。中国基本上使用 &lt;a id="c_-x" title="PAL 制式" href="http://zh.wikipedia.org/wiki/PAL%E5%88%B6%E5%BC%8F" target="_blank"&gt;PAL 制式&lt;/a&gt;，但现在的电视和 DVD 播放器一般对两种制式都是支持的。把制式的选项独立出来，从而允许用户创建混合制式的 DVD，有些电影以 PAL/SECAM，而其他的用 &lt;a id="gs:q" title="NTSC 制式" href="http://zh.wikipedia.org/wiki/NTSC%E5%88%B6%E5%BC%8F" target="_blank"&gt;NTSC 制式&lt;/a&gt;。这样做的理由是针对不同的原始帧率（Original Frames per Second）的视频选择不同的制式，例如原始文件为每秒24帧或25帧就选择 PAL 制式，如果是30帧就选择 NTSC，我们会有更流畅的画面。当然，DeVeDe 也可以把统一转换为使用25帧或30帧。&lt;br /&gt;
&lt;br /&gt;
点击字幕栏的“添加”按钮，我们可以选择外部字幕，这些字幕会被添加到当前的视频，存储为真正的 DVD 字幕，因此我们可以在观看 DVD 的过程中显示或隐藏它们。对于中文字幕来说，编码一般为 UTF-8 或 GBK，我们必须选对编码，不然 DeVeDe 会报错。另外，就像之前说的，合适的中文字体也很重要。&lt;br /&gt;
&lt;br /&gt;
如果要删除字幕，只需使用“清除”（Remove）按钮。&lt;br /&gt;
&lt;div id="x77e" style="text-align: left;"&gt;&lt;a href="http://docs.google.com/File?id=ds3pqnf_1539hck8gp3q_b" target="_blank"&gt;&lt;img style="width: 282px; height: 214px;" src="http://docs.google.com/File?id=ds3pqnf_1539hck8gp3q_b" alt="" /&gt;&lt;/a&gt;&lt;/div&gt;字幕栏的下面，展开高级选项（Advanced Options）。通用选项（General&lt;br /&gt;
Options）中，我们可以输入一个新的视频和音频的比特率。请记住，选择更大的比特率，就有更好的视频质量，但文件大小也会更大。默认情况下，如果视频的宽度被重新调整为720像素， DeVeDe 将采用&lt;br /&gt;
5001Kbps；如果宽度为352像素，高度是288（PAL）或240（NTSC），DeVeDe 将默认使用&lt;br /&gt;
2001Kbps，如果最终的高度是576（PAL）或480（NTSC），3001Kbps 将是默认的比特率。&lt;br /&gt;
&lt;br /&gt;
不过，我们也可以不用急着现在设置，回到主界面中点击“调整光盘使用率”（Adjust Disc Usage）按钮，DeVeDe 会自动设置比特率，以填满 DVD 的空间。我推荐这个选项。&lt;br /&gt;
&lt;br /&gt;
大多数情况下，没有其他值得我们特别关心的地方了，所以保持默认的设置就好。&lt;br /&gt;
&lt;br /&gt;
最后，文件属性对话框的底部有一个“预览”（Preview）按钮。用它可以生成一段默认长度为60秒的视频预览，如果我们的设置有任何的问题，都会在预览过程中暴露出来。DeVeDe 会将它保存在 /var/tmp 目录，你也可以自行设定。我们应该仔细的查看预览，确保视频的字幕正常，视频和音频的质量理想，以及音频的同步没有问题。&lt;br /&gt;
&lt;div id="x.x1" style="text-align: left;"&gt;&lt;a href="http://docs.google.com/File?id=ds3pqnf_1540gj4kzwdc_b" target="_blank"&gt;&lt;img style="width: 400px; height: 537.954px;" src="http://docs.google.com/File?id=ds3pqnf_1540gj4kzwdc_b" alt="" /&gt;&lt;/a&gt;&lt;/div&gt;觉得完美无缺（至少预览看起来是这样）以后，点击 OK 按钮，我们会回到主界面。&lt;br /&gt;
&lt;h3&gt;制作 DVD 菜单&lt;/h3&gt;&lt;/div&gt;&lt;/div&gt;主界面的文件栏中已经有我们刚才添加的视频了。文件栏下方的文件信息栏（File Info）包括了基本信息：理想的视频和音频比特率，估计的最终大小，原始尺寸，FPS 和播放时间（秒）等。估算的文件大小（Estimated Length）是你设定的视频和音频率，乘以视频长度计算出来的，有可能超过一般 DVD 的容量。显而易见的，我们需要把它降下来。&lt;br /&gt;
&lt;div id="dzy5" style="text-align: left;"&gt;&lt;a href="http://docs.google.com/File?id=ds3pqnf_1541gfwg8pcn_b" target="_blank"&gt;&lt;img style="width: 400px; height: 334.923px;" src="http://docs.google.com/File?id=ds3pqnf_1541gfwg8pcn_b" alt="" /&gt;&lt;/a&gt;&lt;/div&gt;在光盘使用率（Disc Usage）一栏，我们可以选择 CD/DVD 的容量大小，默认为 4.7GB。中间是一个以百分比呈现的光盘使用率。右边是，前面提到过的，“调整光盘使用率”（Adjust Disc Usage）按钮。点击这个按钮，DeVeDe 会自动调整视频的比特率，让估算的文件大小和 DVD 容量尽量相等。&lt;br /&gt;
&lt;div id="result_box" style="text-align: left;" dir="ltr"&gt;现在，我们该制作 DVD 菜单了。DeVeDe 有一个基本的菜单模板，不算糟糕但也不算满意，我们可以先看一下。&lt;br /&gt;
&lt;div id="sjba" style="text-align: left;"&gt;&lt;a href="http://docs.google.com/File?id=ds3pqnf_1542tjskpfgb_b" target="_blank"&gt;&lt;img style="width: 400px; height: 360.858px;" src="http://docs.google.com/File?id=ds3pqnf_1542tjskpfgb_b" alt="" /&gt;&lt;/a&gt;&lt;/div&gt;点击“菜单选项”（Menu Options）按钮，DeVeDe 会弹出菜单设置对话框。首先，我们可以添加菜单的主标题，和它的字体、颜色和阴影等，它会显示在菜单的顶部。&lt;br /&gt;
&lt;br /&gt;
我们还可以设置菜单的背景图片和背景音乐。&lt;br /&gt;
&lt;br /&gt;
接着，我们该设置菜单的子标题，也就是电影标题了，选项有位置、字体、背景色和阴影色等。但要注意，尽管我们可以改变字体的大小，却不能改变按钮的大小，所以如果字体太大，就会超出按钮的范围。一定想要用大字体的话，可以把按钮背景设成透明，这样就不会显得突兀了。&lt;br /&gt;
&lt;div id="se9e" style="text-align: left;"&gt;&lt;a href="http://docs.google.com/File?id=ds3pqnf_1547dpphq3ct_b" target="_blank"&gt;&lt;img style="width: 400px; height: 497.976px;" src="http://docs.google.com/File?id=ds3pqnf_1547dpphq3ct_b" alt="" /&gt;&lt;/a&gt;&lt;/div&gt;在设置的过程中，我们随时可以“预览菜单”（Preview Menu），来确认菜单的显示效果。最终的效果如下图。&lt;br /&gt;
&lt;div id="lki1" style="text-align: left;"&gt;&lt;a href="http://docs.google.com/File?id=ds3pqnf_1543znjqqjfb_b" target="_blank"&gt;&lt;img style="width: 400px; height: 362.466px;" src="http://docs.google.com/File?id=ds3pqnf_1543znjqqjfb_b" alt="" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;h3&gt;一切准备就绪&lt;/h3&gt;&lt;p style="text-align: left;"&gt;&lt;/p&gt;&lt;p style="text-align: left;"&gt;接下来，我们会在高级选项里看到，DeVeDe 可以将视频文件转换成三种格式。第一种是将电影文件转换 DVD 兼容的 MPEG 视频，这个选项的好处是，我们以后可以用 DVD Author 或 DVD Styler 等类似的软件来 DIY 创建 DVD 菜单。&lt;/p&gt;&lt;p style="text-align: left;"&gt;&lt;/p&gt;&lt;p style="text-align: left;"&gt;第二种是创建 DVD 目录结构。DeVeDe 会在转换 MPEG 视频后，用 DVD Author 创建菜单和 DVD 树结构。&lt;/p&gt;&lt;p style="text-align: left;"&gt;&lt;/p&gt;&lt;p style="text-align: left;"&gt;第三种是创建一个 DVD ISO 映像，这是 DeVeDe 默认的，最方便的，也是我们将要使用的方法。DeVeDe 会把转换视频，创建菜单和创建 DVD 目录一气完成，生成一张 ISO 或 BIN/CUE 光盘镜像，然后我们就可以直接用 GnomeBaker、K3b 或 Xfburn 烧制 DVD。&lt;/p&gt;&lt;br /&gt;
如果你用的是多核 CPU，你还应该勾上“为多核 CPU 优化“（Use Optimizations for Multicore CPUs）一项。&lt;br /&gt;
&lt;div id="ib5h" style="text-align: left;"&gt;&lt;a href="http://docs.google.com/File?id=ds3pqnf_1544cmdm9fhc_b" target="_blank"&gt;&lt;img style="width: 400px; height: 398.352px;" src="http://docs.google.com/File?id=ds3pqnf_1544cmdm9fhc_b" alt="" /&gt;&lt;/a&gt;&lt;/div&gt;我们已经将一切准备就绪了，点击“前进”（Forward）按钮，DeVeDe 会让我们选择 ISO 保存的位置。&lt;br /&gt;
&lt;div id="a5yv" style="text-align: left;"&gt;&lt;a href="http://docs.google.com/File?id=ds3pqnf_1545fc5w4g6w_b" target="_blank"&gt;&lt;img style="width: 400px; height: 220.569px;" src="http://docs.google.com/File?id=ds3pqnf_1545fc5w4g6w_b" alt="" /&gt;&lt;/a&gt;&lt;/div&gt;之后我们要做的慢慢等着，和你一起变老，不，DeVeDe 吐出一张制作完成的视频 DVD 镜像。&lt;br /&gt;
&lt;div id="te97" style="text-align: left;"&gt;&lt;a href="http://docs.google.com/File?id=ds3pqnf_1546dr47ccg7_b" target="_blank"&gt;&lt;img style="width: 388px; height: 201px;" src="http://docs.google.com/File?id=ds3pqnf_1546dr47ccg7_b" alt="" /&gt;&lt;/a&gt;&lt;/div&gt;参考链接&lt;br /&gt;
&lt;ul&gt; &lt;li&gt;&lt;a id="mr8p" title="DeVeDe" href="http://www.rastersoft.com/programas/devede.html" target="_blank"&gt;DeVeDe Homepage&lt;br /&gt;
&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a id="wskw" title="Howto use Devede" href="http://thenexus.tk/how-to-use-devede/" target="_blank"&gt;Howto use Devede&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a id="ax7:" title="How to create a custom DVD using DeVeDe" href="http://www.my-guides.net/en/content/view/75/" target="_blank"&gt;How to create a custom DVD using DeVeDe&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a id="elms" title="How to Convert AVI to DVD with Devede" href="http://news.softpedia.com/news/How-to-convert-AVI-to-DVD-54418.shtml" target="_blank"&gt;How to Convert AVI to DVD with Devede&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a id="x09z" title="DeVeDe：视频 CD 制作利器" href="http://linuxtoy.org/archives/devede.html" target="_blank"&gt;DeVeDe：视频 CD 制作利器&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a id="scgk" title="Devede - 好用的輕量級 DVD authoring 軟體" href="http://moto.debian.org.tw/viewtopic.php?t=12112&amp;amp;view=previous&amp;amp;sid=6e72ac21a4770fb1f003bba63815e015" target="_blank"&gt;Devede - 好用的輕量級 DVD authoring 軟體&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7286295415331143255-6275430457267193926?l=py.thonic.org'/&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/E54-XbOT62cnYC6cLZVDYwoq9K0/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/E54-XbOT62cnYC6cLZVDYwoq9K0/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/E54-XbOT62cnYC6cLZVDYwoq9K0/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/E54-XbOT62cnYC6cLZVDYwoq9K0/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;</content><link rel="replies" type="application/atom+xml" href="http://py.thonic.org/feeds/6275430457267193926/comments/default" title="帖子评论" /><link rel="replies" type="text/html" href="http://py.thonic.org/2009/07/devede-dvd.html#comment-form" title="0 条评论" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7286295415331143255/posts/default/6275430457267193926?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7286295415331143255/posts/default/6275430457267193926?v=2" /><link rel="alternate" type="text/html" href="http://py.thonic.org/2009/07/devede-dvd.html" title="怎样用 DeVeDe 制作视频 DVD" /><author><name>wyt</name><uri>http://www.blogger.com/profile/04947921907676762514</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="13162551058647906166" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></entry><entry gd:etag="W/&quot;A0MCQHg5fSp7ImA9WxNTGU4.&quot;"><id>tag:blogger.com,1999:blog-7286295415331143255.post-6706353326607312538</id><published>2009-07-04T19:09:00.000+08:00</published><updated>2009-08-22T19:11:01.625+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-08-22T19:11:01.625+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="html5" /><category scheme="http://www.blogger.com/atom/ns#" term="html" /><title>HTML5 笔记：字符编码、DOCTYPE 和标签改进</title><content type="html">照理说，HTML5 正式发布至少要到2020年，是一件挺遥远的事儿。但是前几天安装了 Firefox 3.5 以后，突然觉得 HTML5 近在眼前了，还真是不可思议。&lt;br /&gt;
&lt;br /&gt;
HTML4 和 XHTML1.x 是目前互联网的主流标准。但是，HTML 最初是为静态文本内容所写，标准控件有限，不支持富媒体，越来越难以为现代的 Web 应用所服务。&lt;br /&gt;
&lt;br /&gt;
于是，HTML5 来了。HTML5 草案的前身名为 Web Applications 1.0。2004年由 WHATWG 提出，2007年被 W3C 接纳。在2008年1月22日，W3C 发布了第一份正式草案。&lt;br /&gt;
&lt;br /&gt;
HTML5 主要有三个特点。&lt;br /&gt;
&lt;ul&gt; &lt;li&gt;&lt;strong&gt;标签的语义化&lt;/strong&gt;。例如新增了 &amp;lt;nav&amp;gt; 和 &amp;lt;footer&amp;gt; 标签，表现 &amp;lt;div&amp;gt; 和类似，但代码的可读性和 SEO 更好。&lt;/li&gt;
 &lt;li&gt;&lt;strong&gt;支持富媒体化&lt;/strong&gt;。例如新增了 &amp;lt;audio&amp;gt; 和 &amp;lt;video&amp;gt; 标签，使得浏览器不需要任何插件，直接播放视频和音频文件。&lt;/li&gt;
 &lt;li&gt;&lt;strong&gt;分离布局和样式&lt;/strong&gt;。例如取消了 &amp;lt;font&amp;gt; 和 &amp;lt;center&amp;gt; 标签，因为所有的样式都应该在 CSS 中定义。&lt;/li&gt;
&lt;/ul&gt;我记下了一部分 HTML5 和 HTML4（包括 XHTML1.x）的不同之处作为备忘，参考了《&lt;a title="HTML 5 differences from HTML 4" href="http://www.w3.org/TR/html5-diff/" target="_blank"&gt;HTML 5 differences from HTML 4&lt;/a&gt;》和其他一些文档。&lt;br /&gt;
&lt;br /&gt;
&lt;strong&gt;字符编码和 DOCTYPE&lt;/strong&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;strong&gt;HTML5 有三种设置页面的字符编码（Character Encoding）的方法。&lt;/strong&gt;&lt;br /&gt;
&lt;ul&gt; &lt;li&gt;在传输层，设置 HTTP header 的 Content-Type 项。&lt;/li&gt;
 &lt;li&gt;在文件头部，添加一个 Unicode BOM 字符。&lt;/li&gt;
 &lt;li&gt;&lt;strong&gt;在文档中添加 &amp;lt;meta charset="UTF-8"&amp;gt;。&lt;/strong&gt;这会取代 HTML4 常见的 &amp;lt;meta http-equiv="Content-Type" content="text/html; charset=UTF-8"&amp;gt;，不过原来的仍然有效。&lt;/li&gt;
&lt;/ul&gt;&lt;strong&gt;HTML5 同样需要指定 DOCTYPE。因为不再引用 DTD，写法很简洁，例如 &amp;lt; !DOCTYPE html&amp;gt;。&lt;/strong&gt;HTML4 常见的 DOCTYPE 会比较长，例如：&lt;br /&gt;
&lt;pre&gt;&amp;lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&amp;gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;strong&gt;新增的标签&lt;/strong&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;strong&gt;HTML5 增加了几个常见的布局（Layout）标签，功能类似于 DIV 元素，但重新定义了标签名，例如 section、article、aside、header、footer 等标签。&lt;/strong&gt;使用以后，我们不再依赖 id 或 class 属性，如&lt;br /&gt;
&amp;lt;div id="header" class="header"&amp;gt;，来推测元素的意义，而是用标签名，如 ，直接判断。&lt;br /&gt;
&lt;br /&gt;
用 HTML5 写的典型的双栏 blog 文章页面的布局，相当简洁。&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html&amp;gt;
    &amp;lt;head&amp;gt;
        &amp;lt;meta charset="UTF-8"&amp;gt;
        &amp;lt;title&amp;gt;派・索尼客&amp;lt;/title&amp;gt;
    &amp;lt;/head&amp;gt;
    &amp;lt;body&amp;gt;
        &amp;lt;section&amp;gt;
            &amp;lt;header&amp;gt;
                &amp;lt;h1&amp;gt;派・索尼客&amp;lt;/h1&amp;gt;
                &amp;lt;p&amp;gt;A Pythonic Blog&amp;lt;/p&amp;gt;
            &amp;lt;/header&amp;gt;
            &amp;lt;article&amp;gt;
                &amp;lt;h2&amp;gt; 文章标题 ... &amp;lt;/h2&amp;gt;
                &amp;lt;p&amp;gt; 文章内容 ... &amp;lt;/p&amp;gt;
            &amp;lt;/article&amp;gt;
            &amp;lt;aside&amp;gt;
                &amp;lt;div&amp;gt; widget1 ... &amp;lt;/div&amp;gt;
                &amp;lt;div&amp;gt; widget2 ... &amp;lt;/div&amp;gt;
            &amp;lt;/aside&amp;gt;
            &amp;lt;nav&amp;gt;
                &amp;lt;a href="/prev/"&amp;gt;前一篇&amp;lt;/a&amp;gt;
                &amp;lt;a href="/"&amp;gt;回到主页&amp;lt;/a&amp;gt;
                &amp;lt;a href="/next/"&amp;gt;后一篇&amp;lt;/a&amp;gt;
            &amp;lt;footer&amp;gt;
                &amp;copy; 2009 保留所有权利 &amp;lt;a href="/"&amp;gt;派・索尼客&amp;lt;/a&amp;gt;
            &amp;lt;/footer&amp;gt;
        &amp;lt;section&amp;gt;
    &amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;strong&gt;HTML5 还有几个新增加的内联（Inline）元素，用来表示时间、进度等信息，例如 mark、meter、progress、time、keygen&lt;/strong&gt;&lt;strong&gt; 等标签。&lt;/strong&gt; meter 标签定义度量（单位）。仅用于已知最大和最小值的度量。例如 IMDB 的评分（10分满分）可以写成：&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;&amp;lt;meter value="8.13" min="0" max="10" low="5" high="8" optimum="10"&amp;gt;8.13&amp;lt;/meter&amp;gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;
time 标签定义日期和时间。具体的时间或日期可以存储在 datetime 属性中，格式没有特别的规定。例如“六四大屠杀”可以写成：&lt;br /&gt;
&lt;pre&gt;&amp;lt;time datetime="1989-06-04"&amp;gt;六四大屠杀&amp;lt;/time&amp;gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;strong&gt;HTML5 最吸引眼球的一点，是无需插件，即支持视频、音频等富媒体，例如 audio、video、canvas 等标签。&lt;/strong&gt;不过，如果浏览器厂商不能统一视频编码，那么富媒体标签也就名存实亡了——总不能把视频一式四份，为 Firefox 播放 OGG，为 Chrome 播放 H264，为 Safari 播放 QuickTime，为 IE 播放 WMV 吧。&lt;br /&gt;
&lt;br /&gt;
audio 标签支持播放音乐或 Podcast 等音频流。例如在页面上把 Feel My Soul 作为背景音乐，可以写成：&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;&amp;lt;audio autoplay="true" playcount="100" src="Feel My Soul.ogg" /&amp;gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;
&lt;div id="t0jn" style="text-align: left;"&gt;&lt;a href="http://lh4.ggpht.com/_sKun2mxXeAk/Sk9xj419GiI/AAAAAAAAEBM/qkuTT7ts8bM/s800/audio.png" target="_blank"&gt;&lt;img style="width: 304px; height: 42px;" src="http://lh4.ggpht.com/_sKun2mxXeAk/Sk9xj419GiI/AAAAAAAAEBM/qkuTT7ts8bM/s800/audio.png" alt="" /&gt;&lt;/a&gt;&lt;/div&gt;video 标签支持播放电影片段或其他视频流。例如：&lt;br /&gt;
&lt;br /&gt;
&lt;strong&gt;另外，INPUT 元素的也增加了一些新的 type 属性，例如 datetime、date、week、number、email、url、search、color 等。&lt;/strong&gt;这些属性可以为一些 UI，如日期拾取器（Date Picker）或电邮地址簿，增加语义性。据文档里说，这些属性可以提供浏览器端的数据验证，不过我没试出来。&lt;br /&gt;
&lt;pre&gt;&amp;lt;video width="640" height="360" controls="true" src="hinagiku.ogv" /&amp;gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;
&lt;div id="ysyg" style="text-align: left;"&gt;&lt;a href="http://lh4.ggpht.com/_sKun2mxXeAk/Sk9xj1-tFdI/AAAAAAAAEBQ/ks73V0ZEIPs/s800/video.png"&gt;&lt;img style="width: 400px; height: 225px;" src="http://lh4.ggpht.com/_sKun2mxXeAk/Sk9xj1-tFdI/AAAAAAAAEBQ/ks73V0ZEIPs/s400/video.png" alt="" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;strong&gt;有变动的标签&lt;/strong&gt;&lt;br /&gt;
&lt;br /&gt;
有改动的标签不是很多，且大部分都是语义上的变化，例如 &amp;lt;strong&amp;gt; 标签现在表重要性（SEO？），而不是表强调；&amp;lt;i&amp;gt; 标签不再只是斜体，而是表示和一般文字不同的专业术语或专用名词……值得一说的是&lt;strong&gt; menu 标签，&lt;/strong&gt;虽然在 HTML4 中被禁用（Deprecated），但是在 HTML5 中又“死灰复燃”并被赋予了新的意义，&lt;strong&gt;可以和 command 标签或 checkbox 控件一起用来生成命令菜单、工具栏或右键菜单等。&lt;/strong&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;strong&gt;被取缔的标签&lt;/strong&gt;&lt;br /&gt;
&lt;br /&gt;
接下来的三种标签将不会被 HTML5 采用。&lt;br /&gt;
&lt;ul&gt; &lt;li&gt;&lt;strong&gt;标签的功能应该被 CSS 取代。&lt;/strong&gt;例如：basefont、center、big、font、s、strike、tt、u 等。&lt;/li&gt;
 &lt;li&gt;&lt;strong&gt;标签被开发者误用或滥用。&lt;/strong&gt;例如：frame、frameset、noframes 等。&lt;/li&gt;
 &lt;li&gt;&lt;strong&gt;标签很少被使用。&lt;/strong&gt;例如：acronym、applet、isindex、dir 等。&lt;/li&gt;
&lt;/ul&gt;参考链接：&lt;br /&gt;
&lt;ul&gt; &lt;li&gt;&lt;a id="g75_" title="HTML 5 differences from HTML 4" href="http://www.w3.org/TR/html5-diff/" target="_blank"&gt;HTML 5 differences from HTML 4&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a id="rh-e" title="HTML 5 参考手册" href="http://www.w3school.com.cn/html5/index.asp" target="_blank"&gt;HTML 5 参考手册&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a id="xxrp" title="HTML5的结构和语义" href="http://www.52css.com/article.asp?id=671" target="_blank"&gt;HTML5的结构和语义&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a id="avc5" title="Semantics in HTML 5" href="http://www.alistapart.com/articles/semanticsinhtml5" target="_blank"&gt;Semantics in HTML 5&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a id="a-ec" title="HTML 5 Reference" href="http://dev.w3.org/html5/html-author/" target="_blank"&gt;HTML 5 Reference&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7286295415331143255-6706353326607312538?l=py.thonic.org'/&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/SWGp5jrgT06-utdACCeOIF4FCJg/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/SWGp5jrgT06-utdACCeOIF4FCJg/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/SWGp5jrgT06-utdACCeOIF4FCJg/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/SWGp5jrgT06-utdACCeOIF4FCJg/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;</content><link rel="replies" type="application/atom+xml" href="http://py.thonic.org/feeds/6706353326607312538/comments/default" title="帖子评论" /><link rel="replies" type="text/html" href="http://py.thonic.org/2009/07/html5-doctype.html#comment-form" title="0 条评论" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7286295415331143255/posts/default/6706353326607312538?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7286295415331143255/posts/default/6706353326607312538?v=2" /><link rel="alternate" type="text/html" href="http://py.thonic.org/2009/07/html5-doctype.html" title="HTML5 笔记：字符编码、DOCTYPE 和标签改进" /><author><name>wyt</name><uri>http://www.blogger.com/profile/04947921907676762514</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="13162551058647906166" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://lh4.ggpht.com/_sKun2mxXeAk/Sk9xj419GiI/AAAAAAAAEBM/qkuTT7ts8bM/s72-c/audio.png" height="72" width="72" /><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></entry><entry gd:etag="W/&quot;A0EMR3gzcSp7ImA9WxNTGU4.&quot;"><id>tag:blogger.com,1999:blog-7286295415331143255.post-9001081522217532397</id><published>2009-07-03T19:11:00.000+08:00</published><updated>2009-08-22T19:14:46.689+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-08-22T19:14:46.689+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="firefox" /><category scheme="http://www.blogger.com/atom/ns#" term="gentoo" /><category scheme="http://www.blogger.com/atom/ns#" term="linux" /><category scheme="http://www.blogger.com/atom/ns#" term="html5" /><title>试用 Firefox 3.5</title><content type="html">Mozilla 前几天刚发布最新的 Firefox  3.5 正式版。主要的新功能有&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;&lt;strong&gt;启用 TraceMonkey JavaScript 引擎&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;新增隐私浏览模式&lt;/li&gt;
&lt;li&gt; 改进了拖拉标签新建窗口功能&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;支持 HTML5 标准&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;支持用户的地理位置&lt;/li&gt;
&lt;/ul&gt;发布的当天，Gentoo 就把 Firefox 3.5 纳入了 Portage 当中。因为有被 hard masked，Gentoo 下安装的时候，需要运行&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;$ sudo autounmask =www-client/mozilla-firefox-3.5
$ sudo emerge =www-client/mozilla-firefox-3.5&lt;/pre&gt;&lt;br /&gt;
Emerge 完了以后，启动 Firefox，发现一个问题：&lt;strong&gt;系统的语言设定（Locale）虽然是 en_US.UTF-8，可 Firefox 的界面却变成中文的了。&lt;/strong&gt;看了下 Firefox 3.5 的包信息，不知道为什么少了 en 和 en_US 的 LINGUAS。解决方法有：&lt;br /&gt;
&lt;br /&gt;
打开 about:config，找到 general.useragent.locale 一项，把 zh-CN 改成 en-US 就好了。&lt;br /&gt;
&lt;br /&gt;
或者是直接修改 ebuild，把被遗失的 "en en-US" 添加到 LANGS 一项，然后安装一下。&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;$ diff ~/mozilla-firefox-3.5.ebuild.old mozilla-firefox-3.5.ebuild 9c9
&amp;lt; LANGS="af ar as be bg bn-BD bn-IN ca cs cy da de el es-AR es-CL es-ES
---
&amp;gt; LANGS="af ar as be bg bn-BD bn-IN ca cs cy da de el en en-US en-GB eo es-AR es-CL es-ES&lt;/pre&gt;&lt;br /&gt;
BTW，禁用中文的语言包（Language Pack）也可以把 Firefox 的界面恢复成原来的语言，但是对扩展没有用，算是不完全的。&lt;br /&gt;
&lt;br /&gt;
&lt;strong&gt;Firefox 3.5 最吸引我的两点。一是使用了号称速度上不输 Chrome V8 （太多）的 TraceMonkey&lt;br /&gt;
JavaScript 引擎。&lt;/strong&gt;在测评当中，&lt;a href="http://crave.cnet.co.uk/software/0,39029471,49302846,00.htm" id="df2r" title="Firefox 3.5 要比 3.0 快了2倍有余"&gt;Firefox 3.5 要比 3.0 快了2倍有余&lt;/a&gt;，尽管没有 Chrome 和 Safari 快，但差距已经不大。&lt;br /&gt;
&lt;div&gt;&lt;a href="http://picasaweb.google.com/lh/photo/rVFWNEnFZJAmxFlqSYOFKQ?authkey=Gv1sRgCPDOt77UypzpQA&amp;amp;feat=embedwebsite"&gt;&lt;img alt="" src="http://lh5.ggpht.com/_sKun2mxXeAk/SkzozUYvbEI/AAAAAAAAD38/3ZJq3nplvhg/s400/firefox-3-5-comparison.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;strong&gt;二是，Firefox 3.5 最重要的更新，对 HTML5 的支持。&lt;/strong&gt;最好的演示就是无需像 Flash 这样的插件，就可以在页面上直接观看 Theora/OGG 格式的视频了。写了一个简单的视频播放 Demo HTML。&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;&amp;lt;video width="640" height="360" src="test.ogv" autobuffer&amp;gt;
    &amp;lt;div class="video-fallback"&amp;gt;
        &amp;lt;br /&amp;gt;You must have an HTML5 capable browser.
    &amp;lt;/div&amp;gt;
&amp;lt;/video&amp;gt;&lt;/pre&gt;&lt;br /&gt;
截屏的效果如下。&lt;br /&gt;
&lt;div&gt;&lt;a href="http://lh6.ggpht.com/_sKun2mxXeAk/SkzouJnFObI/AAAAAAAAD30/Q47qmWeMa8E/s800/firefox-html5-video-controls.jpg"&gt;&lt;img alt="" src="http://lh6.ggpht.com/_sKun2mxXeAk/SkzouJnFObI/AAAAAAAAD30/Q47qmWeMa8E/s400/firefox-html5-video-controls.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;播放视频中。还有 Play 按钮、进度条、时间和音量等控件。&lt;br /&gt;
&lt;div&gt;&lt;a href="http://lh5.ggpht.com/_sKun2mxXeAk/Skzov87VPHI/AAAAAAAAD34/i0ZuvoEtIOU/s800/firefox-html5-video-context-menu.jpg"&gt;&lt;img alt="" src="http://lh5.ggpht.com/_sKun2mxXeAk/Skzov87VPHI/AAAAAAAAD34/i0ZuvoEtIOU/s400/firefox-html5-video-context-menu.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;暂停播放时。单击右键弹出菜单，可以像保存图片一样保存视频了。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7286295415331143255-9001081522217532397?l=py.thonic.org'/&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/13Fx_v2by7qe1oB0GmPcYFw8j9E/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/13Fx_v2by7qe1oB0GmPcYFw8j9E/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/13Fx_v2by7qe1oB0GmPcYFw8j9E/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/13Fx_v2by7qe1oB0GmPcYFw8j9E/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;</content><link rel="replies" type="application/atom+xml" href="http://py.thonic.org/feeds/9001081522217532397/comments/default" title="帖子评论" /><link rel="replies" type="text/html" href="http://py.thonic.org/2009/08/firefox-35.html#comment-form" title="0 条评论" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7286295415331143255/posts/default/9001081522217532397?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7286295415331143255/posts/default/9001081522217532397?v=2" /><link rel="alternate" type="text/html" href="http://py.thonic.org/2009/08/firefox-35.html" title="试用 Firefox 3.5" /><author><name>wyt</name><uri>http://www.blogger.com/profile/04947921907676762514</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="13162551058647906166" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://lh5.ggpht.com/_sKun2mxXeAk/SkzozUYvbEI/AAAAAAAAD38/3ZJq3nplvhg/s72-c/firefox-3-5-comparison.jpg" height="72" width="72" /><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></entry><entry gd:etag="W/&quot;A0EFSXY-cSp7ImA9WxNTGU4.&quot;"><id>tag:blogger.com,1999:blog-7286295415331143255.post-313809184344947175</id><published>2009-06-19T22:12:00.001+08:00</published><updated>2009-08-22T19:13:38.859+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-08-22T19:13:38.859+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="linux" /><category scheme="http://www.blogger.com/atom/ns#" term="git" /><title>git config push.default matching</title><content type="html">升级到 git 1.6.3 以后，每次 git push 的时候都会出现这样“吓人”的警告。&lt;br /&gt;
&lt;pre&gt;warning: You did not specify any refspecs to push, and the current remote
warning: has not configured any push refspecs. The default action in this
warning: case is to push all matching refspecs, that is, all branches
warning: that exist both locally and remotely will be updated.  This may
warning: not necessarily be what you want to happen.
warning:
warning: You can specify what action you want to take in this case, and
warning: avoid seeing this message again, by configuring 'push.default' to:
warning:   'nothing'  : Do not push anything
warning:   'matching' : Push all matching branches (default)
warning:   'tracking' : Push the current branch to whatever it is tracking
warning:   'current'  : Push the current branch&lt;/pre&gt;通常，这是很多 Linux 或者说开源社区贴心的地方，主动告诉你，“注意了，我们发布了一个新版本，有些地方和之前的不太一样，需要你自己动手改一下”。。。只是，为什么不直接给出一条简单明了的指令呢？比如，&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;$ git config push.default matching&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7286295415331143255-313809184344947175?l=py.thonic.org'/&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/t8zgcHAAAdp3sBnpEZRWyP1-lbE/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/t8zgcHAAAdp3sBnpEZRWyP1-lbE/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/t8zgcHAAAdp3sBnpEZRWyP1-lbE/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/t8zgcHAAAdp3sBnpEZRWyP1-lbE/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;</content><link rel="replies" type="application/atom+xml" href="http://py.thonic.org/feeds/313809184344947175/comments/default" title="帖子评论" /><link rel="replies" type="text/html" href="http://py.thonic.org/2009/06/git-config-pushdefault-matching.html#comment-form" title="0 条评论" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7286295415331143255/posts/default/313809184344947175?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7286295415331143255/posts/default/313809184344947175?v=2" /><link rel="alternate" type="text/html" href="http://py.thonic.org/2009/06/git-config-pushdefault-matching.html" title="git config push.default matching" /><author><name>wyt</name><uri>http://www.blogger.com/profile/04947921907676762514</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="13162551058647906166" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></entry><entry gd:etag="W/&quot;A0AARnczfyp7ImA9WxNTGU4.&quot;"><id>tag:blogger.com,1999:blog-7286295415331143255.post-2534849364358212145</id><published>2009-05-22T19:15:00.002+08:00</published><updated>2009-08-22T19:15:47.987+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-08-22T19:15:47.987+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="blogger" /><category scheme="http://www.blogger.com/atom/ns#" term="feed" /><title>Blog 搬家，也不算搬家</title><content type="html">因为 &lt;a href="http://www.google.com/search?q=blogger.com+被封"&gt;Blogger 后台被封锁&lt;/a&gt;的关系，原本用 Blogger FTP 发布的 Blog， 现在改成用 &lt;a id="uhvo" title="WordPress" href="http://wordpress.org/"&gt;WordPress&lt;/a&gt; 架设了。不过，不管是 FTP 还是 WordPress 发布，都在同一台主机上，其实也算不上搬家了。&lt;br /&gt;
&lt;br /&gt;
顺带也把域名换了。新的 Blog 域名为 &lt;strong&gt;PY.THONIC.ORG&lt;/strong&gt;，来自于单词 pythonic，意思是&lt;a id="mxp7" title="简单、清晰，不要过分强调技巧" href="http://blog.donews.com/limodou/archive/2005/08/07/498175.aspx"&gt;简单、清晰，不要过分强调技巧&lt;/a&gt;，一般论的话。于是，Blog 的名字也从“陆离斑「博」”改成“派・索尼客”，简单的音译，感觉不错就写上去了，结果反而有些不知所云呢。本人不是 Sony、Somy or Pony 的粉丝这一点倒是肯定的。&lt;br /&gt;
&lt;br /&gt;
Feed方面。&lt;a id="cpsm" title="FeedSky" href="http://feedsky.com/"&gt;FeedSky&lt;/a&gt; 被收购以后抓取的&lt;strong&gt;龟速&lt;/strong&gt;，所以不打算在 FeedSky 烧制 feed 了，现在的 feed 就是默认的 &lt;a id="vj_m" title="http://py.thonic.org/feed/" href="http://py.thonic.org/feed/"&gt;http://py.thonic.org/feed/&lt;/a&gt; 或 &lt;a id="iw8k" title="http://feeds2.feedburner.com/pythonic" href="http://feeds2.feedburner.com/pythonic"&gt;http://feeds2.feedburner.com/pythonic&lt;/a&gt;。原来绑定在 FeedSky 上的 feed，如 feed.luliban.com，feed.feedsky.com/luliban 等，会自动被重定向到 http://py.thonic.org/feed/。所以继续订阅也没差，至少在域名到期之前是这样子。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7286295415331143255-2534849364358212145?l=py.thonic.org'/&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/TcZkXybO2fv9UkXkzKhhzd-jaus/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/TcZkXybO2fv9UkXkzKhhzd-jaus/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/TcZkXybO2fv9UkXkzKhhzd-jaus/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/TcZkXybO2fv9UkXkzKhhzd-jaus/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;</content><link rel="replies" type="application/atom+xml" href="http://py.thonic.org/feeds/2534849364358212145/comments/default" title="帖子评论" /><link rel="replies" type="text/html" href="http://py.thonic.org/2009/05/blog.html#comment-form" title="0 条评论" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7286295415331143255/posts/default/2534849364358212145?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7286295415331143255/posts/default/2534849364358212145?v=2" /><link rel="alternate" type="text/html" href="http://py.thonic.org/2009/05/blog.html" title="Blog 搬家，也不算搬家" /><author><name>wyt</name><uri>http://www.blogger.com/profile/04947921907676762514</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="13162551058647906166" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></entry><entry gd:etag="W/&quot;DEcHSHc9fyp7ImA9WxJSFU0.&quot;"><id>tag:blogger.com,1999:blog-7286295415331143255.post-80079513528878620</id><published>2009-05-05T14:33:00.005+08:00</published><updated>2009-05-05T14:47:19.967+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-05-05T14:47:19.967+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="湖人" /><category scheme="http://www.blogger.com/atom/ns#" term="nba" /><category scheme="http://www.blogger.com/atom/ns#" term="火箭" /><title>不要低估一颗姚明的心/总决赛级别的防守</title><content type="html">和开拓者的系列赛开始前一样，我也列出了三个关键点。&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;首先，火箭能不能防住 Gasol 是最重要的。&lt;/b&gt;去年总决赛中 Gasol 被 Perkins 和 Kevin Garnett 彻底遏制是 Celtics 的取胜的关键之一，当 Gasol 被遏制的时候，湖人就回到了那支 05 年被太阳翻盘的只有 Kobe 一个人战斗的湖人。这一点今天火箭做得最好，在最后时刻的几次补篮前，Gasol 似乎只有 13 投 3 中。&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;其次，保护住防守篮板，尤其是第二阵容。&lt;/b&gt;湖人是常规赛中进攻篮板效率第三好的球队，前两名是波特兰和费城。火箭第一轮让开拓者场均拿到了 9.8 个进攻篮板，虽然比他们的赛季平均要少了 3 个，但光 Przybilla 和 Oden 两个人就贡献 5.0 个前板。而湖人在季后赛的表现也不比开拓者差，Gasol 和 Odom 合起来也能在爵士头上拿到 5.1 个进攻篮板。从这场比赛中，我们也可以看到火箭的第二阵容 Hayes + Landry 在高度上相差很多，光 Odom 一个人就拿到了 4 个前板，整场比赛湖人拿到了 12 个前场篮板。&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;第三，和开拓者的时候一样，当火箭在防守端做到最好的时候，Aaron Brooks 或 Artest 能不能在进攻端拿到足够取胜的分数。&lt;/b&gt;而且，这一点比对开拓者的时候更重要，因为湖人是全联盟攻守转换速度最快的几支球队之一，当他们能够保证自己的后场篮板的时候，快攻会非常之多。&lt;br /&gt;
&lt;br /&gt;
也许你会奇怪三条里面，没有一条是关于 Kobe 的。但绝对不是对 Kobe 的防守不重要，而是说这个地球上没有一支球队可以完全限制住 Kobe Bryant，你所能做的就是在比赛开始前为他准备好 30 分，在他投篮的时候遮住他的双眼，在他突破的路线上让姚明挡在他的身前，当他起跳的时候往他身上扔三四个人，接下来就只有看上帝更爱谁了。。。话说回来，当姚明能够顶防 Kobe 的挡拆的时候，火箭似乎又变回了 Van Gundy 时代的那支“即使 Kobe 拿到50分我还是能赢球”的火箭队。&lt;br /&gt;
&lt;br /&gt;
最后说一句，裁判也是人。凡是看到一个人血流满面的站在面前的时候，难免会动恻隐之心；凡是看到一个7尺6的巨人痛苦倒地后坚持完比赛的时候，难免会心生敬佩。于是，湖人的犯规以 26 比 14，火箭的罚球以 29 比 19 远远领先于对手，最后几次的吹罚也不像是在斯坦普斯中心了。&lt;br /&gt;
&lt;br /&gt;
最后的最后，希望姚明的膝盖没事。&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;更新一下：看起来姚明的膝盖没事。这是不是有点像去年总决赛的第一场 Paul Pierce 被人抬出球场的情景？&lt;/b&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7286295415331143255-80079513528878620?l=py.thonic.org'/&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/Mgca_2oOth5yWbxFcLxDrJ0vNwA/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/Mgca_2oOth5yWbxFcLxDrJ0vNwA/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/Mgca_2oOth5yWbxFcLxDrJ0vNwA/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/Mgca_2oOth5yWbxFcLxDrJ0vNwA/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;</content><link rel="replies" type="application/atom+xml" href="http://py.thonic.org/feeds/80079513528878620/comments/default" title="帖子评论" /><link rel="replies" type="text/html" href="http://py.thonic.org/2009/05/blog-post.html#comment-form" title="0 条评论" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7286295415331143255/posts/default/80079513528878620?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7286295415331143255/posts/default/80079513528878620?v=2" /><link rel="alternate" type="text/html" href="http://py.thonic.org/2009/05/blog-post.html" title="不要低估一颗姚明的心/总决赛级别的防守" /><author><name>wyt</name><uri>http://www.blogger.com/profile/04947921907676762514</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="13162551058647906166" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></entry><entry gd:etag="W/&quot;CEcDR3w_eCp7ImA9WxJSEUQ.&quot;"><id>tag:blogger.com,1999:blog-7286295415331143255.post-7731844426511254848</id><published>2009-05-01T14:37:00.010+08:00</published><updated>2009-05-01T23:34:36.240+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-05-01T23:34:36.240+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="开拓者" /><category scheme="http://www.blogger.com/atom/ns#" term="nba" /><category scheme="http://www.blogger.com/atom/ns#" term="火箭" /><title>恭喜火箭破处/Batum 的价值/加强版的开拓者</title><content type="html">火箭 4 - 2 开拓者。恭喜姚明7年职业生涯第一次进入西区半决赛。恭喜火箭12年来第一次进入第二轮。&lt;br&gt;&lt;br&gt;今天 Batum 用另类的方式证明了自己的价值。之前的五场比赛中，Artest 场均 13.4 分，命中率 37.7％，三分球命中率 28.0%，惨不忍睹情何以堪。但是第六场比赛中，之前场均 1.8 分的 Batum 被开拓者主教练 McMillan 摁在了板凳上，整场比赛用 Roy 或 Outlaw 对位，让 Artest 一口气轰下职业生涯的季后赛新高 27 分。结果论而说，McMillan 这一变招相当的失败。&lt;br&gt;&lt;br&gt;之前也说过，Artest 在面对身高臂长跑跳出色的防守者的时候，效率非常一般。所以，即使 McMillan 不希望再看到 Batum 出现在轮转阵容中，也应该把 Outlaw 放到先发。McMillan 把 Rudy Fernandez提拔，只得用 Roy 去防守 Artest。但 Roy 整场比赛都无法限制 Artest 和姚明的挡拆。有意思的是，昨天 Artest 莫名的大夸 Roy 更胜 Kobe 和 LeBron 之余，也说了 Roy 在防守端还不是精英级别的，马上就被验证了。&lt;br&gt;&lt;br&gt;火箭接下来的对手是湖人。湖人从各种角度来说，都是开拓者的加强版——这也是人们看好开拓者的未来的理由之一。相对应的是，火箭偶尔也会被人叫做山寨版的凯尔特人。除了“伪三巨头”之外，&lt;b&gt;火箭的防守体系，和去年在总决赛中将 Kobe 困于牢笼的凯尔特人的一样，师承防守大师 Tom Thibodeau 之手是一个很重要的原因。&lt;/b&gt;&lt;br&gt;&lt;br&gt;在凯尔特的体系中，Allen，Pierce 和 Posey 负责对 Kobe 贴身紧逼；Kevin Garnett 的活动范围非常大，他从进入三分线的那一刻起就开始夹击 Kobe；KG 身后的 Perkin 是最后一堵墙。相比之下，由 Battier 和 Artest 组成的火箭的侧翼防守不会输给任何一只球队；但是姚明以往在三秒区内更有威慑力，但中距离的挡拆防守和 KG 不能相提并论；而一旦姚明扑出去，身后的 Scola 能不能像 Perkins 一样保护好篮下也是一个问号。这也是湖人本赛季能横扫火箭的一个因素之一。&lt;br&gt;&lt;br&gt;但是，今天的姚明在防守端拿出了一个赛季以来的最高水准。他的活动范围直到 FIBA 的三分线，像一把大锁一样卡在了火箭的油漆区外，上一场被 Blake 和 Rudy 们频频利用的中距离空间，这一场消失殆尽。有那么一瞬间让人以为那是去年季后赛中的 Kevin
Garnett。像凯尔特人那样打出总决赛级别的防守，这是火箭和湖人对抗唯一的选择。&lt;br&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7286295415331143255-7731844426511254848?l=py.thonic.org'/&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/AiqlrtLe_DP0woUI02iCYE7v2p8/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/AiqlrtLe_DP0woUI02iCYE7v2p8/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/AiqlrtLe_DP0woUI02iCYE7v2p8/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/AiqlrtLe_DP0woUI02iCYE7v2p8/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;</content><link rel="replies" type="application/atom+xml" href="http://py.thonic.org/feeds/7731844426511254848/comments/default" title="帖子评论" /><link rel="replies" type="text/html" href="http://py.thonic.org/2009/05/batum.html#comment-form" title="0 条评论" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7286295415331143255/posts/default/7731844426511254848?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7286295415331143255/posts/default/7731844426511254848?v=2" /><link rel="alternate" type="text/html" href="http://py.thonic.org/2009/05/batum.html" title="恭喜火箭破处/Batum 的价值/加强版的开拓者" /><author><name>wyt</name><uri>http://www.blogger.com/profile/04947921907676762514</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="13162551058647906166" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></entry><entry gd:etag="W/&quot;CEIMRno8eyp7ImA9WxJTGEw.&quot;"><id>tag:blogger.com,1999:blog-7286295415331143255.post-2310023021880153449</id><published>2009-04-27T14:08:00.002+08:00</published><updated>2009-04-27T14:09:47.473+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-04-27T14:09:47.473+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="开拓者" /><category scheme="http://www.blogger.com/atom/ns#" term="nba" /><category scheme="http://www.blogger.com/atom/ns#" term="火箭" /><title>破绕前的终章</title><content type="html">&lt;a href="http://blog.luliban.com/2009/04/roy.html" id="qnwf" title="上场比赛后说了"&gt;上场比赛后说了&lt;/a&gt;，火箭的破绕前战术分为三部曲：弱侧突破，罚球线跳投，以及把球给到姚明。今天火箭终于做到了最后一条，姚明的14次出手比前两场总数还要多。三场比赛一场一个台阶，Adelman 展现出了季后赛大师级的调整能力，这是我在 Van Gundy 时代的火箭身上所没有看到的。&lt;br /&gt;
&lt;br /&gt;
接下来的比赛中，火箭还要继续加强对开拓绕前战术的解读能力。如果有弱侧的队员来协防，后卫就要把球从强侧快速的移动到弱侧；如果是由 Aldridge 沉底补防，对位的 Scola 或 Landry 就应该上提到罚球线来策应，或者直接跳投。如果只有 Przybilla 或 Oden 一个人在绕前，姚明可以从强侧横要到弱侧，球也要随之转移。因为开拓者肯定会混合是用这三种不同的绕前战术，而回到玫瑰花园的时候，Przybilla 不可能再开场两分钟就被吹下去，Oden 的大动作拉扯也多少会被无视一些。&lt;br /&gt;
&lt;br /&gt;
再说说 Roy 的改变，前两场比赛中 Roy 在挡拆中的选择无非是跳投和突破。今天 Roy 在挡拆后，不再一味的利用速度冲击火箭的内线，而是适时的收步，吸引火箭其他球员收缩防守后，再把球传到三分线外。沉寂了三场的 Travis Outlaw 和 Steve Blake 由此得到解放，两人联手在三分线外 9投4中。总的来说，这支开拓者已经越来越像那支在常规赛两次击败湖人的开拓者了。&lt;br /&gt;
&lt;br /&gt;
再说一个细节，Lowry 连续两场比赛在最后关头被 Rudy Fernandez 颜射进了大号三分，Lowry 的身高更适合去防守 Blake，也许 Adelman 会在下一场做出调整。&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7286295415331143255-2310023021880153449?l=py.thonic.org'/&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/OZ_R9dokFKrTNw12wgxNNKM5_fk/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/OZ_R9dokFKrTNw12wgxNNKM5_fk/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/OZ_R9dokFKrTNw12wgxNNKM5_fk/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/OZ_R9dokFKrTNw12wgxNNKM5_fk/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;</content><link rel="replies" type="application/atom+xml" href="http://py.thonic.org/feeds/2310023021880153449/comments/default" title="帖子评论" /><link rel="replies" type="text/html" href="http://py.thonic.org/2009/04/blog-post.html#comment-form" title="2 条评论" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7286295415331143255/posts/default/2310023021880153449?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7286295415331143255/posts/default/2310023021880153449?v=2" /><link rel="alternate" type="text/html" href="http://py.thonic.org/2009/04/blog-post.html" title="破绕前的终章" /><author><name>wyt</name><uri>http://www.blogger.com/profile/04947921907676762514</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="13162551058647906166" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">2</thr:total></entry><entry gd:etag="W/&quot;AkEDSH07fyp7ImA9WxJTFk4.&quot;"><id>tag:blogger.com,1999:blog-7286295415331143255.post-4186790087332746880</id><published>2009-04-25T13:42:00.003+08:00</published><updated>2009-04-25T13:51:19.307+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-04-25T13:51:19.307+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="开拓者" /><category scheme="http://www.blogger.com/atom/ns#" term="nba" /><category scheme="http://www.blogger.com/atom/ns#" term="火箭" /><title>对 Roy 的挡拆防守 / 火箭破绕前还差三分之一</title><content type="html">解说的时候，苏群说了一句话，“火箭就像是开拓者的陪练，不管赢没赢下这个系列赛，这都成为开拓者成长道路上的一个磨练”。其实反过来说也合适，火箭这赛季的两个阿喀琉斯之踵——姚明的挡拆防守和为姚明破绕前——通过和开拓者的系列赛，你可以清楚的看到火箭这两个最大的漏洞正在逐渐的被补上。&lt;br /&gt;
&lt;br /&gt;
当 Brandon Roy 挡拆进攻时，姚明不会再像常规赛一样 Shadow Post 沉在三秒区，而是和 Roy 面对面攻防，直到防守 Roy 的 Artest 或 Battier 回到他的防守位置为止。这也是今天火箭能把 Roy 18 次出手仅命中 6 球的两个主要原因之一。另一个就是火箭的主场哨保护了姚明，不像在玫瑰花园第二场比赛的时候一样，很容易被 Roy 的突破来制造犯规。相信在接下来的系列赛当中，Roy 恐怕很难再像第二场一样彪到 42 分的高分了。&lt;br /&gt;
&lt;br /&gt;
再说说绕前战术，这是一种赌博性的战术。当一个大个子对姚明执行绕前的时候，身后必然会留下很大的空位，这需要其他球员来填补身后的空位。&lt;b&gt;你可以把绕前战术想象成一颗洋葱头，开拓者的防守球员就像一层一层的洋葱皮，而姚明就被围困在其中心。&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
火箭的破绕前战术可以分为三种。第一种是利用弱侧的空档进行突破，这在第二场比赛中火箭已经做到了极致，Von Wafer 的坚决突破拿到了 20 分，以及 Aaron Brooks 或 Luis Scola 的弱侧挡拆在第三节也为火箭拉开7分的领先优势。虽然火箭第二场输了，但开拓者的主教练 McMillan 还是意识到了问题并作出了调整，在第三场比赛中让弱侧的球员更注意盯防火箭的外线球员。所以，火箭在第三场比赛中，也有几次成功的在弱侧给到了姚明皮球。&lt;b&gt;火箭的弱侧进攻已经剥去了洋葱头的第一层皮。&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
既然弱侧必须兼顾，McMillan 只有让大前锋 Aldridge 来做补防的工作。火箭的第二种破绕前战术正是针对这一点，Luis Scola 和 Carl Landry 的罚球线上提，在中距离让开拓者付出代价。今天比赛的上半场就是一个经典案例，Scola 上半场连投带突12投6中13分全队最高，这种表现甚至让 McMillan 一度放弃了绕前战术，因此下半场的前三次进攻中姚明都在强侧很轻松的拿到了皮球。&lt;b&gt;火箭的大前锋为姚明剥去了洋葱头的第二层皮。&lt;br /&gt;&lt;br /&gt;&lt;/b&gt;但是 Scola 的第四次犯规下场改变了整个比赛的进程。虽然 Landry 上半场中距离发炮5投5中效率惊人，但他不像 Scola 一样有杀伤能力，所以 McMillan 又恢复了绕前防守，甚至既不让弱侧进行补防，也不让大前锋协防。洋葱头就剩下最后一层皮——Przybilla 和 Oden 的独力绕前，&lt;b&gt;这时候开拓者的绕前战术就变成一种纯赌博性的战术，就赌火箭的外线不能够抓住那 0.5 秒的机会，把球给到内线的姚明。&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
最后的结果不必多说，虽然比赛赢了，但看看姚明的出手数（7次，只比上一场多了1次而已）就知道火箭的破绕前战术并没有成功。但也不能说完全失败，因为现在这颗洋葱头就只剩下一层皮，火箭也不是没有剥皮成功的经验——常规赛对开拓者的那一场大胜就是例子。&lt;br /&gt;
&lt;br /&gt;
如果火箭破得了绕前，防得了挡拆，那么火箭基本上就可以战胜开拓者了。而第二轮的对手湖人是一支和开拓者结构非常类似的球队，Kobe 之于 Roy，Bynum 之于 Oden，Gasol 之于 Aldridge，第一轮的宝贵经验会成为火箭对抗湖人的筹码。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
豆瓣的认证码：doubanclaim5ca247f8bb42286e&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7286295415331143255-4186790087332746880?l=py.thonic.org'/&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/viNoyM-IFDh4EnImBlBMaxKEFT0/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/viNoyM-IFDh4EnImBlBMaxKEFT0/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/viNoyM-IFDh4EnImBlBMaxKEFT0/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/viNoyM-IFDh4EnImBlBMaxKEFT0/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;</content><link rel="replies" type="application/atom+xml" href="http://py.thonic.org/feeds/4186790087332746880/comments/default" title="帖子评论" /><link rel="replies" type="text/html" href="http://py.thonic.org/2009/04/roy.html#comment-form" title="0 条评论" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7286295415331143255/posts/default/4186790087332746880?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7286295415331143255/posts/default/4186790087332746880?v=2" /><link rel="alternate" type="text/html" href="http://py.thonic.org/2009/04/roy.html" title="对 Roy 的挡拆防守 / 火箭破绕前还差三分之一" /><author><name>wyt</name><uri>http://www.blogger.com/profile/04947921907676762514</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="13162551058647906166" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></entry><entry gd:etag="W/&quot;C0EERnk_eyp7ImA9WxJTEU8.&quot;"><id>tag:blogger.com,1999:blog-7286295415331143255.post-4965994348292740685</id><published>2009-04-19T14:06:00.003+08:00</published><updated>2009-04-19T14:13:27.743+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-04-19T14:13:27.743+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="开拓者" /><category scheme="http://www.blogger.com/atom/ns#" term="nba" /><category scheme="http://www.blogger.com/atom/ns#" term="火箭" /><title>姚破绕前／像 Kobe 一样打挡拆／Ron 和 AB 的进攻效率</title><content type="html">今天比赛之前，给火箭列出了三个问题。&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;姚明和火箭如何应对 Przybilla + Oden + Aldridge 的绕前防守？&lt;/b&gt;&lt;br /&gt;
开拓者不会整场比赛都进行绕前，但在关键时刻适当的战术变化却是秃子头上的虱子——明摆的事。应该说，McMillan 今天的绕前来得有点晚，直到第三节的前六分钟开拓者才开始对姚明进行绕前，而这个时候开拓者已经落后20分。不过效果也是立竿见影，Artest 和 Brooks 接连几次不合理的出手，但之后裁判的主场哨反而帮了倒忙。把姚明四次犯规吹下去之后，火箭把防守端的一个大窟窿给补上了。在领先20分的情况下，防守比进攻更显重要，只要不让对手打出高潮，一场胜利基本跑不掉。&lt;br /&gt;
&lt;br /&gt;
但火箭不可能场场比赛都在第三节领先20分，如果在比分焦灼的情况下，开拓者绕前的话，火箭的执行情况会怎样呢？&lt;br /&gt;
&lt;b&gt;&lt;br /&gt;Roy 能不能像 Kobe 一样利用姚明挡拆的弱点？&lt;/b&gt;&lt;br /&gt;
McMillian 从第一节开始就让 Roy 打击姚明的挡拆，并早早的让姚明背上一次犯规。但如果看了 Kobe 对火箭的录像，Kobe 在上半场总是会让队友充分的热身，直到第三节或第四节才开始打挡拆。因为挡拆很难让其他球员融入到整体进攻中来，过早的使用就会陷入今天开拓者的窘境。今天的 Roy，比起 Kobe 来更像前几天和大败给火箭的 Chris Paul。&lt;br /&gt;
&lt;br /&gt;
另外和常规赛不同，姚明在防守挡拆时会出来顶防，而让两个底角的防守者收缩禁区。但开拓者是联盟第一的进攻篮板球球队，如果姚明出去，身后的篮板球是不是会成为另外一个问题？&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Artest 和 Brooks 的进攻效率？&lt;/b&gt;&lt;br /&gt;
说实话，比赛之前，我有点担心 Artest 和 Brooks 的进攻效率。因为本赛季面对跑跳素质出色的防守者的时候，Artest的效率相当糟糕。对湖人的 Ariza 只有 32.6% 的命中率，对开拓者的 Batum 和 Outlaw 也只有 36.4%。Brooks 在三月份虽然能以 44% 的命中率场均砍下 14.9 分，但四月份收官阶段的表现一般，得分和命中率分别只有 9.9 分和 36.1%。&lt;br /&gt;
&lt;br /&gt;
但从今天的表现来看，我是想多了。Artest 的 17分和 AB 的 27分4板7助都是比赛的关键，但两个人唯一的瑕疵都来自于第三节前半段姚明被绕前的时候，也许下次 McMillan 会更早更坚决的执行绕前战术。&lt;br /&gt;
&lt;br /&gt;
总的来说，火箭今天虽然大胜，但仍不足喜。&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;这是开拓者第一场季后赛，这是他们应缴的学费，Aldridge 和其他开拓者球员不可能每一场系列赛都打出这种效率。&lt;/li&gt;
&lt;li&gt;即使在总篮板球数上落后（火箭投失的球少），开拓者还是抓到了 15 个进攻篮板，如果比分焦灼着进入第四节，这会是一个威胁。&lt;/li&gt;
&lt;li&gt;虽然只有短短六分钟，火箭在绕前问题上仍然没有很好的解决方案。&lt;/li&gt;
&lt;/ol&gt;
&lt;br /&gt;
再说个开拓者的亮点，今天 Oden 算是小爆了大叔。不过，如果对比一下大叔对 O'Neal 的防守——双腿趴开，重心前压，两只手死顶在 O'Neal 背上——和对 Oden 的防守——双腿直立，两只手高举，就想着扇个帽摇手指——你就知道大叔多少有点轻敌了。&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7286295415331143255-4965994348292740685?l=py.thonic.org'/&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/NMUjmX528DVi8EllJizLLE8nqic/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/NMUjmX528DVi8EllJizLLE8nqic/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/NMUjmX528DVi8EllJizLLE8nqic/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/NMUjmX528DVi8EllJizLLE8nqic/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;</content><link rel="replies" type="application/atom+xml" href="http://py.thonic.org/feeds/4965994348292740685/comments/default" title="帖子评论" /><link rel="replies" type="text/html" href="http://py.thonic.org/2009/04/kobe-ron-ab.html#comment-form" title="0 条评论" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7286295415331143255/posts/default/4965994348292740685?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7286295415331143255/posts/default/4965994348292740685?v=2" /><link rel="alternate" type="text/html" href="http://py.thonic.org/2009/04/kobe-ron-ab.html" title="姚破绕前／像 Kobe 一样打挡拆／Ron 和 AB 的进攻效率" /><author><name>wyt</name><uri>http://www.blogger.com/profile/04947921907676762514</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="13162551058647906166" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></entry><entry gd:etag="W/&quot;DEAGRH89fCp7ImA9WxVWGU4.&quot;"><id>tag:blogger.com,1999:blog-7286295415331143255.post-8233563007575535616</id><published>2009-03-02T03:33:00.006+08:00</published><updated>2009-03-02T03:45:25.164+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-03-02T03:45:25.164+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="python" /><category scheme="http://www.blogger.com/atom/ns#" term="豆瓣" /><category scheme="http://www.blogger.com/atom/ns#" term="authdouban" /><category scheme="http://www.blogger.com/atom/ns#" term="appengine" /><title>authdouban 快速上手</title><content type="html">&lt;a href="http://github.com/wuyuntao/appengine-authdouban/tree/master" title="authdouban"&gt;authdouban&lt;/a&gt; 是一个即插即用（pluggable）的 AppEngine 应用，可以让你的 web 应用支持&lt;a href="http://www.douban.com/service/apidoc/auth" title="豆瓣的 OAuth 认证"&gt;豆瓣的 OAuth 认证&lt;/a&gt;和管理已授权的豆瓣帐户。authdouban 目前的版本是 &lt;a href="http://github.com/wuyuntao/appengine-authdouban/blob/a5df957e8778d3dfb3d69db060d3efd008683060/VERSION" title="0.1"&gt;0.1&lt;/a&gt;。欢迎大家的建议和意见，你可以 &lt;a href="http://github.com/" title="GitHub"&gt;GitHub&lt;/a&gt; 的仓库中检出或&lt;a href="http://github.com/wuyuntao/appengine-authdouban/zipball/master" title="下载"&gt;下载&lt;/a&gt;。&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;


视图 Views&lt;/h3&gt;
&lt;br /&gt;
authdouban 由下面五个 views 组成。&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;list accounts : 列出用户已授权的豆瓣帐户&lt;/li&gt;
&lt;li&gt;authorize : 将用户被重定向到豆瓣的授权页面。用户同意（不同意）授权后，返回到授权成功（失败）页面&lt;/li&gt;
&lt;li&gt;authorization complete : 授权成功页面&lt;/li&gt;
&lt;li&gt;authorization failure : 授权失败页面&lt;/li&gt;
&lt;li&gt;delete account : 删除已授权的豆瓣帐户&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
&lt;h3&gt;


依赖 Requirements&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://code.google.com/p/gdata-python-client/" title="gdata-python-client"&gt;gdata-python-client&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;&lt;a href="http://code.google.com/p/douban-python/" title="douban-python"&gt;douban-python&lt;/a&gt; &lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
&lt;h3&gt;


设置 Settings&lt;/h3&gt;
&lt;br /&gt;
应用的设置保存在 settings.py，一共有五个选项。首先要填写应用的豆瓣 API key，如果没有的话，你可以到&lt;a href="http://www.douban.com/service/apikey/apply" id="lgdt" title="豆瓣的 API 申请页面"&gt;豆瓣的 API key 申请页面&lt;/a&gt;去填表获得。&lt;br /&gt;
&lt;pre class="codes"&gt;&lt;code&gt;DOUBAN_API_KEY = 'yourapikeyhere'
DOUBAN_API_SECRET = 'yourapisecrethere'&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
选择是否将豆瓣用户的档案信息（比如用户名，城市，头像 URL 等）保存在服务器上。如果是，应将 STORE_DOUBAN_PROFILE 设为 True，反之 False。如果不在服务器上保存，也可以在生成页面时通过 javascript 抓取，这样会比较即时。&lt;br /&gt;
&lt;pre class="codes"&gt;&lt;code&gt;STORE_DOUBAN_PROFILE = True&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
如果把用户资料保存在服务器上，不可避免会有一个资料过期的问题，不过 authdouban 支持自动更新用户档案的信息。你可以修改 MAX_CACHE_TIME 来设置一个缓存的有效时限（默认为 24 小时），也就是如果用户信息最近一次更新的时间超过了 24 小时，则自动从豆瓣抓取新的用户信息。如果将 MAX_CACHE_TIME 设为 0，就永远不会更新用户信息。不过，根据&lt;a href="http://www.douban.com/service/apidoc/terms" id="jvbk" title="豆瓣 API 的使用条款"&gt;豆瓣 API 的使用条款&lt;/a&gt;，在服务器端缓存的用户信息，不能超过 24 小时就是了。&lt;br /&gt;
&lt;pre class="codes"&gt;&lt;code&gt;MAX_CACHE_TIME = 24&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
最后一个选项是 MAX_STORED_ACCOUNTS，你可以用它限定一个用户最多可以授权的豆瓣帐户的数量。设为 0 的话，即为没有限制，不过 AppEngine 最多只能返回 1000 条查询。如果超过了限定，authdouban 会自动删除一个最早授权的豆瓣帐户。&lt;br /&gt;
&lt;pre class="codes"&gt;&lt;code&gt;MAX_STORED_ACCOUNTS = 10&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
&lt;h3&gt;


URL 映射&lt;/h3&gt;
&lt;br /&gt;
URL 映射保存在 urls.py 文件中，和上面的视图相对应。&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;/account/douban/&lt;/li&gt;
&lt;li&gt;/account/douban/authorize/&lt;/li&gt;
&lt;li&gt;/account/douban/authorize/complete/&lt;/li&gt;
&lt;li&gt;/account/douban/authorize/failure/&lt;/li&gt;
&lt;li&gt;/account/douban/delete/&amp;lt;id&amp;gt;/&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
需要特别注意的是&lt;br /&gt;
&lt;blockquote&gt;&lt;p&gt;
如果你修改了 urls.py 中的映射，那你也要改一下 views.py 中相应的 URL（wyt：可以在文件中搜一下 "/account/douban/"）。我不知道 AppEngine 中怎样才能实现像 &lt;a href="http://docs.djangoproject.com/en/dev/topics/http/urls/#reverse" title="django.core.urlresolvers.reverse"&gt;django.core.urlresolvers.reverse&lt;/a&gt;  一样的逆解析，所以只能手动改了。如果有同学知道怎么做，请一定要留言～&lt;/p&gt;&lt;/blockquote&gt;
&lt;br /&gt;
&lt;h3&gt;


模板 Templates&lt;/h3&gt;
&lt;br /&gt;
模板在 templates/authdouban 文件夹下，你可以 copy 到你的应用的模板目录&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;list_account.html : 列出已授权的豆瓣帐户&lt;/li&gt;
&lt;li&gt;delete_account.html : 删除豆瓣帐户的授权&lt;/li&gt;
&lt;li&gt;complete.html : 授权成功&lt;/li&gt;
&lt;li&gt;failure.html : 授权失败&lt;/li&gt;
&lt;li&gt;douban_user.html : 豆瓣用户档案的模板&lt;/li&gt;
&lt;li&gt;douban_user_no_delete.html : 也是豆瓣用户档案的模板，但是没有“删除帐户”的按钮&lt;/li&gt;
&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7286295415331143255-8233563007575535616?l=py.thonic.org'/&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/otSB3mV8sPf6VU72jyz94GBiq5U/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/otSB3mV8sPf6VU72jyz94GBiq5U/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/otSB3mV8sPf6VU72jyz94GBiq5U/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/otSB3mV8sPf6VU72jyz94GBiq5U/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;</content><link rel="replies" type="application/atom+xml" href="http://py.thonic.org/feeds/8233563007575535616/comments/default" title="帖子评论" /><link rel="replies" type="text/html" href="http://py.thonic.org/2009/03/authdouban.html#comment-form" title="0 条评论" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7286295415331143255/posts/default/8233563007575535616?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7286295415331143255/posts/default/8233563007575535616?v=2" /><link rel="alternate" type="text/html" href="http://py.thonic.org/2009/03/authdouban.html" title="authdouban 快速上手" /><author><name>wyt</name><uri>http://www.blogger.com/profile/04947921907676762514</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="13162551058647906166" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></entry><entry gd:etag="W/&quot;DEAGRH89fCp7ImA9WxVWGU4.&quot;"><id>tag:blogger.com,1999:blog-7286295415331143255.post-8586174230749386271</id><published>2009-02-19T00:36:00.011+08:00</published><updated>2009-03-02T03:45:25.164+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-03-02T03:45:25.164+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="python" /><category scheme="http://www.blogger.com/atom/ns#" term="豆瓣" /><category scheme="http://www.blogger.com/atom/ns#" term="authdouban" /><category scheme="http://www.blogger.com/atom/ns#" term="appengine" /><title>authdouban: 在 AppEngine 上管理豆瓣授权帐户</title><content type="html">&lt;a href="http://github.com/wuyuntao/appengine-authdouban/tree/master" title="authdouban"&gt;authdouban&lt;/a&gt;，是一个管理豆瓣授权帐户的即插即用（pluggable）的 AppEngine App，目前支持添加，删除和管理多个经授权的豆瓣帐户。authdouban 还在开发中，非常需要大家的参与和建议，欢迎留言。&lt;br /&gt;
&lt;br /&gt;
买一送一，authdouban 中还包括一个&lt;a href="http://code.google.com/p/douban-python/"&gt;豆瓣官方的 Python 客户端&lt;/a&gt;项目的分支版本。这个分支版本会跟着豆瓣官方的上游版本更新，&lt;strike&gt;但是会将用到 httplib 的代码替换成 urlfetch 方法&lt;/strike&gt;（wyt: &lt;a href="http://googleappengine.blogspot.com/2009/02/sdk-version-119-released.html"&gt;AppEngine SDK 1.1.9&lt;/a&gt; 已经支持 httplib 了，所以不需要再用 urlfetch 替换 httplib 了，不过还是&lt;a href="http://code.google.com/p/douban-python/issues/detail?id=5" title="有些地方需要修改"&gt;有些地方需要修改&lt;/a&gt;），使之在 AppEngine 上可以顺利运行。&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;2009-02-21 更新：&lt;/b&gt;豆瓣接受了&lt;a href="http://code.google.com/p/douban-python/issues/detail?id=5&amp;can=1"&gt;我提交的patch&lt;/a&gt;，所以如果从官方 SVN 中检出最新的（&lt;a href="http://code.google.com/p/douban-python/source/detail?r=47"&gt;r47&lt;/a&gt;）的上游版本和 authdouban 中的分支版本是一样的。&lt;br /&gt;
&lt;br /&gt;
你可以&lt;a href="http://authdouban.luliban.com/account/douban/" title="点击这里"&gt;点击这里&lt;/a&gt;尝试一下用 authdouban 实现的简单界面。下面有几张截图。&lt;br /&gt;
&lt;br /&gt;
授权成功后。&lt;br /&gt;
&lt;div&gt;
&lt;a href="http://lh5.ggpht.com/_sKun2mxXeAk/SZw4XNzcaQI/AAAAAAAAA6s/AT1vN0WvyWc/s800/authentication-complete.png"&gt;&lt;img src="http://lh5.ggpht.com/_sKun2mxXeAk/SZw4XNzcaQI/AAAAAAAAA6s/AT1vN0WvyWc/s400/authentication-complete.png" /&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;br /&gt;
已授权的帐户列表。&lt;br /&gt;
&lt;div&gt;
&lt;a href="http://lh3.ggpht.com/_sKun2mxXeAk/SZw4XAoqG3I/AAAAAAAAA6k/JNB0aXfKEv0/s800/account-list.png"&gt;&lt;img src="http://lh3.ggpht.com/_sKun2mxXeAk/SZw4XAoqG3I/AAAAAAAAA6k/JNB0aXfKEv0/s400/account-list.png" /&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;br /&gt;
删除已授权的豆瓣帐户。&lt;br /&gt;
&lt;div&gt;
&lt;a href="http://lh5.ggpht.com/_sKun2mxXeAk/SZw4XE8Q6AI/AAAAAAAAA60/lEZaAC3i0F4/s800/delete_account.png"&gt;&lt;img src="http://lh5.ggpht.com/_sKun2mxXeAk/SZw4XE8Q6AI/AAAAAAAAA60/lEZaAC3i0F4/s400/delete_account.png" /&gt;&lt;/a&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7286295415331143255-8586174230749386271?l=py.thonic.org'/&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/qZbmxFNWPsGxXmB4DxagK_jX60g/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/qZbmxFNWPsGxXmB4DxagK_jX60g/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/qZbmxFNWPsGxXmB4DxagK_jX60g/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/qZbmxFNWPsGxXmB4DxagK_jX60g/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;</content><link rel="replies" type="application/atom+xml" href="http://py.thonic.org/feeds/8586174230749386271/comments/default" title="帖子评论" /><link rel="replies" type="text/html" href="http://py.thonic.org/2009/02/fork-of-douban-python-client-for.html#comment-form" title="5 条评论" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7286295415331143255/posts/default/8586174230749386271?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7286295415331143255/posts/default/8586174230749386271?v=2" /><link rel="alternate" type="text/html" href="http://py.thonic.org/2009/02/fork-of-douban-python-client-for.html" title="authdouban: 在 AppEngine 上管理豆瓣授权帐户" /><author><name>wyt</name><uri>http://www.blogger.com/profile/04947921907676762514</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="13162551058647906166" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://lh5.ggpht.com/_sKun2mxXeAk/SZw4XNzcaQI/AAAAAAAAA6s/AT1vN0WvyWc/s72-c/authentication-complete.png" height="72" width="72" /><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">5</thr:total></entry><entry gd:etag="W/&quot;A0MFQHc6fCp7ImA9WxVXF0Q.&quot;"><id>tag:blogger.com,1999:blog-7286295415331143255.post-157642369800866086</id><published>2009-02-16T23:40:00.003+08:00</published><updated>2009-02-16T23:50:11.914+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-02-16T23:50:11.914+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="nba" /><title>全明星观感</title><content type="html">Pheonix 有可能是进入21世纪以来最落寞的一届全明星主场。&lt;br /&gt;
&lt;br /&gt;
金融风暴的阴影自不用说。Steve “主场球队的老大外加过去两届常规赛 MVP” Nash，居然被排除在全明星阵容之外，连替补名单 David Stern 也没给个面子。在 O'Neal 的阴影下郁郁不得志的 Amare Stoudamire 被球队放在交易市场上引来超过十支球队（包括火箭）的报价。&lt;a title="太阳的主教练 Terry Porter 半个小时前刚被球队炒了鱿鱼" href="http://bbs.hoopchina.com/536087.html" id="f5wc"&gt;太阳的主教练 Terry Porter 一个小时前刚被球队炒了鱿鱼&lt;/a&gt;，接任者的优点唯有听话二字，用 Stoudamire 的话说，A great players' coach。&lt;br /&gt;
&lt;br /&gt;
聊以欣慰的是，Shaq O'Neal 还是为 Phoenix 的主场球迷还是捧回了全明星赛 MVP 的奖杯。不过比起 Phoenix 来，Shaq 似乎对与他分享奖杯的 Kobe 和教练席上的 Phil Jackson 所在的城市更感兴趣一些。所谓落叶归根嘛。&lt;br /&gt;
&lt;br /&gt;
&lt;h4&gt;&lt;a title="奥尼尔：我把最棒的表演留给全明星赛" href="http://bbs.hoopchina.com/read.php?tid=536633" id="sq4r"&gt;奥尼尔：我把最棒的表演留给全明星赛&lt;/a&gt;&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;奥尼尔依旧是全明星赛上的那个大活宝。不过所有人都对奥尼尔是否能够参与下届全明星赛报以怀疑的态度。即将在3月6日迎来自己37岁生日的奥尼尔本人也不例外。&lt;br&gt;&lt;br&gt;当奥尼尔被问及在球员介绍时候所表演的面具舞时，“Jabberwockees是最专业的舞蹈团队，但是我在舞蹈中尽量表现的出挑。”他接着说，“因为我意识到这也许是我最后一次站在全明星的舞台上了，所以我要在菲尼克斯全明星赛上给所有球迷和我自己都留下令人难忘的表现。”&lt;br&gt;&lt;br&gt;奥尼尔全明星赛出场10分55秒内得到17分5篮3助，他和科比共同分享全明星赛MVP奖杯。赛后西部全明星主教练菲尔-杰克逊说，“这是我第一次见到一名球员仅仅在全明星赛场呆了11分钟就获得了MVP。但是毫无疑问他的表现让人印象深刻。”&lt;/p&gt;&lt;/blockquote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7286295415331143255-157642369800866086?l=py.thonic.org'/&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/V9piWRdm5u2fbIQpYKaQDzmfUWM/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/V9piWRdm5u2fbIQpYKaQDzmfUWM/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/V9piWRdm5u2fbIQpYKaQDzmfUWM/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/V9piWRdm5u2fbIQpYKaQDzmfUWM/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;</content><link rel="replies" type="application/atom+xml" href="http://py.thonic.org/feeds/157642369800866086/comments/default" title="帖子评论" /><link rel="replies" type="text/html" href="http://py.thonic.org/2009/02/blog-post.html#comment-form" title="0 条评论" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7286295415331143255/posts/default/157642369800866086?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7286295415331143255/posts/default/157642369800866086?v=2" /><link rel="alternate" type="text/html" href="http://py.thonic.org/2009/02/blog-post.html" title="全明星观感" /><author><name>wyt</name><uri>http://www.blogger.com/profile/04947921907676762514</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="13162551058647906166" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></entry><entry gd:etag="W/&quot;DEcHRHs-eSp7ImA9WxVSGU8.&quot;"><id>tag:blogger.com,1999:blog-7286295415331143255.post-4593204413899352727</id><published>2009-01-13T10:24:00.006+08:00</published><updated>2009-01-14T17:40:35.551+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-01-14T17:40:35.551+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="blogger" /><category scheme="http://www.blogger.com/atom/ns#" term="豆瓣" /><title>九点，把文章标题还给我的链接～</title><content type="html">&lt;ol&gt;
&lt;li&gt;在九点的阅读器里，只有点击“查看原文”才能进入原帖。点击标题只会扩展文章，而不是像原来的九点一样进入原帖。如
&lt;a href="http://9.douban.com/reader/"&gt;http://9.douban.com/reader/&lt;/a&gt;&amp;nbsp;&lt;/li&gt;
&lt;li&gt;&lt;strike&gt;在某些页面展开文章以后，甚至没有办法找到原帖的链接&lt;/strike&gt;&lt;/li&gt;
&lt;li&gt;有的 feed 只输出摘要，你不得不再点击一次标题收起文章后，才能找到“查看原文”打开原帖&lt;/li&gt;
&lt;li&gt;点击标题栏扩展文章的功能，Google Reader，鲜果和抓虾都有，但她们都会将标题指向原帖，用户点击旁边的留白时才会扩展文章&lt;/li&gt;
&lt;li&gt;一个有些尴尬的设计，看不出对九点有什么实质的好处，可是这对 blogger 并不友好&lt;/li&gt;
&lt;li&gt;没有 blogger 会喜欢一个阅读器抓取他们的内容后，不给链接，或者只给一个12px大小的“查看原文”链接&lt;/li&gt;
&lt;li&gt;总之，请把文章标题还给原文链接，就像在九点的频道里那样～&lt;br /&gt;&lt;/li&gt;
&lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7286295415331143255-4593204413899352727?l=py.thonic.org'/&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/yoc6A9pvo3q6hKSBsrGE0oQA14E/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/yoc6A9pvo3q6hKSBsrGE0oQA14E/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/yoc6A9pvo3q6hKSBsrGE0oQA14E/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/yoc6A9pvo3q6hKSBsrGE0oQA14E/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;</content><link rel="replies" type="application/atom+xml" href="http://py.thonic.org/feeds/4593204413899352727/comments/default" title="帖子评论" /><link rel="replies" type="text/html" href="http://py.thonic.org/2009/01/blog-post.html#comment-form" title="5 条评论" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7286295415331143255/posts/default/4593204413899352727?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7286295415331143255/posts/default/4593204413899352727?v=2" /><link rel="alternate" type="text/html" href="http://py.thonic.org/2009/01/blog-post.html" title="九点，把文章标题还给我的链接～" /><author><name>wyt</name><uri>http://www.blogger.com/profile/04947921907676762514</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="13162551058647906166" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">5</thr:total></entry><entry gd:etag="W/&quot;DUIBRXw5cSp7ImA9WxVRFkk.&quot;"><id>tag:blogger.com,1999:blog-7286295415331143255.post-2722959601827177919</id><published>2009-01-08T14:54:00.015+08:00</published><updated>2009-01-23T02:05:54.229+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-01-23T02:05:54.229+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="javascript" /><category scheme="http://www.blogger.com/atom/ns#" term="豆瓣" /><category scheme="http://www.blogger.com/atom/ns#" term="gears" /><category scheme="http://www.blogger.com/atom/ns#" term="ebookviewer" /><title>eBook Viewer - 用豆瓣 + Gears 管理本地电子书</title><content type="html">&lt;b&gt;&lt;a href="http://ebookviewer.appspot.com/" id="n6bq" title="eBook Viewer"&gt;eBook Viewer&lt;/a&gt; （中文名没想好）是一个用&lt;a href="http://www.douban.com/" id="yuf2" title="豆瓣"&gt;豆瓣&lt;/a&gt;提供的书籍信息管理本地电子书的工具。&lt;/b&gt;用户可以为电子书文件和豆瓣书目建立一一对应的关系，并利用豆瓣搜索来查找和管理这些电子书。欢迎大家试用，如果有什么问题的话，欢迎留言，或者加入 &lt;a href="http://www.douban.com/group/ebookviewer/"&gt;eBook Viewer 小组&lt;/a&gt;讨论。&lt;br /&gt;
&lt;br /&gt;
开发的起因是，我的硬盘上存了 10G+ 电子书，怎样快速的找到想要的书渐渐变成了一个问题。虽然基本上有分类存储，但一些类别很微妙的书就说不清当初放哪里了；还有不少书是从 BT or eMule 上打包拖下来，文件名相当混乱，搜索文件名的办法也不太管用；所以，我想到是不是可以把这些电子书和豆瓣上的条目对应起来，方便以后的查找和管理。于是就有了 eBook Viewer。&lt;br /&gt;
&lt;br /&gt;
eBook Viewer 用到了&lt;a href="http://www.douban.com/service/apidoc/"&gt;豆瓣 API&lt;/a&gt; + &lt;a href="http://gears.google.com/"&gt;Google Gears&lt;/a&gt; 的组合。因为 Gears 提供了 Javascript 跨域访问的功能，所以&lt;a href="http://blog.luliban.com/2008/11/google-gears-api.html"&gt;查询豆瓣 API 的请求&lt;/a&gt;都是从客户端发出的，获取和分析 JSON 用的是自己写的 &lt;a href="http://blog.luliban.com/2008/11/jquery-douban-api-gdata-json.html" id="qlo1" title="jQuery Douban"&gt;jQuery Douban&lt;/a&gt; 插件，可以方便的和 Gears 协同工作。&lt;br /&gt;
&lt;br /&gt;
添加电子书的时候，电子书除了和相关的豆瓣书目一起被记录到数据库之外，eBook Viewer 也将电子书保存到本地的 Store 中，并提供一个本地的下载链接如 &lt;a href="http://ebookviewer.appspot.com/book/wyt/stored/2/Python%20Cookbook.chm" id="t56q" title="http://ebookviewer.appspot.com/book/wyt/stored/2/Python Cookbook.chm"&gt;/book/wyt/stored/2/Python Cookbook.chm&lt;/a&gt;，方便用户想要读这本电子书的时候可以保存到文件夹中。这个链接，虽然看起来像是远程链接，实际上只有在本地才有效。&lt;br /&gt;
&lt;br /&gt;
浏览器。我在 Firefox 3.0.5 (Linux + Windows)，IE 7 和 Chrome 1.0 上测试过 eBook Viewer，都可以正常运行。Safari for Mac 如果有安装 Gears 的话理论上也可以，但我就没有条件测试了。不打算支持 IE6 及其更糟的 IE 浏览器。&lt;br /&gt;
&lt;br /&gt;
如果需要备份系统，问到电子书被保存在哪个文件夹，具体可以参考 &lt;a href="http://code.google.com/apis/gears/api_database.html#directories" id="ap7q" title="Google Gears 的文档"&gt;Google Gears 的文档&lt;/a&gt;。&lt;br /&gt;
&lt;br /&gt;
一般来说，Linux + Firefox 用户的电子书会被保存在&lt;br /&gt;
~/.mozilla/firefox/tb3ujwvc.default/Google\ Gears\ for\ Firefox/ebookviewer.appspot.com/&lt;br /&gt;
&lt;br /&gt;
Windows XP + Firefox 用户是在&lt;br /&gt;
C:\Documents and Settings\Bob\Local Settings\Application Data\Mozilla\Firefox\Profiles\uelib44s.default\Google Gears for Firefox\ebookviewer.appspot.com\&lt;br /&gt;
&lt;br /&gt;
Window XP + IE 用户是在&lt;br /&gt;
C:\Documents and Settings\Bob\Local Settings\Application Data\Google\Google Gears for Internet Explorer\ebookviewer.appspot.com\&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;
eBook Viewer 使用流程&lt;/h3&gt;
第一步，是在右侧的搜索框里输入你想要添加的书本的关键字，如 python，并回车。eBook Viewer 会从豆瓣 API 返回搜索的结果。&lt;br /&gt;
&lt;br /&gt;
&lt;a href="http://lh4.ggpht.com/_sKun2mxXeAk/SWTWXQrSfOI/AAAAAAAAA24/hVHlUaQKawU/s800/0_ready_to_search.png"&gt;&lt;img src="http://lh4.ggpht.com/_sKun2mxXeAk/SWTWXQrSfOI/AAAAAAAAA24/hVHlUaQKawU/s400/0_ready_to_search.png" /&gt;&lt;/a&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;a href="http://lh3.ggpht.com/_sKun2mxXeAk/SWTXUd7x8cI/AAAAAAAAA3c/ko9rAQin12w/s800/1_search_result.png"&gt;&lt;img src="http://lh3.ggpht.com/_sKun2mxXeAk/SWTXUd7x8cI/AAAAAAAAA3c/ko9rAQin12w/s400/1_search_result.png" /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
第二步，选择你想要添加的书如 Python Cookbook，单击右键并“打开”，或者直接双击，弹出一个包含基本的书本信息和电子书存档记录的对话框。&lt;br /&gt;
&lt;br /&gt;
&lt;a href="http://lh3.ggpht.com/_sKun2mxXeAk/SWTXUeFt4tI/AAAAAAAAA3k/rq94fGZj1BQ/s800/2_open_book_dialog.png"&gt;&lt;img src="http://lh3.ggpht.com/_sKun2mxXeAk/SWTXUeFt4tI/AAAAAAAAA3k/rq94fGZj1BQ/s400/2_open_book_dialog.png" /&gt;&lt;/a&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;a href="http://lh4.ggpht.com/_sKun2mxXeAk/SWTXU3AAuGI/AAAAAAAAA3s/iCH1ZeTZo4w/s800/3_book_dialog.png"&gt;&lt;img src="http://lh4.ggpht.com/_sKun2mxXeAk/SWTXU3AAuGI/AAAAAAAAA3s/iCH1ZeTZo4w/s400/3_book_dialog.png" /&gt;&lt;/a&gt;
&lt;br /&gt;
&lt;br /&gt;
第三步，点击“添加电子书”。你可以在弹出的文件对话框中，选中一本或多本电子书，如 Python Cookbook.chm，然后“OK”。一切顺利的话，这个 chm 文件就会被存储到 Gears Store 中，以后打开 Python Cookbok 的时候都可以看到这本电子书，你可以在想读的时候点击文件名，保存到本地文件夹。电子书的格式可以是文本（.txt），网页（.html），PDF 或 CHM 文件。&lt;br /&gt;
&lt;br /&gt;
&lt;a href="http://lh4.ggpht.com/_sKun2mxXeAk/SWTXVIxTQKI/AAAAAAAAA30/8qs_wEUEfEM/s800/4_add_ebook_file.png"&gt;&lt;img src="http://lh4.ggpht.com/_sKun2mxXeAk/SWTXVIxTQKI/AAAAAAAAA30/8qs_wEUEfEM/s400/4_add_ebook_file.png" /&gt;&lt;/a&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;a href="http://lh5.ggpht.com/_sKun2mxXeAk/SWTXVVmTqOI/AAAAAAAAA38/1pvwHboQugw/s800/5_ebook_file_added.png"&gt;&lt;img src="http://lh5.ggpht.com/_sKun2mxXeAk/SWTXVVmTqOI/AAAAAAAAA38/1pvwHboQugw/s400/5_ebook_file_added.png" /&gt;&lt;/a&gt;
&lt;br /&gt;
&lt;br /&gt;
如果你还想添加其他 Python 相关的电子，也不需要从第一步从头开始，你可以直接选择其他的书如 Dive into Python，从第二步开始做下去。如果你想返回初始页面，可以对着空处点击右键并“主页”。这样 eBook Viewer 会显示你已经收藏的电子书，另外右键菜单里可以翻页、选择多种排列和升降序组合。&lt;br /&gt;
&lt;br /&gt;
&lt;a href="http://lh6.ggpht.com/_sKun2mxXeAk/SWTXuYnUYQI/AAAAAAAAA4E/xzN2UVsW4HA/s800/6_back_to_homepage.png"&gt;&lt;img src="http://lh6.ggpht.com/_sKun2mxXeAk/SWTXuYnUYQI/AAAAAAAAA4E/xzN2UVsW4HA/s400/6_back_to_homepage.png" /&gt;&lt;/a&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;a href="http://lh3.ggpht.com/_sKun2mxXeAk/SWTXulYEiWI/AAAAAAAAA4M/_Sf8zCP1CZI/s800/7_home_page_context_menu.png"&gt;&lt;img src="http://lh3.ggpht.com/_sKun2mxXeAk/SWTXulYEiWI/AAAAAAAAA4M/_Sf8zCP1CZI/s400/7_home_page_context_menu.png" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7286295415331143255-2722959601827177919?l=py.thonic.org'/&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/eVA4ndVPR8WoyrJjZFQfjoVxgDI/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/eVA4ndVPR8WoyrJjZFQfjoVxgDI/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/eVA4ndVPR8WoyrJjZFQfjoVxgDI/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/eVA4ndVPR8WoyrJjZFQfjoVxgDI/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;</content><link rel="replies" type="application/atom+xml" href="http://py.thonic.org/feeds/2722959601827177919/comments/default" title="帖子评论" /><link rel="replies" type="text/html" href="http://py.thonic.org/2009/01/ebook-viewer-gears.html#comment-form" title="22 条评论" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7286295415331143255/posts/default/2722959601827177919?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7286295415331143255/posts/default/2722959601827177919?v=2" /><link rel="alternate" type="text/html" href="http://py.thonic.org/2009/01/ebook-viewer-gears.html" title="eBook Viewer - 用豆瓣 + Gears 管理本地电子书" /><author><name>wyt</name><uri>http://www.blogger.com/profile/04947921907676762514</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="13162551058647906166" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://lh4.ggpht.com/_sKun2mxXeAk/SWTWXQrSfOI/AAAAAAAAA24/hVHlUaQKawU/s72-c/0_ready_to_search.png" height="72" width="72" /><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">22</thr:total></entry><entry gd:etag="W/&quot;CkEFSHYzfip7ImA9WxVSEEk.&quot;"><id>tag:blogger.com,1999:blog-7286295415331143255.post-6076599149718368375</id><published>2009-01-03T13:22:00.007+08:00</published><updated>2009-01-04T11:43:39.886+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-01-04T11:43:39.886+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="blogger" /><title>悠言悠闲：2008年 Blog 小结</title><content type="html">&lt;ol&gt;&lt;li&gt;39篇文章。去年初是希望能一周写一篇的，没有达成 :(&lt;br&gt;&lt;/li&gt;&lt;li&gt;&lt;a title="Feedsky" href="http://www.feedsky.com/" id="aint"&gt;Feedsky&lt;/a&gt; 有126个订阅，&lt;a title="FeedBurner" href="http://www.feedburner.com/" id="s2uf"&gt;FeedBurner&lt;/a&gt; 有 35个订阅，原始 feed 在 &lt;a title="Google Reader" href="http://reader.google.com/" id="ty2r"&gt;Google Reader&lt;/a&gt; 有 40 个订阅。水分大大的样子 :)&lt;/li&gt;&lt;li&gt;一年来有 13,000+ 访问和 20,000+ 页面浏览&lt;/li&gt;&lt;li&gt;8月7日是访问最多的一天，有 162 visits，大多数是冲着 &lt;a title="Google Reader 风的豆瓣广播 widget" href="/2008/08/google-reader-style-douban-miniblog.html" id="ecd4"&gt;Google Reader 风的豆瓣广播 widget&lt;/a&gt; 来的。感谢&lt;a title="豆瓣" href="http://www.douban.com/" id="l9qd"&gt;豆瓣&lt;/a&gt;友邻们的推荐先～&lt;/li&gt;&lt;li&gt;浏览器：Firefox 47%, IE 45%, Opera 3.1% and Safari 1.8%. Chrome 貌似很猛，才出场四个月已经有 2.6% :)&lt;br&gt;&lt;/li&gt;&lt;li&gt;操作系统：Windows 80%, Linux 16%, Mac ~3%&lt;br&gt;&lt;/li&gt;&lt;li&gt;搜索引擎：Google 81%。百度 17％，不过10月重定向域名之后，百度就不再收录我的 blog 了...&lt;/li&gt;&lt;li&gt;最多人看的5篇文章：
&lt;ul&gt;&lt;li&gt;&lt;a title="绕过 GHS 用自定义域名发布 Blogger" href="/2008/05/ghs-blogger.html" id="tofk"&gt;绕过 GHS 用自定义域名发布 Blogger&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a title="一个 jQuery 的时间选择插件" href="/2008/08/yet-another-jquery-time-picker-plugin.html" id="hifw"&gt;一个 jQuery 的时间选择插件&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a title="在 Gentoo 上部署 Git + Gitosis 服务器" href="/2008/05/gentoo-git-gitosis.html" id="vz13"&gt;在 Gentoo 上部署 Git + Gitosis 服务器&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a title="在 Google App Engine 上应用豆瓣 Python 客户端" href="/2008/04/google-app-engine-python.html" id="xt8i"&gt;在 Google App Engine 上应用豆瓣 Python 客户端&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a title="Google Reader 风的豆瓣广播 widget" href="/2008/08/google-reader-style-douban-miniblog.html" id="r-qn"&gt;Google Reader 风的豆瓣广播 widget&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;最少人看的5篇文章：&lt;ul&gt;
&lt;li&gt;&lt;a title="用 Gaupol 生成文本字幕" href="/2008/09/gaupol.html" id="gj4-"&gt;用 Gaupol 生成文本字幕&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a title="Firefox 下载日" href="/2008/06/firefox.html" id="xpis"&gt;Firefox 下载日&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a title="Battier or Artest，谁将首发？" href="/2008/09/battier-or-artest.html" id="s7b-"&gt;Battier or Artest，谁将首发？&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a title="用curl获取内网的外部ip" href="/blog/2008/01/curlip.html" id="td50"&gt;用 curl 获取内网的外部 ip&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a title="用 Google Gears 跨域调用豆瓣 API" href="/2008/11/google-gears-api.html" id="ugca"&gt;用 Google Gears 跨域调用豆瓣 API&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;有来自 65 个国家的访问，最多的5个：中国 84%，台湾 4.3%，美国 2.7%，香港 2.4% 和日本 0.94% :)&lt;/li&gt;&lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7286295415331143255-6076599149718368375?l=py.thonic.org'/&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/-pIBJrXKSn7omcGBiQQjykLfMfY/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/-pIBJrXKSn7omcGBiQQjykLfMfY/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/-pIBJrXKSn7omcGBiQQjykLfMfY/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/-pIBJrXKSn7omcGBiQQjykLfMfY/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;</content><link rel="replies" type="application/atom+xml" href="http://py.thonic.org/feeds/6076599149718368375/comments/default" title="帖子评论" /><link rel="replies" type="text/html" href="http://py.thonic.org/2009/01/2008-blog.html#comment-form" title="2 条评论" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7286295415331143255/posts/default/6076599149718368375?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7286295415331143255/posts/default/6076599149718368375?v=2" /><link rel="alternate" type="text/html" href="http://py.thonic.org/2009/01/2008-blog.html" title="悠言悠闲：2008年 Blog 小结" /><author><name>wyt</name><uri>http://www.blogger.com/profile/04947921907676762514</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="13162551058647906166" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">2</thr:total></entry><entry gd:etag="W/&quot;CUEGRng8eyp7ImA9WxVSFEo.&quot;"><id>tag:blogger.com,1999:blog-7286295415331143255.post-6216476679276940335</id><published>2008-12-06T00:15:00.006+08:00</published><updated>2009-01-09T12:00:27.673+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-01-09T12:00:27.673+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="javascript" /><category scheme="http://www.blogger.com/atom/ns#" term="jquery-douban" /><category scheme="http://www.blogger.com/atom/ns#" term="greasemonkey" /><title>有备无患：用 jQuery Douban 写 GreaseMonkey 脚本</title><content type="html">&lt;a title="jQuery Douban" href="http://blog.luliban.com/2008/11/jquery-douban-api-gdata-json.html" id="bax7"&gt;jQuery Douban&lt;/a&gt; 是一个简化豆瓣 API 应用开发的 jQuery 插件。jQuery Douban 支持用 GM_xmlhttpRequest 方法实现跨域访问，所以我们可以在 GreaseMonkey 脚本中方便的调用豆瓣 API。这篇文章会以&lt;a title="友邻高亮脚本" href="http://userscripts.org/scripts/show/38149" id="bh3b"&gt;友邻高亮脚本&lt;/a&gt;为例，说明在 GreaseMonkey 中使用 jQuery Douban 的方法。&lt;br /&gt;&lt;br /&gt;

&lt;b&gt;Metadata。&lt;/b&gt;jquery.douban.js 依赖于 jquery.js、sha1.js 和 oauth.js，所以我们首先要在 UserScript Metadata 中加入这四个 js 文件。&lt;br /&gt;
&lt;pre class="codes"&gt;&lt;code&gt;&lt;span style="color: rgb(96, 160, 176);"&gt;&lt;i&gt;// ==UserScript==&lt;/i&gt;&lt;/span&gt;
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt;&lt;span style="color: rgb(96, 160, 176);"&gt;&lt;i&gt;// @name&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Douban Highlight Friends Script&lt;/i&gt;&lt;/span&gt;
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt;&lt;span style="color: rgb(96, 160, 176);"&gt;&lt;i&gt;// @namespace&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; http://blog.luliban.com/&lt;/i&gt;&lt;/span&gt;
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt;&lt;span style="color: rgb(96, 160, 176);"&gt;&lt;i&gt;// @description&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Highlight all your friends and contacts on every douban page&lt;/i&gt;&lt;/span&gt;
&lt;span class="lineno special"&gt;&lt;/span&gt;&lt;span style="color: rgb(96, 160, 176);"&gt;&lt;i&gt;// @include&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; http://www.douban.com/*&lt;/i&gt;&lt;/span&gt;
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt;&lt;b&gt;&lt;span style="color: rgb(96, 160, 176);"&gt;&lt;i&gt;// @require&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; http://jquery-douban.appspot.com/media/scripts/jquery.js&lt;/i&gt;&lt;/span&gt;
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt;&lt;span style="color: rgb(96, 160, 176);"&gt;&lt;i&gt;// @require&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; http://jquery-douban.appspot.com/media/scripts/sha1.js&lt;/i&gt;&lt;/span&gt;
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt;&lt;span style="color: rgb(96, 160, 176);"&gt;&lt;i&gt;// @require&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; http://jquery-douban.appspot.com/media/scripts/oauth.js&lt;/i&gt;&lt;/span&gt;
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt;&lt;span style="color: rgb(96, 160, 176);"&gt;&lt;i&gt;// @require&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; http://jquery-douban.appspot.com/media/scripts/jquery.douban.js&lt;/i&gt;&lt;/span&gt;&lt;/b&gt;
&lt;span class="lineno special"&gt;&lt;/span&gt;&lt;span style="color: rgb(96, 160, 176);"&gt;&lt;i&gt;// ==/UserScript==&lt;/i&gt;&lt;/span&gt;
&lt;span style="color: rgb(96, 160, 176);"&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;

&lt;b&gt;初始化豆瓣 service。&lt;/b&gt;除了向豆瓣申请的 API key 之外，用 $.douban 创建 service 实例的时候，还要将 type 设为 'greasemonkey'，这样就可以用 GM_xmlhttpRequest 方法来跨域访问豆瓣 API 了。&lt;br /&gt;

&lt;pre class="codes"&gt;&lt;code&gt;&lt;span style="color: rgb(96, 160, 176);"&gt;&lt;i&gt;// API key&lt;/i&gt;&lt;/span&gt;
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 112, 32);"&gt;&lt;b&gt;var&lt;/b&gt;&lt;/span&gt; api_key &lt;span style="color: rgb(102, 102, 102);"&gt;=&lt;/span&gt; &lt;span style="color: rgb(64, 112, 160);"&gt;'0107c5c3c9d4eaa40317514b5d7ec64c'&lt;/span&gt;&lt;span style="color: rgb(102, 102, 102);"&gt;;&lt;/span&gt;
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 112, 32);"&gt;&lt;b&gt;var&lt;/b&gt;&lt;/span&gt; api_secret &lt;span style="color: rgb(102, 102, 102);"&gt;=&lt;/span&gt; &lt;span style="color: rgb(64, 112, 160);"&gt;'7feaf4ec7b6779f8'&lt;/span&gt;&lt;span style="color: rgb(102, 102, 102);"&gt;;&lt;/span&gt;

&lt;span style="color: rgb(96, 160, 176);"&gt;&lt;i&gt;// 初始化豆瓣service&lt;/i&gt;&lt;/span&gt;
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 112, 32);"&gt;&lt;b&gt;var&lt;/b&gt;&lt;/span&gt; service &lt;span style="color: rgb(102, 102, 102);"&gt;=&lt;/span&gt; $.douban({
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp; key&lt;span style="color: rgb(102, 102, 102);"&gt;:&lt;/span&gt; api_key&lt;span style="color: rgb(102, 102, 102);"&gt;,&lt;/span&gt;
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp; secret&lt;span style="color: rgb(102, 102, 102);"&gt;:&lt;/span&gt; api_secret&lt;span style="color: rgb(102, 102, 102);"&gt;,&lt;/span&gt;
&lt;span class="lineno special"&gt;&lt;/span&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;b&gt;type&lt;span style="color: rgb(102, 102, 102);"&gt;:&lt;/span&gt; &lt;span style="color: rgb(64, 112, 160);"&gt;'greasemonkey'&lt;/span&gt;&lt;/b&gt;
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt; });
&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;

&lt;b&gt;OAuth 授权认证。&lt;/b&gt;虽然用户的友邻不是受限资源，即使不进行 OAuth 认证也一样可以获得，但是 OAuth 认证在豆瓣 API 应用中常常会用到，所以还是应该写一下 OAuth 认证。&lt;br /&gt;
&lt;br /&gt;
下面这段代码实现了获取 request token，将用户重定向到授权页面，用户同意授权后获取 access token 的过程。如果怕麻烦的话，可以把这段代码直接拷贝到你的脚本中。不过需要注意一下加粗的三行，将其中的两行限定了可以执行获取 access token 命令的页面，另外一条将授权命令注册到 GreaseMonkey 的脚本命令（User Script Commands）中。&lt;br /&gt;

&lt;pre class="codes"&gt;&lt;code&gt;&lt;span style="color: rgb(96, 160, 176);"&gt;&lt;i&gt;// 获取已存的 request token 和 access token&lt;/i&gt;&lt;/span&gt;
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 112, 32);"&gt;&lt;b&gt;var&lt;/b&gt;&lt;/span&gt; request_key &lt;span style="color: rgb(102, 102, 102);"&gt;=&lt;/span&gt; GM_getValue(&lt;span style="color: rgb(64, 112, 160);"&gt;'request_key'&lt;/span&gt;&lt;span style="color: rgb(102, 102, 102);"&gt;,&lt;/span&gt; &lt;span style="color: rgb(64, 112, 160);"&gt;''&lt;/span&gt;);
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 112, 32);"&gt;&lt;b&gt;var&lt;/b&gt;&lt;/span&gt; request_secret &lt;span style="color: rgb(102, 102, 102);"&gt;=&lt;/span&gt; GM_getValue(&lt;span style="color: rgb(64, 112, 160);"&gt;'request_secret'&lt;/span&gt;&lt;span style="color: rgb(102, 102, 102);"&gt;,&lt;/span&gt; &lt;span style="color: rgb(64, 112, 160);"&gt;''&lt;/span&gt;);
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 112, 32);"&gt;&lt;b&gt;var&lt;/b&gt;&lt;/span&gt; access_key &lt;span style="color: rgb(102, 102, 102);"&gt;=&lt;/span&gt; GM_getValue(&lt;span style="color: rgb(64, 112, 160);"&gt;'access_key'&lt;/span&gt;&lt;span style="color: rgb(102, 102, 102);"&gt;,&lt;/span&gt; &lt;span style="color: rgb(64, 112, 160);"&gt;''&lt;/span&gt;);
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 112, 32);"&gt;&lt;b&gt;var&lt;/b&gt;&lt;/span&gt; access_secret &lt;span style="color: rgb(102, 102, 102);"&gt;=&lt;/span&gt; GM_getValue(&lt;span style="color: rgb(64, 112, 160);"&gt;'access_secret'&lt;/span&gt;&lt;span style="color: rgb(102, 102, 102);"&gt;,&lt;/span&gt; &lt;span style="color: rgb(64, 112, 160);"&gt;''&lt;/span&gt;);
&lt;span class="lineno special"&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 112, 32);"&gt;&lt;b&gt;var&lt;/b&gt;&lt;/span&gt; user_id &lt;span style="color: rgb(102, 102, 102);"&gt;=&lt;/span&gt; GM_getValue(&lt;span style="color: rgb(64, 112, 160);"&gt;'user_id'&lt;/span&gt;&lt;span style="color: rgb(102, 102, 102);"&gt;,&lt;/span&gt; &lt;span style="color: rgb(64, 112, 160);"&gt;''&lt;/span&gt;);

&lt;span style="color: rgb(0, 112, 32);"&gt;&lt;b&gt;if&lt;/b&gt;&lt;/span&gt; (access_key) {
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: rgb(96, 160, 176);"&gt;&lt;i&gt;// 如果 access token 已存，直接登录&lt;/i&gt;&lt;/span&gt;
&lt;span class="lineno special"&gt;&lt;/span&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp; service.login({ key&lt;span style="color: rgb(102, 102, 102);"&gt;:&lt;/span&gt; access_key&lt;span style="color: rgb(102, 102, 102);"&gt;,&lt;/span&gt; secret&lt;span style="color: rgb(102, 102, 102);"&gt;:&lt;/span&gt; access_secret });
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt;
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: rgb(96, 160, 176);"&gt;&lt;i&gt;// 然后做些什么……&lt;/i&gt;&lt;/span&gt;
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt; &lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt; &lt;b&gt;} &lt;span style="color: rgb(0, 112, 32);"&gt;else&lt;/span&gt; &lt;span style="color: rgb(0, 112, 32);"&gt;if&lt;/span&gt; (request_key &lt;span style="color: rgb(102, 102, 102);"&gt;&amp;amp;&amp;amp;&lt;/span&gt; location.href.match(&lt;span style="color: rgb(35, 83, 136);"&gt;/#friend_marker/&lt;/span&gt;)) {&lt;/b&gt;
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: rgb(96, 160, 176);"&gt;&lt;i&gt;// 如果只有 request token 已存，则用request key获取相应的 access token&lt;/i&gt;&lt;/span&gt;
&lt;span class="lineno special"&gt;&lt;/span&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp; service.getAccessToken({
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; key&lt;span style="color: rgb(102, 102, 102);"&gt;:&lt;/span&gt; request_key&lt;span style="color: rgb(102, 102, 102);"&gt;,&lt;/span&gt;
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; secret&lt;span style="color: rgb(102, 102, 102);"&gt;:&lt;/span&gt; request_secret
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;span style="color: rgb(102, 102, 102);"&gt;,&lt;/span&gt; onAccessToken);
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt; }&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt;&lt;span style="color: rgb(96, 160, 176);"&gt;&lt;/span&gt;
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt;
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt;&lt;span style="color: rgb(96, 160, 176);"&gt;&lt;i&gt;// 设置授权命令&lt;/i&gt;&lt;/span&gt;
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 112, 32);"&gt;&lt;b&gt;function&lt;/b&gt;&lt;/span&gt; authorize() {
&lt;span class="lineno special"&gt;&lt;/span&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: rgb(96, 160, 176);"&gt;&lt;i&gt;// 清除已存的 access token&lt;/i&gt;&lt;/span&gt;
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp; GM_setValue(&lt;span style="color: rgb(64, 112, 160);"&gt;'access_key'&lt;/span&gt;&lt;span style="color: rgb(102, 102, 102);"&gt;,&lt;/span&gt; &lt;span style="color: rgb(64, 112, 160);"&gt;''&lt;/span&gt;);
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp; GM_setValue(&lt;span style="color: rgb(64, 112, 160);"&gt;'access_secret'&lt;/span&gt;&lt;span style="color: rgb(102, 102, 102);"&gt;,&lt;/span&gt; &lt;span style="color: rgb(64, 112, 160);"&gt;''&lt;/span&gt;);
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp; GM_setValue(&lt;span style="color: rgb(64, 112, 160);"&gt;'user_id'&lt;/span&gt;&lt;span style="color: rgb(102, 102, 102);"&gt;,&lt;/span&gt; &lt;span style="color: rgb(64, 112, 160);"&gt;''&lt;/span&gt;);
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt;
&lt;span class="lineno special"&gt;&lt;/span&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: rgb(96, 160, 176);"&gt;&lt;i&gt;// 获取 request token&lt;/i&gt;&lt;/span&gt;
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp; service.getRequestToken(onRequestToken);
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt; }
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt; &lt;b&gt;GM_registerMenuCommand(&lt;span style="color: rgb(64, 112, 160);"&gt;"授权豆瓣帐户（高亮友邻脚本）"&lt;/span&gt;&lt;span style="color: rgb(102, 102, 102);"&gt;,&lt;/span&gt; authorize);&lt;/b&gt;

&lt;span style="color: rgb(96, 160, 176);"&gt;&lt;i&gt;// 处理获取 request token 响应&lt;/i&gt;&lt;/span&gt;
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 112, 32);"&gt;&lt;b&gt;function&lt;/b&gt;&lt;/span&gt; onRequestToken(token) {
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: rgb(0, 112, 32);"&gt;&lt;b&gt;if&lt;/b&gt;&lt;/span&gt; (token.key) {
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: rgb(0, 112, 32);"&gt;&lt;b&gt;if&lt;/b&gt;&lt;/span&gt; (confirm(&lt;span style="color: rgb(64, 112, 160);"&gt;"现在将转入授权页面，请选择同意授权。授权成功后，将返回当前页面"&lt;/span&gt;)) {
&lt;span class="lineno special"&gt;&lt;/span&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: rgb(96, 160, 176);"&gt;&lt;i&gt;// 保存 request token&lt;/i&gt;&lt;/span&gt;
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; GM_setValue(&lt;span style="color: rgb(64, 112, 160);"&gt;'request_key'&lt;/span&gt;&lt;span style="color: rgb(102, 102, 102);"&gt;,&lt;/span&gt; token.key);
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; GM_setValue(&lt;span style="color: rgb(64, 112, 160);"&gt;'request_secret'&lt;/span&gt;&lt;span style="color: rgb(102, 102, 102);"&gt;,&lt;/span&gt; token.secret);
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt;
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: rgb(96, 160, 176);"&gt;&lt;i&gt;// 重定向到授权页面&lt;/i&gt;&lt;/span&gt;
&lt;span class="lineno special"&gt;&lt;/span&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; setTimeout(&lt;span style="color: rgb(0, 112, 32);"&gt;&lt;b&gt;function&lt;/b&gt;&lt;/span&gt;() {
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;b&gt;location.href &lt;span style="color: rgb(102, 102, 102);"&gt;=&lt;/span&gt; service.getAuthorizationUrl(token&lt;span style="color: rgb(102, 102, 102);"&gt;,&lt;/span&gt; location.href &lt;span style="color: rgb(102, 102, 102);"&gt;+&lt;/span&gt; &lt;span style="color: rgb(64, 112, 160);"&gt;'#friend_marker'&lt;/span&gt;);&lt;/b&gt;
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;span style="color: rgb(102, 102, 102);"&gt;,&lt;/span&gt; &lt;span style="color: rgb(64, 160, 112);"&gt;500&lt;/span&gt;);
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;span style="color: rgb(0, 112, 32);"&gt;&lt;b&gt;else&lt;/b&gt;&lt;/span&gt; {
&lt;span class="lineno special"&gt;&lt;/span&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; alert(&lt;span style="color: rgb(64, 112, 160);"&gt;'授权失败，请稍后再试。'&lt;/span&gt;);
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp; }
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt; }
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt;
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt;&lt;span style="color: rgb(96, 160, 176);"&gt;&lt;i&gt;// 处理获取 access token 响应&lt;/i&gt;&lt;/span&gt;
&lt;span class="lineno special"&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 112, 32);"&gt;&lt;b&gt;function&lt;/b&gt;&lt;/span&gt; onAccessToken(token&lt;span style="color: rgb(102, 102, 102);"&gt;,&lt;/span&gt; user_id) {
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: rgb(0, 112, 32);"&gt;&lt;b&gt;if&lt;/b&gt;&lt;/span&gt; (token.key) {
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: rgb(96, 160, 176);"&gt;&lt;i&gt;// 保存 access token 和用户id&lt;/i&gt;&lt;/span&gt;
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; GM_setValue(&lt;span style="color: rgb(64, 112, 160);"&gt;'access_key'&lt;/span&gt;&lt;span style="color: rgb(102, 102, 102);"&gt;,&lt;/span&gt; token.key);
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; GM_setValue(&lt;span style="color: rgb(64, 112, 160);"&gt;'access_secret'&lt;/span&gt;&lt;span style="color: rgb(102, 102, 102);"&gt;,&lt;/span&gt; token.secret);
&lt;span class="lineno special"&gt;&lt;/span&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; GM_setValue(&lt;span style="color: rgb(64, 112, 160);"&gt;'user_id'&lt;/span&gt;&lt;span style="color: rgb(102, 102, 102);"&gt;,&lt;/span&gt; user_id);
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt;
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: rgb(96, 160, 176);"&gt;&lt;i&gt;// 清除 request token&lt;/i&gt;&lt;/span&gt;
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; GM_setValue(&lt;span style="color: rgb(64, 112, 160);"&gt;'request_key'&lt;/span&gt;&lt;span style="color: rgb(102, 102, 102);"&gt;,&lt;/span&gt; &lt;span style="color: rgb(64, 112, 160);"&gt;''&lt;/span&gt;);
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; GM_setValue(&lt;span style="color: rgb(64, 112, 160);"&gt;'request_secret'&lt;/span&gt;&lt;span style="color: rgb(102, 102, 102);"&gt;,&lt;/span&gt; &lt;span style="color: rgb(64, 112, 160);"&gt;''&lt;/span&gt;);
&lt;span class="lineno special"&gt;&lt;/span&gt;
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: rgb(96, 160, 176);"&gt;&lt;i&gt;// 登录 service&lt;/i&gt;&lt;/span&gt;
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; service.login(token);
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;span style="color: rgb(0, 112, 32);"&gt;&lt;b&gt;else&lt;/b&gt;&lt;/span&gt; {
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; alert(&lt;span style="color: rgb(64, 112, 160);"&gt;'授权失败，请稍后再试。'&lt;/span&gt;);
&lt;span class="lineno special"&gt;&lt;/span&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp; }
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt; }&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;

&lt;b&gt;更新友邻列表。&lt;/b&gt;虽然文档中多是同步获取的方式，不过实际上却是用异步获取的时候比较多，所以 jQuery Douban 的 GreaseMonkey HTTP handler 并不支持同步获取数据（Gears 也是这样）。获取朋友和关注列表分别是用 service.user.friends 和 service.user.contacts，不过一次最多只能获取 50 个用户，所以这里用递归将获得的用户都加入一个数组，然后将数组中的用户名 join 后保存到 GreaseMonkey。&lt;br /&gt;

&lt;pre class="codes"&gt;&lt;code&gt;&lt;span style="color: rgb(96, 160, 176);"&gt;&lt;/span&gt;&lt;span style="color: rgb(96, 160, 176);"&gt;&lt;/span&gt;&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt;&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt;&lt;span style="color: rgb(96, 160, 176);"&gt;&lt;i&gt;&lt;/i&gt;&lt;/span&gt;&lt;span style="color: rgb(102, 102, 102);"&gt;&lt;/span&gt;&lt;span class="lineno special"&gt;&lt;/span&gt;&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt;&lt;span style="color: rgb(96, 160, 176);"&gt;&lt;/span&gt;&lt;span style="color: rgb(102, 102, 102);"&gt;&lt;/span&gt;&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt;&lt;span class="lineno special"&gt;&lt;/span&gt;&lt;span style="color: rgb(96, 160, 176);"&gt;&lt;/span&gt;&lt;span class="lineno special"&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 112, 32);"&gt;&lt;b&gt;var&lt;/b&gt;&lt;/span&gt; friends &lt;span style="color: rgb(102, 102, 102);"&gt;=&lt;/span&gt; GM_getValue(&lt;span style="color: rgb(64, 112, 160);"&gt;'friends'&lt;/span&gt;&lt;span style="color: rgb(102, 102, 102);"&gt;,&lt;/span&gt; &lt;span style="color: rgb(64, 112, 160);"&gt;''&lt;/span&gt;);
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 112, 32);"&gt;&lt;b&gt;var&lt;/b&gt;&lt;/span&gt; contacts &lt;span style="color: rgb(102, 102, 102);"&gt;=&lt;/span&gt; GM_getValue(&lt;span style="color: rgb(64, 112, 160);"&gt;'contacts'&lt;/span&gt;&lt;span style="color: rgb(102, 102, 102);"&gt;,&lt;/span&gt; &lt;span style="color: rgb(64, 112, 160);"&gt;''&lt;/span&gt;);
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt;
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt;&lt;span style="color: rgb(96, 160, 176);"&gt;&lt;i&gt;&lt;/i&gt;&lt;/span&gt;&lt;span class="lineno special"&gt;&lt;/span&gt;&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt;&lt;span style="color: rgb(96, 160, 176);"&gt;&lt;/span&gt;&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt;&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 112, 32);"&gt;&lt;/span&gt;&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt;&lt;span class="lineno special"&gt;&lt;/span&gt;&lt;span style="color: rgb(96, 160, 176);"&gt;&lt;i&gt;// 更新朋友列表&lt;/i&gt;&lt;/span&gt;
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 112, 32);"&gt;&lt;b&gt;function&lt;/b&gt;&lt;/span&gt; get_friends(offset) {
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp; offset &lt;span style="color: rgb(102, 102, 102);"&gt;=&lt;/span&gt; offset &lt;span style="color: rgb(102, 102, 102);"&gt;||&lt;/span&gt; &lt;span style="color: rgb(64, 160, 112);"&gt;0&lt;/span&gt;&lt;span style="color: rgb(102, 102, 102);"&gt;;&lt;/span&gt;
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: rgb(96, 160, 176);"&gt;&lt;i&gt;// 新建临时列表&lt;/i&gt;&lt;/span&gt;
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: rgb(0, 112, 32);"&gt;&lt;b&gt;if&lt;/b&gt;&lt;/span&gt; (offset &lt;span style="color: rgb(102, 102, 102);"&gt;==&lt;/span&gt; &lt;span style="color: rgb(64, 160, 112);"&gt;0&lt;/span&gt;) &lt;span style="color: rgb(0, 112, 32);"&gt;window&lt;/span&gt;._friends &lt;span style="color: rgb(102, 102, 102);"&gt;=&lt;/span&gt; [];
&lt;span class="lineno special"&gt;&lt;/span&gt;
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;b&gt;service.user.friends(user_id&lt;span style="color: rgb(102, 102, 102);"&gt;,&lt;/span&gt; offset&lt;span style="color: rgb(102, 102, 102);"&gt;,&lt;/span&gt; &lt;span style="color: rgb(64, 160, 112);"&gt;50&lt;/span&gt;&lt;span style="color: rgb(102, 102, 102);"&gt;,&lt;/span&gt; &lt;span style="color: rgb(0, 112, 32);"&gt;function&lt;/span&gt;(users) {&lt;/b&gt;
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: rgb(96, 160, 176);"&gt;&lt;i&gt;// 如果没有取到所有的朋友，则继续抓取&lt;/i&gt;&lt;/span&gt;
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: rgb(0, 112, 32);"&gt;&lt;b&gt;if&lt;/b&gt;&lt;/span&gt; (users.total &lt;span style="color: rgb(102, 102, 102);"&gt;&amp;amp;&amp;amp;&lt;/span&gt; (offset &lt;span style="color: rgb(102, 102, 102);"&gt;+&lt;/span&gt; &lt;span style="color: rgb(64, 160, 112);"&gt;50&lt;/span&gt; &lt;span style="color: rgb(102, 102, 102);"&gt;&amp;lt;&lt;/span&gt; users.total)) {
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; get_friends(offset &lt;span style="color: rgb(102, 102, 102);"&gt;+&lt;/span&gt; &lt;span style="color: rgb(64, 160, 112);"&gt;50&lt;/span&gt;);
&lt;span class="lineno special"&gt;&lt;/span&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt;
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: rgb(0, 112, 32);"&gt;&lt;b&gt;if&lt;/b&gt;&lt;/span&gt; (users.entries) {
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: rgb(96, 160, 176);"&gt;&lt;i&gt;// 将获得的朋友的id，加入临时列表&lt;/i&gt;&lt;/span&gt;
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; $.each(users.entries&lt;span style="color: rgb(102, 102, 102);"&gt;,&lt;/span&gt; &lt;span style="color: rgb(0, 112, 32);"&gt;&lt;b&gt;function&lt;/b&gt;&lt;/span&gt;() {
&lt;span class="lineno special"&gt;&lt;/span&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: rgb(0, 112, 32);"&gt;window&lt;/span&gt;._friends.push(&lt;span style="color: rgb(0, 112, 32);"&gt;&lt;b&gt;this&lt;/b&gt;&lt;/span&gt;.userName);
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; });
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt;
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: rgb(96, 160, 176);"&gt;&lt;i&gt;// 保存朋友列表&lt;/i&gt;&lt;/span&gt;
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; GM_setValue(&lt;span style="color: rgb(64, 112, 160);"&gt;'friends'&lt;/span&gt;&lt;span style="color: rgb(102, 102, 102);"&gt;,&lt;/span&gt; &lt;span style="color: rgb(64, 112, 160);"&gt;'|'&lt;/span&gt; &lt;span style="color: rgb(102, 102, 102);"&gt;+&lt;/span&gt; &lt;span style="color: rgb(0, 112, 32);"&gt;window&lt;/span&gt;._friends.join(&lt;span style="color: rgb(64, 112, 160);"&gt;'|'&lt;/span&gt;) &lt;span style="color: rgb(102, 102, 102);"&gt;+&lt;/span&gt; &lt;span style="color: rgb(64, 112, 160);"&gt;'|'&lt;/span&gt;);
&lt;span class="lineno special"&gt;&lt;/span&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;b&gt;});&lt;/b&gt;
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt; }&lt;span style="color: rgb(96, 160, 176);"&gt;&lt;i&gt;&lt;/i&gt;&lt;/span&gt;

&lt;span style="color: rgb(96, 160, 176);"&gt;&lt;i&gt;// 更新关注列表&lt;/i&gt;&lt;/span&gt;
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 112, 32);"&gt;&lt;b&gt;function&lt;/b&gt;&lt;/span&gt; get_contacts(offset) { ... }&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;

上面这些代码就是友邻高亮脚本中用到 jQuery Douban 的部分了。不是很多，但也包括了初始化 service，OAuth 授权认证和获取豆瓣 API 这些关键的部分了。如果正想动手写一个 GreaseMonkey 脚本的话，希望会有帮助。如果有任何建议，问题或BUG，欢迎留言 FIX ME :-)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7286295415331143255-6216476679276940335?l=py.thonic.org'/&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/vw_dtMNR328rXx69p0JEjd4SiNE/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/vw_dtMNR328rXx69p0JEjd4SiNE/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/vw_dtMNR328rXx69p0JEjd4SiNE/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/vw_dtMNR328rXx69p0JEjd4SiNE/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;</content><link rel="replies" type="application/atom+xml" href="http://py.thonic.org/feeds/6216476679276940335/comments/default" title="帖子评论" /><link rel="replies" type="text/html" href="http://py.thonic.org/2008/12/jquery-douban-greasemonkey.html#comment-form" title="5 条评论" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7286295415331143255/posts/default/6216476679276940335?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7286295415331143255/posts/default/6216476679276940335?v=2" /><link rel="alternate" type="text/html" href="http://py.thonic.org/2008/12/jquery-douban-greasemonkey.html" title="有备无患：用 jQuery Douban 写 GreaseMonkey 脚本" /><author><name>wyt</name><uri>http://www.blogger.com/profile/04947921907676762514</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="13162551058647906166" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">5</thr:total></entry><entry gd:etag="W/&quot;DkcGSH0_eSp7ImA9WxVSFEo.&quot;"><id>tag:blogger.com,1999:blog-7286295415331143255.post-4072278807636066763</id><published>2008-11-28T17:10:00.008+08:00</published><updated>2009-01-09T12:07:09.341+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-01-09T12:07:09.341+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="javascript" /><category scheme="http://www.blogger.com/atom/ns#" term="jquery-douban" /><category scheme="http://www.blogger.com/atom/ns#" term="豆瓣" /><title>jQuery Douban － 简化豆瓣 API 开发的 jQuery 插件</title><content type="html">&lt;h3&gt;什么是 jQuery Douban&lt;/h3&gt;

&lt;a title="jQuery Douban" href="http://jquery-douban.appspot.com/" id="bax7"&gt;jQuery Douban&lt;/a&gt; 是一个简化豆瓣 API 调用和 GData JSON 分析的 jQuery 插件，支持 OAuth 授权认证和各种豆瓣数据读写操作的功能。目前支持的API有用户、条目、收藏、评论、广播、日记、推荐和标签 API，部分支持同城活动的 API。这里有一个简单的&lt;a href="http://jquery-douban.appspot.com/example/book_list/"&gt;读取用户收藏的 Demo&lt;/a&gt;。&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;什么时候使用 jQuery Douban&lt;/h3&gt;
&lt;ul&gt;
    &lt;li&gt;你正好在用 jQuery&lt;/li&gt;
    &lt;li&gt;你正好想从客户端调用豆瓣 API，而不是从服务器&lt;/li&gt;
    &lt;li&gt;或者你正在为豆瓣编写 GreaseMonkey 脚本&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
&lt;h3&gt;为什么不直接使用豆瓣API&lt;/h3&gt;
&lt;ul&gt;
    &lt;li&gt;更喜欢 jQuery 风格的代码&lt;/li&gt;
    &lt;li&gt;可以用有跨域超能力 Javascript 库，比如 Gears&lt;/li&gt;
    &lt;li&gt;看到 {"$t":"9787543632608","@name":"isbn13"} 风格的JSON 会头晕&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
&lt;h3&gt;怎样使用 jQuery Douban&lt;/h3&gt;
示范添加一条广播先。 &lt;br /&gt;
jQuery Douban 依赖于 jquery，oauth 和 sha1 三个 js 库，所以先要导入这三个 js 文件。&lt;br /&gt;
&lt;pre class="codes"&gt;&lt;code&gt;&lt;span style="color: rgb(6, 40, 115);"&gt;&lt;b&gt;&amp;lt;script &lt;/b&gt;&lt;/span&gt;&lt;span style="color: rgb(64, 112, 160);"&gt;type=&lt;/span&gt;&lt;span style="color: rgb(64, 112, 160);"&gt;"text/javascript"&lt;/span&gt; &lt;span style="color: rgb(64, 112, 160);"&gt;src=&lt;/span&gt;&lt;span style="color: rgb(64, 112, 160);"&gt;"/scripts/jquery.js"&lt;/span&gt; &lt;span style="color: rgb(6, 40, 115);"&gt;&lt;b&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/b&gt;&lt;/span&gt;
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt;&lt;span style="color: rgb(6, 40, 115);"&gt;&lt;b&gt;&amp;lt;script &lt;/b&gt;&lt;/span&gt;&lt;span style="color: rgb(64, 112, 160);"&gt;type=&lt;/span&gt;&lt;span style="color: rgb(64, 112, 160);"&gt;"text/javascript"&lt;/span&gt; &lt;span style="color: rgb(64, 112, 160);"&gt;src=&lt;/span&gt;&lt;span style="color: rgb(64, 112, 160);"&gt;"/scripts/sha1.js"&lt;/span&gt; &lt;span style="color: rgb(6, 40, 115);"&gt;&lt;b&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/b&gt;&lt;/span&gt;
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt;&lt;span style="color: rgb(6, 40, 115);"&gt;&lt;b&gt;&amp;lt;script &lt;/b&gt;&lt;/span&gt;&lt;span style="color: rgb(64, 112, 160);"&gt;type=&lt;/span&gt;&lt;span style="color: rgb(64, 112, 160);"&gt;"text/javascript"&lt;/span&gt; &lt;span style="color: rgb(64, 112, 160);"&gt;src=&lt;/span&gt;&lt;span style="color: rgb(64, 112, 160);"&gt;"/scripts/oauth.js"&lt;/span&gt; &lt;span style="color: rgb(6, 40, 115);"&gt;&lt;b&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/b&gt;&lt;/span&gt;
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt;&lt;span style="color: rgb(6, 40, 115);"&gt;&lt;b&gt;&amp;lt;script &lt;/b&gt;&lt;/span&gt;&lt;span style="color: rgb(64, 112, 160);"&gt;type=&lt;/span&gt;&lt;span style="color: rgb(64, 112, 160);"&gt;"text/javascript"&lt;/span&gt; &lt;span style="color: rgb(64, 112, 160);"&gt;src=&lt;/span&gt;&lt;span style="color: rgb(64, 112, 160);"&gt;"/scripts/jquery.douban.js"&lt;/span&gt; &lt;span style="color: rgb(6, 40, 115);"&gt;&lt;b&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/b&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

然后可以添加广播了&lt;br /&gt;

&lt;pre class="codes"&gt;&lt;code&gt;&lt;span style="color: rgb(96, 160, 176);"&gt;&lt;i&gt;// 创建豆瓣服务实例&lt;/i&gt;&lt;/span&gt;
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 112, 32);"&gt;&lt;b&gt;var&lt;/b&gt;&lt;/span&gt; service &lt;span style="color: rgb(102, 102, 102);"&gt;=&lt;/span&gt; $.douban({ key&lt;span style="color: rgb(102, 102, 102);"&gt;:&lt;/span&gt; &lt;span style="color: rgb(64, 112, 160);"&gt;"apiKey"&lt;/span&gt;&lt;span style="color: rgb(102, 102, 102);"&gt;,&lt;/span&gt; secret&lt;span style="color: rgb(102, 102, 102);"&gt;:&lt;/span&gt; &lt;span style="color: rgb(64, 112, 160);"&gt;"apiSecret"&lt;/span&gt; });
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt;&lt;span style="color: rgb(96, 160, 176);"&gt;&lt;i&gt;// 登录豆瓣帐户&lt;/i&gt;&lt;/span&gt;
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 112, 32);"&gt;&lt;b&gt;var&lt;/b&gt;&lt;/span&gt; login &lt;span style="color: rgb(102, 102, 102);"&gt;=&lt;/span&gt; service.login({ key&lt;span style="color: rgb(102, 102, 102);"&gt;:&lt;/span&gt; &lt;span style="color: rgb(64, 112, 160);"&gt;"accessKey"&lt;/span&gt;&lt;span style="color: rgb(102, 102, 102);"&gt;,&lt;/span&gt; secret&lt;span style="color: rgb(102, 102, 102);"&gt;:&lt;/span&gt; &lt;span style="color: rgb(64, 112, 160);"&gt;"accessSecret"&lt;/span&gt;});
&lt;span class="lineno special"&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 112, 32);"&gt;&lt;b&gt;if&lt;/b&gt;&lt;/span&gt; (login) {
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt;&lt;span style="color: rgb(96, 160, 176);"&gt;&lt;i&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&lt;/i&gt;&lt;i&gt; // 添加一条广播&lt;/i&gt;&lt;/span&gt;
&amp;nbsp;&amp;nbsp; &amp;nbsp;&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt; &lt;span style="color: rgb(0, 112, 32);"&gt;&lt;b&gt;var&lt;/b&gt;&lt;/span&gt; miniblog &lt;span style="color: rgb(102, 102, 102);"&gt;=&lt;/span&gt; service.miniblog.add({ content: &lt;span style="color: rgb(64, 112, 160);"&gt;"添加一条广播"&lt;/span&gt; });
&amp;nbsp;&amp;nbsp; &amp;nbsp;&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt; &lt;span style="color: rgb(96, 160, 176);"&gt;&lt;i&gt;// 弹出“添加成功：添加一条广播”&lt;/i&gt;&lt;/span&gt;
&amp;nbsp;&amp;nbsp; &amp;nbsp;&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt; alert(&lt;span style="color: rgb(64, 112, 160);"&gt;"添加成功："&lt;/span&gt; &lt;span style="color: rgb(102, 102, 102);"&gt;+&lt;/span&gt; miniblog.content);
&amp;nbsp;&amp;nbsp; &amp;nbsp;&lt;span class="lineno special"&gt;&lt;/span&gt; &lt;span style="color: rgb(96, 160, 176);"&gt;&lt;i&gt;// 删除一条广播&lt;/i&gt;&lt;/span&gt;
&amp;nbsp;&amp;nbsp; &amp;nbsp;&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt; service.miniblog.remove(miniblog);
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt; }
&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;哪里可以得到 jQuery Douban&lt;/h3&gt;
jQuery Douban 的主页是在 Google Code 上，Homepage: &lt;a href="http://code.google.com/p/jquery-douban/"&gt;http://code.google.com/p/jquery-douban/&lt;/a&gt;。
但代码用 &lt;a href="http://github.com/"&gt;GitHub&lt;/a&gt; 来管理，Repo URL： &lt;a title="http://github.com/wuyuntao/jquery-douban/tree/master" href="http://github.com/wuyuntao/jquery-douban/tree/master" id="jo2w"&gt;http://github.com/wuyuntao/jquery-douban/tree/master&lt;/a&gt;。可以用 Git 检出代码 &lt;pre class="commands"&gt;&lt;code&gt;$ git clone git://github.com/wuyuntao/jquery-douban.git&lt;/code&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7286295415331143255-4072278807636066763?l=py.thonic.org'/&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/yUTQts11dbmLhsT2rG_mmy_Y89w/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/yUTQts11dbmLhsT2rG_mmy_Y89w/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/yUTQts11dbmLhsT2rG_mmy_Y89w/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/yUTQts11dbmLhsT2rG_mmy_Y89w/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;</content><link rel="replies" type="application/atom+xml" href="http://py.thonic.org/feeds/4072278807636066763/comments/default" title="帖子评论" /><link rel="replies" type="text/html" href="http://py.thonic.org/2008/11/jquery-douban-api-gdata-json.html#comment-form" title="5 条评论" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7286295415331143255/posts/default/4072278807636066763?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7286295415331143255/posts/default/4072278807636066763?v=2" /><link rel="alternate" type="text/html" href="http://py.thonic.org/2008/11/jquery-douban-api-gdata-json.html" title="jQuery Douban － 简化豆瓣 API 开发的 jQuery 插件" /><author><name>wyt</name><uri>http://www.blogger.com/profile/04947921907676762514</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="13162551058647906166" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">5</thr:total></entry><entry gd:etag="W/&quot;DUEHSHc_cSp7ImA9WxRUF0k.&quot;"><id>tag:blogger.com,1999:blog-7286295415331143255.post-8681861225244374721</id><published>2008-11-27T00:23:00.007+08:00</published><updated>2008-11-27T09:00:39.949+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-11-27T09:00:39.949+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="javascript" /><category scheme="http://www.blogger.com/atom/ns#" term="豆瓣" /><category scheme="http://www.blogger.com/atom/ns#" term="google" /><category scheme="http://www.blogger.com/atom/ns#" term="gears" /><title>有备无患：用 Google Gears 跨域调用豆瓣 API</title><content type="html">有两种可以实现 Gears 的跨域（Cross-Origin）访问的办法。第一种相对安全，但是要在豆瓣的服务器上安置一个 &lt;a title="cross-origin worker" href="http://code.google.com/apis/gears/gears_faq.html#crossOriginWorker" rel="nofollow"&gt;cross-origin worker&lt;/a&gt;。&lt;br&gt;
&lt;br&gt;
&lt;blockquote&gt;&lt;p&gt;Cross-origin worker 可以由 &lt;a title="WorkerPool API" href="http://code.google.com/apis/gears/api_workerpool.html" id="ri.g"&gt;WorkerPool API&lt;/a&gt; 创建。WorkerPool 类似于线程池的概念，它让 javascript 从页面上解放出来，可以在后台独立运行，父子 workers 之间也可以互相通信，而且不同服务器上的 workers（也就是 Cross-origin workers）也可以互相传递数据，这样就实现了一个安全的浏览器跨域访问方式。&lt;br&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;br&gt;
当然，我们不可能在豆瓣的服务器上动手脚。所以，我们只能在迂回中前进，第二种方法就是自建一个跨域代理（cross-origin proxy），并在上面安置 worker 供 Gears 调用，尽管这有被 XSS 攻击的潜在风险。&lt;br&gt;
&lt;br&gt;
举例来说，我们要从 http://foo.com/ 上调用豆瓣 API，发送一条广播到 http://api.douban.com/miniblog/saying。这通常受到 Same-Origin Policy 的限制。所以，我们通过父 worker 向安置在跨域代理上的 cross-origin worker 发送指令，让它去访问 http://bar.com/proxy?url=http://api.douban.com/people/wyt。成功后，从向本地的 worker 报告工作成果。&lt;br&gt;
&lt;br&gt;
&lt;p&gt;我先用 &lt;a title="App Engine" href="http://code.google.com/appengine/" rel="nofollow"&gt;App Engine&lt;/a&gt; 写了一个&lt;a title="简单的跨域代理" href="http://github.com/wuyuntao/jquery-douban/tree/master/apps%2Fproxy.py" id="w.ih"&gt;简单的跨域代理&lt;/a&gt;，仅做参考。然后在 app.yaml 中设置好 worker.js 的访问路径。&lt;br&gt;
&lt;/p&gt;
&lt;pre class="codes"&gt;&lt;code&gt;- url: /worker.js
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt; &amp;nbsp; static_files: media/scripts/worker.js
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt; &amp;nbsp; upload: media/scripts/worker.js
&lt;/code&gt;&lt;/pre&gt;
&lt;br&gt;
接着编写 worker.js。以前 Gears 只可以在 workers 之间传递文本，现在已经可以传递函数（function）以外的其他对象，比如 Array 和 Object。所以我们可以向 cross-origin worker 传递一个包含了 HTTP request 所需参数的字典（dict），比如说&lt;br&gt;
&lt;br&gt;
&lt;pre class="codes"&gt;&lt;code&gt;&lt;span style="color: rgb(0, 112, 32);"&gt;&lt;b&gt;var&lt;/b&gt;&lt;/span&gt; options = {
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: rgb(64, 112, 160);"&gt;'url'&lt;/span&gt;: &lt;span style="color: rgb(64, 112, 160);"&gt;'http://bar.com/proxy?url=http://api.douban.com/miniblogs/saying'&lt;/span&gt;,
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: rgb(64, 112, 160);"&gt;'type'&lt;/span&gt;: &lt;span style="color: rgb(64, 112, 160);"&gt;'POST'&lt;/span&gt;,
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: rgb(64, 112, 160);"&gt;'headers'&lt;/span&gt;: {
&lt;span class="lineno special"&gt;&lt;/span&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: rgb(64, 112, 160);"&gt;'Authorization'&lt;/span&gt;: &lt;span style="color: rgb(64, 112, 160);"&gt;'OAuth realm="", ...'&lt;/span&gt;,
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: rgb(64, 112, 160);"&gt;'Content-Type'&lt;/span&gt;: &lt;span style="color: rgb(64, 112, 160);"&gt;'application/atom+xml'&lt;/span&gt;
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp; },
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: rgb(64, 112, 160);"&gt;'data'&lt;/span&gt;: &lt;span style="color: rgb(64, 112, 160);"&gt;'&amp;lt;?xml version="1.0" encoding="UTF-8"?&amp;gt;&amp;lt;entry ...'&lt;/span&gt;
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt; };
&lt;/code&gt;&lt;/pre&gt;
&lt;br&gt;
worker.js 中通过 Gears 的 HttpRequest API，向代理发送请求，并将代理返回的结果发送给本地的父 worker 供浏览器调用。这里有一个简单的实现 &lt;a title="gears_worker.js" href="http://github.com/wuyuntao/jquery-douban/tree/master/src%2Fgears_worker.js" id="hub5"&gt;gears_worker.js&lt;/a&gt;，只做了返回成功后的处理。&lt;br&gt;
&lt;br&gt;
&lt;pre class="codes"&gt;&lt;code&gt;&lt;span style="color: rgb(96, 160, 176);"&gt;&lt;i&gt;// 新建 Worker&lt;/i&gt;&lt;/span&gt;
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 112, 32);"&gt;&lt;b&gt;var&lt;/b&gt;&lt;/span&gt; wp &lt;span style="color: rgb(102, 102, 102);"&gt;=&lt;/span&gt; google.gears.workerPool&lt;span style="color: rgb(102, 102, 102);"&gt;;&lt;/span&gt;
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt;
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt;&lt;span style="color: rgb(96, 160, 176);"&gt;&lt;i&gt;// 允许 Worker 跨域脚本访问&lt;/i&gt;&lt;/span&gt;
&lt;span class="lineno special"&gt;&lt;/span&gt; wp.allowCrossOrigin();
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt;
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt; wp.onmessage &lt;span style="color: rgb(102, 102, 102);"&gt;=&lt;/span&gt; &lt;span style="color: rgb(0, 112, 32);"&gt;&lt;b&gt;function&lt;/b&gt;&lt;/span&gt;(a&lt;span style="color: rgb(102, 102, 102);"&gt;,&lt;/span&gt; b&lt;span style="color: rgb(102, 102, 102);"&gt;,&lt;/span&gt; message) {
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: rgb(0, 112, 32);"&gt;&lt;b&gt;var&lt;/b&gt;&lt;/span&gt; s &lt;span style="color: rgb(102, 102, 102);"&gt;=&lt;/span&gt; message.body&lt;span style="color: rgb(102, 102, 102);"&gt;;&lt;/span&gt;
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt;
&lt;span class="lineno special"&gt;&lt;/span&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: rgb(96, 160, 176);"&gt;&lt;i&gt;// 新建 HTTP Request&lt;/i&gt;&lt;/span&gt;
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: rgb(0, 112, 32);"&gt;&lt;b&gt;var&lt;/b&gt;&lt;/span&gt; request &lt;span style="color: rgb(102, 102, 102);"&gt;=&lt;/span&gt; google.gears.factory.create(&lt;span style="color: rgb(64, 112, 160);"&gt;'beta.httprequest'&lt;/span&gt;);
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt;
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp; request.onreadystatechange &lt;span style="color: rgb(102, 102, 102);"&gt;=&lt;/span&gt; &lt;span style="color: rgb(0, 112, 32);"&gt;&lt;b&gt;function&lt;/b&gt;&lt;/span&gt;() {
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: rgb(96, 160, 176);"&gt;&lt;i&gt;// 将响应文本返回给父 Worker&lt;/i&gt;&lt;/span&gt;
&lt;span class="lineno special"&gt;&lt;/span&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: rgb(0, 112, 32);"&gt;&lt;b&gt;if&lt;/b&gt;&lt;/span&gt; (request.readyState &lt;span style="color: rgb(102, 102, 102);"&gt;==&lt;/span&gt; &lt;span style="color: rgb(64, 160, 112);"&gt;4&lt;/span&gt;) {
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; wp.sendMessage(request.responseText&lt;span style="color: rgb(102, 102, 102);"&gt;,&lt;/span&gt; message.sender);
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp; };
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt;
&lt;span class="lineno special"&gt;&lt;/span&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: rgb(96, 160, 176);"&gt;&lt;i&gt;// 打开 URL&lt;/i&gt;&lt;/span&gt;
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp; request.open(s.type&lt;span style="color: rgb(102, 102, 102);"&gt;,&lt;/span&gt; s.url);
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt;
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: rgb(96, 160, 176);"&gt;&lt;i&gt;// 设置请求 Headers&lt;/i&gt;&lt;/span&gt;
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: rgb(0, 112, 32);"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/span&gt; (&lt;span style="color: rgb(0, 112, 32);"&gt;&lt;b&gt;var&lt;/b&gt;&lt;/span&gt; name &lt;span style="color: rgb(0, 112, 32);"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/span&gt; s.headers)
&lt;span class="lineno special"&gt;&lt;/span&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; request.setRequestHeader(name&lt;span style="color: rgb(102, 102, 102);"&gt;,&lt;/span&gt; s.headers[name]);
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt;
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: rgb(96, 160, 176);"&gt;&lt;i&gt;// 发送请求&lt;/i&gt;&lt;/span&gt;
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: rgb(0, 112, 32);"&gt;&lt;b&gt;if&lt;/b&gt;&lt;/span&gt; (s.data) request.send(s.data);
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: rgb(0, 112, 32);"&gt;&lt;b&gt;else&lt;/b&gt;&lt;/span&gt; request.send()
&lt;span class="lineno special"&gt;&lt;/span&gt; };
&lt;/code&gt;&lt;/pre&gt;
         全都部署完成之后，我们就可以在 http://foo.com/ 上通过运行 javascript 调用豆瓣 API 了。下面是一个示例&lt;br&gt;
&lt;pre class="codes"&gt;&lt;code&gt;&lt;span style="color: rgb(96, 160, 176);"&gt;&lt;i&gt;// 新建 WorkerPool&lt;/i&gt;&lt;/span&gt;
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 112, 32);"&gt;&lt;b&gt;var&lt;/b&gt;&lt;/span&gt; workerPool &lt;span style="color: rgb(102, 102, 102);"&gt;=&lt;/span&gt; google.gears.factory.create(&lt;span style="color: rgb(64, 112, 160);"&gt;'beta.workerpool'&lt;/span&gt;);
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt;
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt;&lt;span style="color: rgb(96, 160, 176);"&gt;&lt;i&gt;// 处理响应&lt;/i&gt;&lt;/span&gt;
&lt;span class="lineno special"&gt;&lt;/span&gt; workerPool.onmessage &lt;span style="color: rgb(102, 102, 102);"&gt;=&lt;/span&gt; &lt;span style="color: rgb(0, 112, 32);"&gt;&lt;b&gt;function&lt;/b&gt;&lt;/span&gt;(a&lt;span style="color: rgb(102, 102, 102);"&gt;,&lt;/span&gt; b&lt;span style="color: rgb(102, 102, 102);"&gt;,&lt;/span&gt; message) {
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: rgb(0, 112, 32);"&gt;&lt;b&gt;var&lt;/b&gt;&lt;/span&gt; data &lt;span style="color: rgb(102, 102, 102);"&gt;=&lt;/span&gt; &lt;span style="color: rgb(0, 112, 32);"&gt;eval&lt;/span&gt;(&lt;span style="color: rgb(64, 112, 160);"&gt;"("&lt;/span&gt; &lt;span style="color: rgb(102, 102, 102);"&gt;+&lt;/span&gt; message.body &lt;span style="color: rgb(102, 102, 102);"&gt;+&lt;/span&gt; &lt;span style="color: rgb(64, 112, 160);"&gt;")"&lt;/span&gt;);
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp; alert(data);
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt; };
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt;
&lt;span class="lineno special"&gt;&lt;/span&gt;&lt;span style="color: rgb(96, 160, 176);"&gt;&lt;i&gt;// 创建子 worker 并将预先定义好的 options 字典发送过去&lt;/i&gt;&lt;/span&gt;
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 112, 32);"&gt;&lt;b&gt;var&lt;/b&gt;&lt;/span&gt; childWorkerId &lt;span style="color: rgb(102, 102, 102);"&gt;=&lt;/span&gt; workerPool.createWorkerFromUrl(&lt;span style="color: rgb(64, 112, 160);"&gt;'http://bar.com/worker.js'&lt;/span&gt;);
&lt;span style="color: rgb(96, 160, 176);" class="lineno"&gt;&lt;/span&gt; workerPool.sendMessage(options&lt;span style="color: rgb(102, 102, 102);"&gt;,&lt;/span&gt; childWorkerId);
&lt;/code&gt;&lt;/pre&gt;
      &lt;br&gt;这样部署好之后，就可以用 Google Gears 跨域调用豆瓣 API 了。但还是有一个问题，因为所有的请求都集中到跨域代理，如果没有申请放宽限制的话，很快就会被 403 吧。果然，最好的办法还是豆瓣官方支持 Gears 的远程调用吗？&lt;br&gt;
&lt;br&gt;
&lt;h4&gt;参考页面&lt;/h4&gt;
&lt;ul&gt;&lt;li&gt;&lt;a title="Cross Domain messaging with gears" href="http://gearsblog.blogspot.com/2008/03/cross-domain-messaging-with-gears.html" id="maup"&gt;Cross Domain messaging with gears&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a title="Crossdomain proxy on Google App Engine" href="http://w00kie.com/2008/06/18/crossdomain-proxy-on-google-app-engine/" id="ju6v"&gt;Crossdomain proxy on Google App Engine&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a title="WorkerPool API" href="http://code.google.com/apis/gears/api_workerpool.html#typical_use" id="kb26"&gt;WorkerPool API&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a title="What is a cross-origin worker? What is it useful for? How do I use it?" href="http://code.google.com/apis/gears/gears_faq.html#crossOriginWorker" id="h7xh"&gt;What is a cross-origin worker? What is it useful for? How do I use it?&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;
 
 
&lt;br /&gt;
&lt;br /&gt;
&lt;br&gt;
P.S. Blogger.com 莫名的被 GFWed 了。为什么 Blogger API 可以通过 https:// 访问，可 Blogger 自己却不可以像 GMail 和 GDocs 一样通过 https:// 呢，现在就只能靠 GDocs 发布了。。。 &lt;br&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7286295415331143255-8681861225244374721?l=py.thonic.org'/&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/BV95raOBjYuPKS5Wh0IfSiAaHng/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/BV95raOBjYuPKS5Wh0IfSiAaHng/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/BV95raOBjYuPKS5Wh0IfSiAaHng/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/BV95raOBjYuPKS5Wh0IfSiAaHng/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;</content><link rel="replies" type="application/atom+xml" href="http://py.thonic.org/feeds/8681861225244374721/comments/default" title="帖子评论" /><link rel="replies" type="text/html" href="http://py.thonic.org/2008/11/google-gears-api.html#comment-form" title="4 条评论" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7286295415331143255/posts/default/8681861225244374721?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7286295415331143255/posts/default/8681861225244374721?v=2" /><link rel="alternate" type="text/html" href="http://py.thonic.org/2008/11/google-gears-api.html" title="有备无患：用 Google Gears 跨域调用豆瓣 API" /><author><name>wyt</name><uri>http://www.blogger.com/profile/04947921907676762514</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="13162551058647906166" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">4</thr:total></entry><entry gd:etag="W/&quot;CEcDQ3w4fyp7ImA9WxRQGUQ.&quot;"><id>tag:blogger.com,1999:blog-7286295415331143255.post-2011015186662215924</id><published>2008-10-14T20:53:00.002+08:00</published><updated>2008-10-14T21:47:52.237+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-10-14T21:47:52.237+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="linux" /><title>悠言悠闲：linux 下玩／wine 東方地霊殿</title><content type="html">&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://1.bp.blogspot.com/_sKun2mxXeAk/SPSYxHEixdI/AAAAAAAAAtU/O3691Fz5D0Q/s1600-h/touhou-chireiden-start.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img src="http://1.bp.blogspot.com/_sKun2mxXeAk/SPSYxHEixdI/AAAAAAAAAtU/_jqIquXwUDY/s400-R/touhou-chireiden-start.png" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a rel="nofollow" href="http://www16.big.or.jp/~zun/html/th11top.html"&gt;东方地灵殿&lt;/a&gt;（東方地霊殿 〜 Subterranean Animism.）是日本同人社团&lt;a rel="nofollow" href="http://zh.wikipedia.org/wiki/%E4%B8%8A%E6%B5%B7%E3%82%A2%E3%83%AA%E3%82%B9%E5%B9%BB%E6%A8%82%E5%9B%A3"&gt;上海爱莉丝幻乐团&lt;/a&gt;制作的一款弹幕系射击游戏&lt;/li&gt;
&lt;li&gt;wine 的版本为 1.1.5&lt;/li&gt;
&lt;li&gt;无法启动 th11.exe，需要&lt;a rel="nofollow" href="http://www.dll-files.com/dllindex/dll-files.shtml?d3dx9_36"&gt;下载&lt;/a&gt;，或者从 Windows 下面复制一个 d3dx9_36.dll 文件，
&lt;pre class="commands"&gt;&lt;code&gt;$ cp d3dx9_36.dll ～/.wine/drive_c/windows/system32/&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;运行地灵殿的窗口模式的时候，分辨率似乎被限制在了640x480。&lt;a rel="nofollow"  href="http://forum.ubuntu.org.cn/viewtopic.php?f=121&amp;t=144249"&gt;没有找到解决办法&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;如果使用虚拟桌面（Virtual Desktop） + 地灵殿的全屏模式，感觉会有点卡，帧速降到50fps左右&lt;/li&gt;
&lt;li&gt;如果使用虚拟桌面 + 窗口模式，游戏界面黑屏有声音&lt;/li&gt;
&lt;li&gt;如果取消虚拟桌面 + 窗口模式，感觉上速度和 Windows 下面差不多，不过限速 60fps，实际差多少也不知道就对了&lt;/li&gt;
&lt;li&gt;运行正确的话，wine 应该只会输出下面这几行消息，
&lt;pre class="commands"&gt;&lt;code&gt;$ wine th11.exe 
fixme:win:EnumDisplayDevicesW ((null),0,0x32f8d4,0x00000000), stub!
fixme:d3d:WineD3D_ChoosePixelFormat Add OpenGL context recreation support to SetDepthStencilSurface
fixme:d3d:WineD3D_ChoosePixelFormat Add OpenGL context recreation support to SetDepthStencilSurface
fixme:win:WINNLSEnableIME hUnknown1 (nil) bUnknown2 1: stub!
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;有一篇更加详细的说明，&lt;a href="http://d.hatena.ne.jp/lugia/20080718/1216352077"&gt;東方地霊殿に関するメモ&lt;/a&gt;（日语）&lt;/li&gt;
&lt;/ol&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://4.bp.blogspot.com/_sKun2mxXeAk/SPSY3WJkAWI/AAAAAAAAAtc/VlB01fVRxX4/s1600-h/touhou-chireiden.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img src="http://4.bp.blogspot.com/_sKun2mxXeAk/SPSY3WJkAWI/AAAAAAAAAtc/vN0WTvw5vB0/s400-R/touhou-chireiden.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7286295415331143255-2011015186662215924?l=py.thonic.org'/&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/4e7OlJ3I_il50jW7vGEjF4DAc9U/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/4e7OlJ3I_il50jW7vGEjF4DAc9U/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/4e7OlJ3I_il50jW7vGEjF4DAc9U/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/4e7OlJ3I_il50jW7vGEjF4DAc9U/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;</content><link rel="replies" type="application/atom+xml" href="http://py.thonic.org/feeds/2011015186662215924/comments/default" title="帖子评论" /><link rel="replies" type="text/html" href="http://py.thonic.org/2008/10/wine.html#comment-form" title="7 条评论" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7286295415331143255/posts/default/2011015186662215924?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7286295415331143255/posts/default/2011015186662215924?v=2" /><link rel="alternate" type="text/html" href="http://py.thonic.org/2008/10/wine.html" title="悠言悠闲：linux 下玩／wine 東方地霊殿" /><author><name>wyt</name><uri>http://www.blogger.com/profile/04947921907676762514</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="13162551058647906166" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/_sKun2mxXeAk/SPSYxHEixdI/AAAAAAAAAtU/_jqIquXwUDY/s72-Rc/touhou-chireiden-start.png" height="72" width="72" /><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">7</thr:total></entry><entry gd:etag="W/&quot;A04FQnY6fip7ImA9WxVRFkQ.&quot;"><id>tag:blogger.com,1999:blog-7286295415331143255.post-4431373542880290926</id><published>2008-09-20T15:55:00.013+08:00</published><updated>2009-01-23T16:38:33.816+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-01-23T16:38:33.816+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="javascript" /><category scheme="http://www.blogger.com/atom/ns#" term="greasemonkey" /><category scheme="http://www.blogger.com/atom/ns#" term="豆瓣" /><category scheme="http://www.blogger.com/atom/ns#" term="google" /><category scheme="http://www.blogger.com/atom/ns#" term="gears" /><title>有备无患：豆瓣离线 - 利用 Google Gears 实现离线浏览豆瓣的 GreaseMonkey 脚本</title><content type="html">&lt;b&gt;&lt;a href="http://blog.luliban.com/2008/09/douban-offline-greasemonkey-google.html"&gt;豆瓣离线&lt;/a&gt;（Douban Offline）是一个可以让用户可以离线浏览豆瓣的 &lt;a href="https://addons.mozilla.org/firefox/addon/748" id="i5o1" rel="nofollow" title="GreaseMonkey"&gt;GreaseMonkey&lt;/a&gt; 脚本。&lt;/b&gt;&lt;b&gt;它可以在网络无法使用的情况下，浏览保存在本地的页面。它也可以用来收藏或备份豆瓣上的条目、小组和友邻等页面。&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
豆瓣离线使用 &lt;a href="http://code.google.com/apis/gears/" id="tqm4" rel="nofollow" title="Google Gears API"&gt;Google Gears API&lt;/a&gt; 来实现离线浏览的功能。&lt;a href="http://gears.google.com/" id="hzqn" rel="nofollow" title="Google Gears"&gt;Google Gears&lt;/a&gt; 是一款 &lt;a class="mw-redirect" href="http://zh.wikipedia.org/w/index.php?title=Google&amp;amp;variant=zh-cn" rel="nofollow" title="Google"&gt;Google&lt;/a&gt; 开发的软件。Gears 通过 &lt;a href="http://zh.wikipedia.org/w/index.php?title=SQLite&amp;amp;variant=zh-cn" rel="nofollow" title="SQLite"&gt;SQLite&lt;/a&gt; 
数据库让客户端能够把网页暂存起来，并通过内部服务器（Local server）把数据库中暂存的网页重现，从而让用户实现离线上网的功能。&lt;a href="http://docs.google.com/" rel="nofollow" title="Google Docs"&gt;Google Docs&lt;/a&gt; 和 &lt;a href="http://reader.google.com/" rel="nofollow" title="Google Reader"&gt;Google Reader&lt;/a&gt; 都支持用 Gears 将本地暂存的资料与网络做同步。&lt;br /&gt;
&lt;br /&gt;
豆瓣离线现在版本为 0.1，还有许多的不完善之处，欢迎大家的建议、意见和 Bug 报告:-)&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: left;"&gt;
&lt;a href="http://3.bp.blogspot.com/_sKun2mxXeAk/SNSuTFxQpXI/AAAAAAAAAs0/AnbkR1tYWbQ/s1600-h/screen_shot_1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://3.bp.blogspot.com/_sKun2mxXeAk/SNSuTFxQpXI/AAAAAAAAAs0/FL7UYli7t_U/s400-R/screen_shot_1.png" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;h3&gt;


功能&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;保存豆瓣上的某个页面，以及相关的图片、CSS 和 Javascript 脚本&lt;/li&gt;
&lt;li&gt;按分类浏览已缓存的页面，目前的分类有：条目，小组和用户&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
&lt;h3&gt;




使用方法&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;如果希望保存当前页面，我们先找到导航栏“退出”附近的“离线”。点击“离线”，待离线状态栏展开完毕后，点击“离线”下面的“收藏此页面”。注意，点击之后不要马上关闭窗口，因为相关的文件可能还在下载中。另外我们也可以打开 FireBug 的终端（Console）来看看究竟那些文件被下载下来了。&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;如果希望浏览已缓存的页面，&lt;del&gt;点击 Firefox -&amp;gt; File（文件） -&amp;gt; Work Offline（离线工作）来强制 Firefox 进入离线工作的状态。&lt;/del&gt;点击“离线” -&gt; “离线浏览”，然后在缓存页面目录，我们可以点击其中的链接访问已被缓存的页面。&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;如果希望恢复在线浏览，在同样的地方点击“在线浏览”。&lt;/li&gt;
&lt;li&gt;第一次使用豆瓣离线脚本时，Gears 会弹出两个安全警告对话框，都选择 Allow（允许）就可以了。&lt;br /&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
&lt;h3&gt;
安装需求&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Firefox (&amp;gt;=3.0.0): &lt;a href="http://www.mozilla.com/en-US/firefox/" rel="nofollow"&gt;http://www.mozilla.com/en-US/firefox/&lt;/a&gt; &lt;br /&gt;&lt;/li&gt;
&lt;li&gt;
GreaseMonkey (&amp;gt;=0.8)：&lt;a href="https://addons.mozilla.org/en-US/firefox/addon/748" id="ctp4" rel="nofollow" title="https://addons.mozilla.org/en-US/firefox/addon/748"&gt;https://addons.mozilla.org/en-US/firefox/addon/748&lt;/a&gt; &lt;br /&gt;&lt;/li&gt;
&lt;li&gt;Google Gears (&amp;gt;=0.4)：&lt;a href="http://gears.google.com/" id="r.w1" rel="nofollow" title="http://gears.google.com/"&gt;http://gears.google.com/&lt;/a&gt; &lt;br /&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;br /&gt;
&lt;h3&gt;




下载&lt;/h3&gt;
&lt;br /&gt;
大家可以从我的 GitHub Repo 中检出最新的脚本试用&lt;br /&gt;
&lt;pre class="commands"&gt;&lt;code&gt;git clone git://github.com/wuyuntao/douban-offline.git&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
或者从 UserScripts 网站上下载&lt;br /&gt;
&lt;a href="http://userscripts.org/scripts/show/34040"&gt;&lt;img alt="下载" class="no-border" src="http://luliban.com/images/download90.gif" style="border: medium none;" /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;h4&gt;2008-09-23 UPDATE 0.2:&lt;/h4&gt;
豆瓣离线脚本更新为 0.2，有下面这些改动：&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;可以手动切换上线／离线浏览&lt;/li&gt;
&lt;li&gt;可以更新缓存页&lt;/li&gt;
&lt;li&gt;新增两个分类，日记和相册&lt;/li&gt;
&lt;li&gt;选中分类有高亮&lt;br /&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;br /&gt;&lt;br /&gt;
&lt;h4&gt;2008-10-15 下载链接更新：&lt;/h4&gt;
祸不单行。&lt;a rel="nofollow" href="http://github.com/"&gt;github&lt;/a&gt; 前几天数据库出了问题，到现在还没有恢复；
&lt;a href="http://userscripts.org/"&gt;userscripts.org&lt;/a&gt; 貌似被 GFW 给封了；今天 GAE 提供的四个 IP 中的又一个阵亡了。。。不管怎样，上面两个下载的链接都不管用了，现在提供一个本地的下载链接。&lt;br /&gt;
&lt;a href="http://github.com/wuyuntao/douban-offline/raw/master/douban_offline.user.js"&gt;&lt;img alt="下载" class="no-border" src="http://blog.luliban.com/images/download90.gif" style="border: medium none;" /&gt;&lt;/a&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;h4&gt;2008-10-22 UPDATE 0.4:&lt;/h4&gt;
豆瓣离线脚本更新为 0.4，有下面这些改动：&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;增加了翻页的功能&lt;/li&gt;
&lt;li&gt;增加了评论和豆邮两个标签 &lt;/li&gt;
&lt;li&gt;增加了一条 &lt;a href="http://www.douban.com/note/17803282/"&gt;Douban Helper&lt;/a&gt; 的控制台命令:write（wyt：Douban Helper 请&lt;a href="http://userscripts.org/scripts/review/32686/"&gt;安装最新版本&lt;/a&gt;）&lt;/li&gt;
&lt;li&gt;改正了相册日记等页面离线按钮位置不正确的bug&lt;/li&gt;
&lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7286295415331143255-4431373542880290926?l=py.thonic.org'/&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/gMJhQT0srM1cerJ0-SsXtw6zFNk/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/gMJhQT0srM1cerJ0-SsXtw6zFNk/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/gMJhQT0srM1cerJ0-SsXtw6zFNk/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/gMJhQT0srM1cerJ0-SsXtw6zFNk/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;</content><link rel="replies" type="application/atom+xml" href="http://py.thonic.org/feeds/4431373542880290926/comments/default" title="帖子评论" /><link rel="replies" type="text/html" href="http://py.thonic.org/2008/09/douban-offline-greasemonkey-google.html#comment-form" title="22 条评论" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7286295415331143255/posts/default/4431373542880290926?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7286295415331143255/posts/default/4431373542880290926?v=2" /><link rel="alternate" type="text/html" href="http://py.thonic.org/2008/09/douban-offline-greasemonkey-google.html" title="有备无患：豆瓣离线 - 利用 Google Gears 实现离线浏览豆瓣的 GreaseMonkey 脚本" /><author><name>wyt</name><uri>http://www.blogger.com/profile/04947921907676762514</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="13162551058647906166" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/_sKun2mxXeAk/SNSuTFxQpXI/AAAAAAAAAs0/FL7UYli7t_U/s72-Rc/screen_shot_1.png" height="72" width="72" /><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">22</thr:total></entry><entry gd:etag="W/&quot;CkMMQX4-cCp7ImA9WxVRGUk.&quot;"><id>tag:blogger.com,1999:blog-7286295415331143255.post-4767419233984363090</id><published>2008-09-14T17:56:00.006+08:00</published><updated>2009-01-26T11:28:00.058+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-01-26T11:28:00.058+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="javascript" /><category scheme="http://www.blogger.com/atom/ns#" term="blogger" /><category scheme="http://www.blogger.com/atom/ns#" term="豆瓣" /><title>有备无患：Google Reader 风的豆瓣广播 widget 更新</title><content type="html">今天为 &lt;a href="http://blog.luliban.com/2008/08/google-reader-style-douban-miniblog.html"&gt;Google Reader 风的豆瓣广播 widget&lt;/a&gt; 新增了三个选项：手动设置宽度 width，隐藏标题 hidetitle 和隐藏主页链接 hidefooter。谢谢 &lt;a href="http://cow.hkbloggers.org/"&gt;cow&lt;/a&gt; 和 &lt;a href="http://asiapan.cn/"&gt;asiapan&lt;/a&gt; 的&lt;a href="http://blog.luliban.com/2008/08/google-reader-style-douban-miniblog.html#comments"&gt;建议&lt;/a&gt;先。&lt;br /&gt;
&lt;br /&gt;
使用方法和&lt;a href="http://blog.luliban.com/2008/08/google-reader-style-douban-miniblog.html"&gt;以前的说明&lt;/a&gt;一样，只需要将下面这段代码插入到你的 blog 模板中，并替换其中的参数。
&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="codes"&gt;&lt;code&gt;&amp;lt;script type="text/javascript" src="http://blog.luliban.com/scripts/miniblog.js?username=wyt&amp;amp;amp;maxresults=16&amp;amp;amp;style=blue"&amp;gt;&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
&lt;h4&gt;
参数列表如下&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;username: 用户名，或者用户 id。（必填）&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;maxresults: 输出广播条目的数量。最大值为50，默认为10。&lt;/li&gt;
&lt;li&gt;style: widget 的配色样式，默认为绿色。其他样式包括 black（黑）、blue（蓝）、gray（灰）、green（绿）、khaki（卡其色）、pink（粉红）、slate（蓝灰） 和 none（无）。其中，none 为不带任何样式的原始 HTML，适合希望自定义广播风格的 bloggers。&lt;/li&gt;
&lt;li&gt;width: 手动设定 widget 的宽度，输入应为宽度的像素值，如 width=300&lt;/code&gt;。默认为自适应宽度（推荐）。&lt;/li&gt;
&lt;li&gt;hidetitle: 如果设 hidetitle=true，将隐藏顶部标题。默认为 false。&lt;/li&gt;
&lt;li&gt;hidefooter: 如果设 hidefooter=true，将隐藏底部豆瓣主页的链接。默认为 false。&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
隐藏标题和主页的效果如下&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: left;"&gt;
&lt;a href="http://3.bp.blogspot.com/_sKun2mxXeAk/SMzo7rziAaI/AAAAAAAAAsU/1kU68xOEFGw/s1600-h/douban-miniblog-widget-screenshot.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img src="http://lh5.ggpht.com/wuyuntao.1122/SMzo7rziAaI/AAAAAAAAAsU/_yINjkTIxiI/s800/douban-miniblog-widget-screenshot.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7286295415331143255-4767419233984363090?l=py.thonic.org'/&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/wjLfsWrenC-kxbyuaAxG0jZa0Go/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/wjLfsWrenC-kxbyuaAxG0jZa0Go/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/wjLfsWrenC-kxbyuaAxG0jZa0Go/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/wjLfsWrenC-kxbyuaAxG0jZa0Go/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;</content><link rel="replies" type="application/atom+xml" href="http://py.thonic.org/feeds/4767419233984363090/comments/default" title="帖子评论" /><link rel="replies" type="text/html" href="http://py.thonic.org/2008/09/widget.html#comment-form" title="5 条评论" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7286295415331143255/posts/default/4767419233984363090?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7286295415331143255/posts/default/4767419233984363090?v=2" /><link rel="alternate" type="text/html" href="http://py.thonic.org/2008/09/widget.html" title="有备无患：Google Reader 风的豆瓣广播 widget 更新" /><author><name>wyt</name><uri>http://www.blogger.com/profile/04947921907676762514</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="13162551058647906166" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://lh5.ggpht.com/wuyuntao.1122/SMzo7rziAaI/AAAAAAAAAsU/_yINjkTIxiI/s72-c/douban-miniblog-widget-screenshot.png" height="72" width="72" /><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">5</thr:total></entry><entry gd:etag="W/&quot;C0MHSXs_fyp7ImA9WxRSEk8.&quot;"><id>tag:blogger.com,1999:blog-7286295415331143255.post-6449994074601658356</id><published>2008-09-12T19:26:00.005+08:00</published><updated>2008-09-12T20:10:38.547+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-09-12T20:10:38.547+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="gentoo" /><category scheme="http://www.blogger.com/atom/ns#" term="linux" /><category scheme="http://www.blogger.com/atom/ns#" term="git" /><title>有备无患：升级到 Git 1.6.01 之后无法启动 git-daemon 的解决办法</title><content type="html">&lt;a rel="nofollow" href="http://git.or.cz/"&gt;git&lt;/a&gt; 升级到 1.6 之后，发现 git-daemon 不能启动，自然也不能作 clone 或 push 之类的操作。原因是原来的 /usr/bin/git-daemon 搬到了 /usr/libexec/git-core 目录，但是 Gentoo 的启动脚本没有随之更新。不过有人已经提交了&lt;a rel="nofollow" href="https://bugs.gentoo.org/236685"&gt;这个 bug&lt;/a&gt;。&lt;br /&gt;
&lt;br /&gt;
自己也可动手，将启动脚本 /etc/init.d/git-daemon 中的 start 函数修改如下。&lt;br /&gt;
&lt;pre class="codes"&gt;&lt;code&gt;start() {
    ebegin "Starting git-daemon"
        start-stop-daemon --start --quiet --background \
        --exec /usr/libexec/git-core/git-daemon -- ${GITDAEMON_OPTS}
    eend $?
}&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
另外，我用来架设 Git 版本库的 &lt;a rel="nofollow" href="http://scie.nti.st/2007/11/14/hosting-git-repositories-the-easy-and-secure-way"&gt;gitosis&lt;/a&gt; 也和 git 1.6 有一点兼容问题，原因是 /usr/bin/git-shell 也搬到了 /usr/libexec/git-core 目录。好在&lt;a rel="nofollow" href="http://eagain.net/gitweb/?p=gitosis.git;a=commitdiff;h=73a032520493f6b4186185d4826d12edb5614135;hp=7e407d1013e2610401792302325c04c40c57a376"&gt;已经有 patch 推出&lt;/a&gt;，只需要修改 /usr/lib/python2.5/site-packages/gitosis/serve.py，将其中调用 &lt;b&gt;git-shell&lt;/b&gt; 的指令，替换成调用 &lt;b&gt;git shell&lt;/b&gt; 即可。&lt;br /&gt;

&lt;pre class="codes"&gt;&lt;code&gt;--- a/gitosis/serve.py
+++ b/gitosis/serve.py
@@ -201,6 +201,6 @@ class Main(app.App):
             sys.exit(1)
         main_log.debug('Serving %s', newcmd)
-        os.execvp('git-shell', ['git-shell', '-c', newcmd])
+        os.execvp('git', ['git', 'shell', '-c', newcmd])
         main_log.error('Cannot execute git-shell.')
         sys.exit(1)
&lt;/code&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7286295415331143255-6449994074601658356?l=py.thonic.org'/&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/Wo4y7wBVdGgGUxvc49yaHQ8lfm8/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/Wo4y7wBVdGgGUxvc49yaHQ8lfm8/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/Wo4y7wBVdGgGUxvc49yaHQ8lfm8/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/Wo4y7wBVdGgGUxvc49yaHQ8lfm8/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;</content><link rel="replies" type="application/atom+xml" href="http://py.thonic.org/feeds/6449994074601658356/comments/default" title="帖子评论" /><link rel="replies" type="text/html" href="http://py.thonic.org/2008/09/git-1601-git-daemon.html#comment-form" title="0 条评论" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7286295415331143255/posts/default/6449994074601658356?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7286295415331143255/posts/default/6449994074601658356?v=2" /><link rel="alternate" type="text/html" href="http://py.thonic.org/2008/09/git-1601-git-daemon.html" title="有备无患：升级到 Git 1.6.01 之后无法启动 git-daemon 的解决办法" /><author><name>wyt</name><uri>http://www.blogger.com/profile/04947921907676762514</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="13162551058647906166" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></entry><entry gd:etag="W/&quot;D0YNSX45eCp7ImA9WxVSFE4.&quot;"><id>tag:blogger.com,1999:blog-7286295415331143255.post-6061637471322325927</id><published>2008-09-10T12:23:00.009+08:00</published><updated>2009-01-09T01:19:58.020+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-01-09T01:19:58.020+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="nba" /><category scheme="http://www.blogger.com/atom/ns#" term="火箭" /><title>南言北哲：Battier or Artest，谁将首发？</title><content type="html">&lt;b&gt;1，Battier or Artest，谁将首发？&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;b id="phx-" style="color: #cc0000;"&gt;Artest。&lt;/b&gt;联盟最好的人盯人防守者之一，上赛季场均20.5分的进攻水准，以及38%的三分球命中率。加上曾在主教练 Rick Adelman 手底下打过一年球，对火箭现在这套动态进攻的体系了然在胸。如果在训练营和季前赛中一切顺利，他极有可能会取代 Shane Battier 成为火箭的正印前锋。&lt;br /&gt;
&lt;br /&gt;
有同学认为，Artest 应妨 Luis Scola 之例，先从替补打起，走循序渐进的路线。可是你要知道，Scola 虽然在 FIBA 摸爬滚打了多年，但是他也需要时间来适应 NBA，另一方面主教练也需要时间来了解他的技术特点，所以 Scola 必须从替补打起。Artest 却是已经在联盟混迹了整九年，别说 Adelman，就是联盟其余的29位主教练也同样对他知根知底。&lt;br /&gt;
&lt;br /&gt;
另外，虽然 Artest 曾经表过态，说愿意从替补打起。可是，以史为鉴，Artest 不是甘居替补之人——05年他炮轰 Jermaine O'Neal 出手权多和进攻效率低，被交易到 Sacramento 之后，又与 Mike Bibby 争当“国王”。（wyt: 最终都以阿泰“抢班夺权”失败而告终。）&lt;br /&gt;
&lt;br /&gt;
&lt;b id="ts0x0"&gt;2，如果 Battier 做替补，能不能胜任第六人的角色？&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;b id="nzmp" style="color: #cc0000;"&gt;&lt;span id="nzmp0"&gt;像 Battier 这样的防守型球员也一样可以胜任第六人，这&lt;/span&gt;&lt;/b&gt;&lt;b id="tt-6" style="color: #cc0000;"&gt;&lt;span id="tt-60"&gt;甚至&lt;/span&gt;&lt;/b&gt;&lt;b id="tt-61"&gt;&lt;span id="tt-62" style="color: red;"&gt;&lt;span style="color: #cc0000;"&gt;还有可能成为一股潮流。&lt;/span&gt;&lt;br id="fu3w" /&gt;
&lt;br id="fu3w0" /&gt;
&lt;/span&gt;&lt;/b&gt;联盟的大多数第六人都是长于进攻的球员，比如被交易回国王的 Bobby Jackson，湖人签下肥约的 Sasha Vujacic，小牛老将 Jerry Stackhouse，还有掘金的 J.R. Smith 等，他们的主要作用是在主力下场的时候带领其他替补球员，提供持续的进攻力，并为主力争取更多的休息时间。（wyt：我不喜欢把 Manu Ginobili 和 Jason Terry 归类到第六人。如果非要说，我更愿意称他们为“伪第六人”，或者，“联盟第六人奖项欺诈师”）&lt;br /&gt;
&lt;br /&gt;
但是对于拥有所谓的“三巨头”的球队，这个角色常常是由“三巨头”的其中之一所担任，比如凯尔特人的 Ray Allen 和马刺的 Manu Ginobili。因而这些球队对第六人在进攻端的要求也有所不同。以 Boston 为例，上赛季第六人就是场均只有7.4分进帐的防守悍将 James Posey。总决赛中出色的表现，也让黄蜂弃用原来的第六人 Jannero Pargo，花重金将 Posey 挖来作为下赛季他们的第六人。另外，湖人下赛季也有可能让 Odom 出任第六人。&lt;br /&gt;
&lt;br /&gt;
Battier 之于火箭，就像 Posey 之于 Boston 和 New Olean。而且 Battier 有更出色的协防能力和不错的背身技巧，可以想见新赛季的第四节，我们经常会看到 Battier 和 Artest 一起打完最后一分钟。&lt;br /&gt;
&lt;br /&gt;
&lt;b id="ts0x1"&gt;3，&lt;/b&gt;&lt;b id="ts0x2"&gt;如果 &lt;/b&gt;&lt;b id="ts0x3"&gt;Artest 做先发，出手次数会不会不够？&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;b id="uwyg" style="color: #cc0000;"&gt;&lt;span id="uwyg0"&gt;这很可能是杞人忧天。&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
上赛季，有三支球队的核心球员被称作“三巨头”，分别是凯尔特人的 Garnett、Pierce 和 Allen，马刺的 Duncan、Parker 和 Ginobili，以及湖人的 Kobe、Odom 和 Gasol。我们首先来看看他们的&lt;a href="http://spreadsheets.google.com/pub?key=p0fkEiAjyzAtC67rSFQT_dg&amp;amp;gid=0" id="w-n9" target="_blank" title="出手分配情况"&gt;出手分配情况&lt;/a&gt;，并和火箭作一下对比。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
表格中的 FGA 为出手次数 (Field Goal Attempts)，FTA 为罚球次数 (Free Throw Attempts)，TP 为球队节奏 (Team Pace)，TSA 为每100次球权的真实出手次数 (True Shooting Attempts)，所使用的统计公式为 TSA = (FGA + 0.44 * FTA) / TP * 100。要说明的，湖人的数据是“打劫” Gasol 以后的全明星之后的数据，而其他球队是整个赛季的数据。&lt;br /&gt;
&lt;br /&gt;
&lt;div&gt;
&lt;a href="http://picasaweb.google.com/lh/photo/vPndGBboJXN_75727-oDig?authkey=QNJyVUfN53A&amp;feat=embedwebsite"&gt;&lt;img src="http://lh6.ggpht.com/_sKun2mxXeAk/SMdMeZ595GI/AAAAAAAAAl0/kbWCtgVuHs0/s400/big-three-true-shooting-attempts-stats.png" /&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;a href="http://picasaweb.google.com/lh/photo/D1-2dhPk15Y1dpY_pE1HPQ?authkey=QNJyVUfN53A&amp;feat=embedwebsite"&gt;&lt;img src="http://lh3.ggpht.com/_sKun2mxXeAk/SMdM_Mw_7nI/AAAAAAAAAl8/SEcWw_MO3zo/s400/big-three-true-shooting-attempts-chart.png" /&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;br /&gt;
从图表中，我们可以看出光是姚明，T-Mac 和 Battier 三个人的出手次数，就已经和其他几个三巨头基本持平。所以即使 Artest 取代 Battier 成为先发，只要姚明和 T-Mac 愿意牺牲自己的球权，火箭的出手次数对于 Artest 来说是绰绰有余的。&lt;br /&gt;
&lt;br /&gt;
另外，由于伤病的关系，姚明和 T-Mac 都有相当长一段时间单独带队，所以也有同学质疑，这段时间他们的出手数是不是突增的，会不会影响到最后的统计结果。我也捎带统计了一下他们同时带队的10月、11月和2月份，姚明的出手数是20.0次，而 T-Mac
的是 24.4次。相比整个赛季并没有太大的变化，这主要是因为无论是姚明还是
T-Mac 带队，他们都是以火箭这个团队来进攻，谁也没有像 Kobe 在 Bynum 和 Gasol
缺席的时候那样贸然增加自己的出手。&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7286295415331143255-6061637471322325927?l=py.thonic.org'/&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/pmyWE09X4nYR5qham47AUfNI6zg/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/pmyWE09X4nYR5qham47AUfNI6zg/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/pmyWE09X4nYR5qham47AUfNI6zg/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/pmyWE09X4nYR5qham47AUfNI6zg/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;</content><link rel="replies" type="application/atom+xml" href="http://py.thonic.org/feeds/6061637471322325927/comments/default" title="帖子评论" /><link rel="replies" type="text/html" href="http://py.thonic.org/2008/09/battier-or-artest.html#comment-form" title="2 条评论" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7286295415331143255/posts/default/6061637471322325927?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7286295415331143255/posts/default/6061637471322325927?v=2" /><link rel="alternate" type="text/html" href="http://py.thonic.org/2008/09/battier-or-artest.html" title="南言北哲：Battier or Artest，谁将首发？" /><author><name>wyt</name><uri>http://www.blogger.com/profile/04947921907676762514</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="13162551058647906166" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://lh6.ggpht.com/_sKun2mxXeAk/SMdMeZ595GI/AAAAAAAAAl0/kbWCtgVuHs0/s72-c/big-three-true-shooting-attempts-stats.png" height="72" width="72" /><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">2</thr:total></entry><entry gd:etag="W/&quot;CEIGSHw7cCp7ImA9WxRTFUQ.&quot;"><id>tag:blogger.com,1999:blog-7286295415331143255.post-6086381502703793504</id><published>2008-09-05T11:35:00.002+08:00</published><updated>2008-09-05T13:28:49.208+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-09-05T13:28:49.208+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="python" /><title>有备无患：用 Gaupol 生成文本字幕</title><content type="html">&lt;a href="http://home.gna.org/gaupol/"&gt;Gaupol&lt;/a&gt; 是一个用 Python 编写的文本字幕文件的编辑工具，支持包括.ssa、.ass、.srt和.sub在内的多种字幕文件格式，并提供文本校正的方法以及时间处理。其用户界面基于 pyGTK，注重对多文档和翻译的批量处理。最新版本为 &lt;a rel="nofollow" href="http://download.gna.org/gaupol/0.13/gaupol-0.13.news"&gt;0.13&lt;/a&gt;。&lt;br /&gt;

&lt;br /&gt;

下面的命令示范了利用 Gaupol 生成一个 SubRip 格式的字幕文件，以作备忘。&lt;br /&gt;

&lt;br /&gt;

&lt;pre class="commands"&gt;&lt;code&gt;$ python
&amp;gt;&amp;gt;&amp;gt; from gaupol.files.subrip import SubRip
&amp;gt;&amp;gt;&amp;gt; from gaupol import NEWLINE
&amp;gt;&amp;gt;&amp;gt; srt = SubRip('/home/wyt/demo.srt', encoding='utf-8', newline=NEWLINE.UNIX)
&amp;gt;&amp;gt;&amp;gt; srt.write(starts=[u'00:00:5.000', u'00:00:15.000', u'00:00:25.000'], \
              ends=[u'00:00:10.000', u'00:00:20.000', u'00:00:30.000'], \
              texts=[u'字幕测试一', u'字幕测试二', u'字幕测试三'])
&lt;/code&gt;&lt;/pre&gt;

&lt;br /&gt;
生成的 .srt 字幕文件如下&lt;br /&gt;
&lt;br /&gt;

&lt;pre class="codes"&gt;&lt;code&gt;1
00:00:5,000 --&amp;gt; 00:00:10,000
字幕测试一

2
00:00:15,000 --&amp;gt; 00:00:20,000
字幕测试二

3
00:00:25,000 --&amp;gt; 00:00:30,000
字幕测试三
&lt;/code&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7286295415331143255-6086381502703793504?l=py.thonic.org'/&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/e_quoKj7taokBpvX1eo7SAZFgWg/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/e_quoKj7taokBpvX1eo7SAZFgWg/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/e_quoKj7taokBpvX1eo7SAZFgWg/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/e_quoKj7taokBpvX1eo7SAZFgWg/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;</content><link rel="replies" type="application/atom+xml" href="http://py.thonic.org/feeds/6086381502703793504/comments/default" title="帖子评论" /><link rel="replies" type="text/html" href="http://py.thonic.org/2008/09/gaupol.html#comment-form" title="0 条评论" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7286295415331143255/posts/default/6086381502703793504?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7286295415331143255/posts/default/6086381502703793504?v=2" /><link rel="alternate" type="text/html" href="http://py.thonic.org/2008/09/gaupol.html" title="有备无患：用 Gaupol 生成文本字幕" /><author><name>wyt</name><uri>http://www.blogger.com/profile/04947921907676762514</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="13162551058647906166" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></entry></feed>
