存档

‘Open Source’ 分类的存档

An IPv6 Enabled NTP Client for Windows in Python

2010年3月7日 Solrex Yang 1 条评论

Python NTP library (ntplib) offers a simple interface to query NTP servers from Python. But it does not support IPv6 NTP servers. I wrote a patch for ntplib to support IPv6 connections. You can download the patch file here and the patched library here.

The code bellow is a simple IPv6 enabled NTP client (ntpdate.py) in Python for Windows, using the patched ntplib. It doesn't (and won't) support Linux because the official NTP release offers IPv6 support on that platform.

#!/usr/bin/env python
# ntpdate.py - set the date and time via NTP
# An IPv6 enabled ntp client, for Windows ONLY.

import ntplib, time
from os import system
from sys import argv

def usage():
  print '''Usage: ntpdate.py  [-qh] server
Example:
  ntpdate.py 210.72.145.44      # IPv4
  ntpdate.py ntp6.remco.org     # IPv6
Options:

  -q     Query only - don't set the clock.
  -h     Print this message.

IPv6 NTP Server List:
  ntp6.remco.org
  ntp6.space.net
  time.buptnet.edu.cn
  time.join.uni-muenster.de
  time6.ipv6.uni-muenster.de
  ntp.sixxs.net
  ntp.eu.sixxs.net
  ntp.us.sixxs.net
  ntp.ap.sixxs.net
  ntp.rhrk.uni-kl.de
  ntp.ipv6.uni-leipzig.de

Report bugs to http://solrex.org.'''
  sys.exit()

def main():
  ntp_svr = ''
  query = False

  for a in argv[1:]:
    if a == '-q':
      query = True
    elif a == '-h':
      usage()
    else:
      ntp_svr = a
  if ntp_svr == '':
    usage()

  c = ntplib.NTPClient()
  res = c.request(ntp_svr, version=3)
  t_epoch = res.offset + res.delay + time.time()
  t = time.localtime(t_epoch)
  centi_sec = t_epoch%1 * 100
  time_str = time.strftime('%H:%M:%S', t)
  if not query:
    system('time %s.%2.0f' % (time_str, centi_sec))
    date_str = time.strftime('%Y-%m-%d', t)
    system('date %s' % date_str)
  if query:
    print 'server %s, stratum %d, offset %f, delay %f' % (
           ntp_svr, res.stratum, res.offset, res.delay)
  print '%s %s ntpdate.py: time server %s offset %f sec' % (
         time.strftime('%d %b', t), time_str, ntp_svr, res.offset)

if __name__ == '__main__':
  main()

分类: Open Source 标签: , , , , ,

一个 Windows 对时小工具

2010年3月6日 Solrex Yang 3 条评论

由于在 CERNET 内,我经常需要用代理上网,没办法直连到 NTP 服务器,因此不能使用 Windows 时间服务对时。偶尔维修电脑或者不小心调整错时间,再加上电脑时钟本身就有一定的漂移,对时就变成了件麻烦的事情。

手动调时也没个参照,误差往往比较大。IPv6 网络上存在一些 NTP 服务器,Linux 下有 ntpdate 是支持 IPv6 NTP 服务器的,但是我搜索了半天,才在一篇文章上看到有人评论说 Windows 下只有一款 NTP 客户端支持 IPv6,还是收费软件——可他也没给出名字。

无奈之下想到 Python 的 httplib 是支持 IPv6 连接的,于是我就仿照 htpdate 写了一个利用 Google 的 IPv6 Web 服务器进行对时的 Python 小工具 htpdate.py。虽然误差比 NTP 大不少,但是还是在可接受范围内(不到 1 秒),而且比较方便,连日期也一块更新了。下面是代码,比较粗糙。

#!/usr/bin/env python
import httplib, time
from os import system

def main():
  conn = httplib.HTTPConnection('google.com')
  time.clock()
  conn.request('HEAD', '')
  t_rtt = time.clock()
  res_time = conn.getresponse().getheader('date')
  t = time.localtime(time.mktime(time.strptime(res_time,
                                 '%a, %d %b %Y %H:%M:%S %Z')) - time.timezone)
  time_str = time.strftime('%H:%M:%S', t)
  local_time = time.asctime()
  t_exe = time.clock()
  centi_sec = (t_exe - t_rtt/2)*100
  if centi_sec > 99:
    centi_sec = 99
  system('time %s.%2.0f' % (time_str, centi_sec))
  date_str = time.strftime('%Y-%m-%d', t)
  system('date %s' % date_str)
  print 'LOCAL  TIME: ' + local_time
  print 'SERVER TIME: ' + time.asctime(t)
  print 'LOCAL  TIME: ' + time.asctime()
  if (t_exe - t_rtt/2) >= 1:
    print 'Round trip time is too long. Time error might be larger than 1 sec.'

if __name__ == '__main__':
  main()

分类: Open Source 标签: , , , , ,

RSS Feed 迁移方法

2010年1月9日 Solrex Yang 2 条评论

由于政策的调整,目前很多博主都将博客域名从 .cn 迁出,相信很多朋友都会遇到 RSS Feed 迁移的问题。如果一直使用 Feedburner/Feedsky 这种第三方烧录网站管理订阅,只需要更换第三方抓取的源即可;但是如果之前订户多用 Wordpress 原始的源 example.cn/feed/、example.cn/?feed=rss2,或者使用自定的域名 feed.example.cn 的话,当域名迁移时,原来的 example.cn 被弃用后,订户就无法得到文章更新了。

我之前一直使用 feed.solrex.cn 作为 Feedsky 的自定义域名,因为我觉得 solrex.cn 可能比 feedsky.com 更长久,后来发现这是非常愚蠢的想法。当我把域名迁移到 .org 时,就面临 feed 迁移的问题。

最简单的方法是将原来的 feed url 重定向到 Feedburner/Feedsky,但这要求网站主必须仍然控制原来域名,那就没有更换域名的必要了。

或者使用一篇博客来通知订户更换 feed url,但是实践证明这种方法收效甚微。很多人(包括我)不会去看自己使用的是什么源,认为自己使用的就是正确的 feed url。

起初我是使用的直接重定向,但后来一封域名注册商的邮件,威胁如果不办理某些手续,24日之后会停止我的 .cn 域名解析。我想,还是用一些略显卑劣的手段通知大家更换订阅源吧。这种卑劣的方法是:如果使用原来的源订阅本站,就会看到每天一篇的“网站迁移通知”,直到用户更改订阅源,或者无法忍受直接删除 feed。

其技术实现方法是:使用 php 模仿 WP 的 rss 源生成一个 xml 文件,该文件只包含一篇文章,将原来的源指向它(或者 url 重定向到它)。该 xml 中的更新日期、文章 url 每天更新一次,这样阅读器就会认为博客有更新,把这篇文章抓取回去。我本以为阅读器是根据更新日期判断文章是否重复,后来发现是根据文章 url 来判断。为减少工作量,我们可以将文章的 url 指向某篇目标文章,然后在 url 后面加上 “?date=***”,这样阅读器就不会认为是同一篇文章,而且读者仍然能够点入目标文章。

方法很简单,如果您比较懒的话,可以参考我使用的文件(也可以从这里直接下载 php 源代码):

<?php echo '<?xml version="1.0" encoding="UTF-8"?>'."\n"; ?>
<?php echo '<?xml-stylesheet type="text/xsl" media="screen" href="http://feeds.feedburner.com/~d/styles/rss2chinesetwfull.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?>'; ?><rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:creativeCommons="http://backend.userland.com/creativeCommonsRssModule" version="2.0">

<channel>
    <title>Solrex Shuffling</title>
   
    <link>http://blog.solrex.org</link>
    <description>Engineering a better life, programming a great future.</description>
    <pubDate><?php echo date('D, d M Y ', strtotime("+7 hour")); echo '00:00:00 GMT'; ?></pubDate>
    <generator>http://wordpress.org/?v=2.7.1</generator>

    <language>en</language>
    <sy:updatePeriod>hourly</sy:updatePeriod>
    <sy:updateFrequency>1</sy:updateFrequency>
        <item>
        <title>站点迁移通知-<?php echo date('d M Y', strtotime("+7 hour")); ?></title>
        <link>http://blog.solrex.org/?p=638679&amp;q=<?php echo date('Ymd', strtotime("+7 hour")); ?></link>
        <comments>http://blog.solrex.org/?p=638679&amp;q=<?php echo date('Ymd', strtotime("+7 hour")); ?>#comments</comments>
        <pubDate><?php echo date('D, d M Y ', strtotime("+7 hour")); echo '00:00:00 GMT'; ?></pubDate>
        <dc:creator>Solrex Yang</dc:creator>
       
        <guid isPermaLink="false">http://blog.solrex.org/?p=638679&amp;q=<?php echo date('Ymd', strtotime("+7 hour")); ?></guid>
        <description><![CDATA[您好,您之所以看到这篇文章是因为您仍在使用被遗弃的 feed 地址 http://feed.solrex.cn 订阅我的博客Solrex Shuffling。我已经将网站从 http://blog.solrex.cn 迁移到了 http://blog.solrex.org。由于 .cn 域名潜在被删除的危险,为了不丢失和您交流的渠道,我不得不出此下策以每天一篇博客的方式提醒您更新 feed 地址,希望您能谅解!...
]]></description>
            <content:encoded><![CDATA[<p>您好,您之所以看到这篇文章是因为您仍在使用被遗弃的 feed 地址 http://feed.solrex.cn 订阅我的博客<a href="http://blog.solrex.org">Solrex Shuffling</a>。我已经将网站从 <a href="http://blog.solrex.org">http://blog.solrex.cn</a> 迁移到了 <a href="http://blog.solrex.org">http://blog.solrex.org</a>。由于 .cn 域名潜在被删除的危险,为了不丢失和您交流的渠道,我不得不出此下策以每天一篇博客的方式提醒您更新 feed 地址,希望您能谅解!</p>
<p>如果您觉得<a href="http://blog.solrex.org">本站</a>对您还有点儿用处,可以使用以下方式继续订阅:</p>
<ul>
<li><p>如果您使用离线阅读器,请将本站的 feed 地址 <a href="http://feeds.feedburner.com/solrex">http://feeds.feedburner.com/solrex</a> 或者 <a href="http://feed.feedsky.com/solrex">http://feed.feedsky.com/solrex</a> 添加到您的订阅器中,并删除现有这个 feed。</p></li>
<li><p>如果您使用在线阅读器,比如 Google Reader、抓虾 之类,您可以点击<a href="http://blog.solrex.org">这里</a>到本站首页,在右侧选择您的在线阅读器,重新订阅,并将现在这个 feed 删除。</p></li>
</ul>
<p>如果您觉得<a href="http://blog.solrex.org">本站</a>对您不再有用,可以使用以下方式退订:</p>
<ul>
<li><p>如果您使用离线阅读器,请咨询阅读器帮助如何删除 feed,一般情况下在 feed 上直接点 del 键即可。</p></li>
<li><p>Google Reader 用户可以在左侧 Subscriptions 中找到本 feed(一般名为 Solrex Shuffling),将鼠标移动至其上,您会发现右侧有一个向下的小箭头,点击箭头,您就会发现有 Unsubscribe 的选项;或者您也可以到右上角的 Setting 中,点入 Subscriptions 标签页,对所有 feed 进行管理时删除 Solrex Shuffling 这个 feed。您可以在<a href="http://www.google.com/support/reader/bin/answer.py?hl=zh_CN&answer=73062">这个页面</a>找到更多帮助。</p></li>
<li><p>抓虾用户可以在<a href="http://zhuaxia.com/help.php#3_3">这个页面</a>找到退订的帮助。</p></li>
<li><p>其它在线阅读器用户请咨询该网站帮助。</p></li>
</ul>
<p>无论如何,感谢您一直以来对本站的支持,我希望能在<a href="http://blog.solrex.org">新的站点</a>继续收到您的批评或支持!祝您好运!</p>
<p>Solrex Yang</p>
<p><?php echo date('D, d M Y ', strtotime("+7 hour")); ?></p>
]]></content:encoded>
            <wfw:commentRss>http://blog.solrex.org/?p=638679&amp;q=<?php echo date('Ymd', strtotime("+7 hour")); ?>/feed/ ?></wfw:commentRss>
        </item>
</channel>
</rss>

您可以到 feed.solrex.cn 查看效果。

分类: Open Source, Programming 标签: , ,

Fix Black Screen After Boot Problem of Ubuntu 9.10 on D630

2009年11月3日 Solrex Yang 6 条评论

Platform: Dell Latitude D630, Nvidia NVS 135M, Intel CPU, Ubuntu 9.10

Problem:

1. Boot from livecd, select install. After a glowing ubuntu Symbol, screen shows nothing, even no CLI.

2. After installation with "text mode", boot from HD. After a glowing ubuntu Symbol, screen shows nothing, even no CLI.

Solution:

I am not very sure whether this problem is caused by the NV 185 driver(nvidia-glx-185). Installing or removing this package gave no help. I googled a lot, found many people encountered the same problem. However, no answer could work on my laptop. Then I tried to install NV driver manually...it works! So, here is the fix:

1. When you get the GRUB boot menu screen, press 'e' to edit the fist entry. Add a word 'single' after 'linux /boot/vmlinuz..... quiet splash', then press 'Ctrl+x' to boot. (I cannot enable networking in recovery mode, so I tried with the single mode.)

2. Select the 'netroot' entry. You will get a root command line with network support.

3. Download the latest NV driver for linux (2010-11-3):

# wget http://us.download.nvidia.com/XFree86/Linux-x86/190.42/NVIDIA-Linux-x86-190.42-pkg1.run

[You can visit http://www.nvidia.com/object/unix.html for the latest NV driver.]

4. Install development tools to build NV driver on you os.

# apt-get update
# apt-get install build-essential

5. Install the NV driver:

# chmod u+x NVIDIA-Linux-x86-190.42-pkg1.run
# ./NVIDIA-Linux-x86-190.42-pkg1.run

6. Reboot.

If you are using a livecd, please use the "text mode" to install Ubuntu 9.10. After installation, try the solution above.

Ubuntu 9.10 启动后黑屏的解决方法

平台: Dell Latitude D630, Nvidia NVS 135M, Intel CPU, Ubuntu 9.10

问题描述:

1. 从 livecd 启动后,选择安装,在白色 Ubuntu 图标闪烁结束之后,无任何屏显,连命令行都没有。

2. 用文本模式安装完成后,从硬盘启动,在白色 Ubuntu 图标闪烁结束之后,无任何屏显,连命令行都没有。

解决方法:

我不太清楚是不是 NV 的 185 驱动有问题(nvidia-glx-185),安装或者删除它对状况没有任何帮助。我搜索了一下,发现很多人遇到和我类似的问题,不过没有任何解决方法可以在我的电脑上工作。无奈下我尝试手动安装了一下 NV 的最新驱动——居然解决了!下面是我的解决方法:

1. 当你进入 grub 启动菜单选择屏幕时,在第一条上按 e 进入编辑状态,在 'linux /boot/vmlinuz..... quiet splash' 这一行最后添加一个单词 single,然后按 Ctrl+x 启动。其实 recovery mode 能做类似的事,但是 9.10 的 recovery mode 好像不能启动网络,所以只好自己进入 single 模式了。

2. 启动后选择 'netroot' 选项,进入带网络的 root 命令行。

3. 下载最新的 NV 驱动(2010-11-3):

# wget http://us.download.nvidia.com/XFree86/Linux-x86/190.42/NVIDIA-Linux-x86-190.42-pkg1.run

[你可以先访问 http://www.nvidia.com/object/unix.html 查看 NV 最新驱动的地址。]

4. 安装编译 NV 驱动需要的编译工具:

# apt-get update
# apt-get install build-essential

5. 安装 NV 驱动:

# chmod u+x NVIDIA-Linux-x86-190.42-pkg1.run
# ./NVIDIA-Linux-x86-190.42-pkg1.run

6. 重启

如果您使用 livecd 安装 Ubuntu 9.10 的话,您应该选择 "text mode" 进行安装。成功安装完成后,仍然遇到黑屏问题,请尝试上述方法。

分类: Linux 标签: , , , ,

Cygwin GCC qsort 函数错误(续)

2009年10月16日 Solrex Yang 没有评论

上一篇文章中提到我在为 qsort 写 compare 函数时犯了一个愚蠢的错误:我脑袋陷入了一个错误的逻辑,以为 compare 函数嘛,就是要 compare 一下,那么我用 '>' 或者 '< ' 这种比较算符就可以满足要求(潜意识里认为 > 会返回 1 或者 -1,显然是错的,上篇文章的评论者 Stephen 开始也犯了同样的直觉错误,不过他马上就醒悟过来了)。我当时脑袋里也犹豫了一下要不要处理相等的情况,后来想快排算法中没有判断相等的情况,那么我没必要加上等号。

这个错误直接导致了快排算法失效。

但是为什么在 Linux 下的 gcc 可以输出正确的排序结果呢?我想了很久,最终还是把 glibc 的代码看了一下,才发现,原来当数组规模比较小时时(数组大小小于物理内存的四分之一),glibc 的 qsort 其实不使用 quick sort(_quicksort),而是使用 merge sort(msort_with_tmp)。而且在 msort_with_tmp 中,对 compare 的处理是比较其返回值是否 <=0,这样排序的结果就是正确的了。[1]

事实上最简单的快排算法是只使用 '<' 号或者 '<='的,比如 Wikipedia 上给出的快排算法,那么我们的 compare 只返回 -1 和 0 行吗?这取决于实现,比如对快排算法的优化中有一个就是对数组中有大量相等元素情况下的优化,其中一种实现 Three-way partition, 就需要使用到三种情况:大于、小于或等于。原始的快排 partition 是将数组按照与 pivot 的比较分为两段,Three-way partition 则是将数组分为三段,中间增加一段与 pivot 值相等的子数组。C 玩具代码的实现如下:

void qsort_3way(int a[], int lo, int hi)
{
  if (hi <= lo) return;
  int lt = lo, gt = hi, i = lt;
  int v = a[lo], t;
  while (i <= gt) {
    if (a[i] < v) {
      t = a[i]; a[i] = a[lt]; a[lt] = t;
      ++i; ++lt;
    } else if (a[i] > v) {
      t = a[i]; a[i] = a[gt]; a[gt] = t;
      --gt;  
    } else i++;
  }
  qsort_3way(a, lo, lt - 1);
  qsort_3way(a, gt + 1, hi);
}

但是 '<' 和 '>' 真的都需要吗?理论上来讲,'>' 是不需要的,我们显然可以将 a[i] > v 改成 v < a[i]。这也是 C++ 里面做的,C++ 中的 sort 函数只需要类重载 '< ' 运算符。但是 C 中并没有这种约定,我们不能预设 qsort 如何拿 compare() 的返回值与 0 比较。因此让 compare() 按照 C 的约定,返回大于、小于和等于 0 的三种情况是绝对正确的而且必要的。

我了解了正确的结果怎么得来的,但是我仍然不知道错误的结果是怎么得来的。看起来 Cygwin 使用的 libc 中没有采取类似 Linux 下 gcc 的策略(比如无法取到物理内存大小?)。quick sort 算法有很多优化的技巧和实现:有的使用 '< ' 符号比较,有的在分支数组足够小时采用插入排序,有的同时使用 '<', '> 两个符号,有的随机取 pivot,有的取三点中值作为 pivot。[2] 没有看到代码和调试,很难判断 Cygwin 的 libc 使用了什么算法(当然,尝试分析不同的输入输出是可以得到规律的,比密码分析还是要简单一些)。

[1] glibc/stdlib/msort.c.
[2] Jon Bentley and M. Douglas McIlroy, "Engineering a sort function", Software - Practice and Experience, Vol. 23 (11), 1249-1265, 1993.

Cygwin GCC qsort 函数错误

2009年10月13日 Solrex Yang 4 条评论

我平时在 Windows 下写代码时,经常使用 Cygwin 的 gcc。但是今天我居然发现 Cygwin 下 gcc 的 qsort 函数是错误的!这种基本的函数出错,太让人惊讶了。为了验证是不是代码有错,我使用 tcc 和 Linux 下的 gcc 都编译了同样一段程序,它们两个都输出了期望的结果,只有 Cygwin 的 gcc 是错的。下面是示例代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int compare(const void *p, const void *q)
{
  return *(const char *)p > *(const char *)q;
}

int main()
{
  char a[] = "1312515";
  printf("%sn", a);
  qsort(a, strlen(a), sizeof(char), compare);
  printf("%sn", a);
  return 0;
}

按说它应该输出:

1312515
1112355

但是我用 Cygwin gcc 编译后,它居然运行出这样的结果:

1312515
2111355

太诡异了。我尝试调试它,结果 gdb 无法步入 qsort 代码中。谁能告诉我是为什么?

附 Cygwin gcc 信息:

$ gcc -v
Using built-in specs.
Target: i686-pc-cygwin
Configured with: /gnu/gcc/package/gcc4-4.3.2-2/src/gcc-4.3.2/configure --srcdir=/gnu/gcc/package/gcc4-4.3.2-2/src/gcc-4.3.2 --prefix=/usr --exec-prefix=/usr --bindir=/usr/bin --sbindir=/usr/sbin --libexecdir=/usr/sbin --datadir=/usr/share --localstatedir=/var --sysconfdir=/etc --infodir=/usr/share/info --mandir=/usr/share/man --datadir=/usr/share --infodir=/usr/share/info --mandir=/usr/share/man -v --with-gmp=/usr --with-mpfr=/usr --enable-bootstrap --enable-version-specific-runtime-libs --with-slibdir=/usr/bin --libexecdir=/usr/lib --enable-static --enable-shared --enable-shared-libgcc --enable-__cxa_atexit --with-gnu-ld --with-gnu-as --with-dwarf2 --disable-sjlj-exceptions --enable-languages=ada,c,c++,fortran,java,objc,obj-c++ --disable-symvers --enable-libjava --program-suffix=-4 --enable-libgomp --enable-libssp --enable-libada --enable-threads=posix AS=/opt/gcc-tools/bin/as.exe AS_FOR_TARGET=/opt/gcc-tools/bin/as.exe LD=/opt/gcc-tools/bin/ld.exe LD_FOR_TARGET=/opt/gcc-tools/bin/ld.exe
Thread model: posix
gcc version 4.3.2 20080827 (beta) 2 (GCC)

我犯了一个愚蠢的错误,感谢来自 Stephen 的评论

你的compare函数有问题,你的compare函数不会返回负数。修改compare为:
int compare(const void *p, const void *q)
{
return *(const char *)p - *(const char *)q;
}
再编译运行就正确了。

Windows Tips: 修改热键和文件访问权限

2009年9月4日 Solrex Yang 3 条评论

我平时习惯使用 Win+E 打开 Windows 的资源管理器,但对资源管理器的左侧栏一直不感冒。用热键打开我的电脑本身就是为了键盘操作方便,但是多了个左侧栏使方向键选择文件夹相当不方便。昨天我总算找到了覆盖 Win+E 热键的方法。

AutoHotKey 是一个编辑和管理 Windows 热键的开源软件,SciTEAutoHotkey 是编辑 AutoHotKey 脚本的开源软件。(也许某些人会惊讶,AutoHotKey 居然不自带脚本编辑器,还要别人帮它写,我想这也许是受到 Unix 哲学的影响:Do one thing and do it well.)

AutoHotKey 脚本的基本语法是很简单的,前面是热键,后面是执行的命令,启动脚本后热键就会起作用了。键盘上每个特殊键对应的符号在热键列表中有列出,像我前面替换热键 Win+E 为打开“我的电脑”且无左侧栏的语句是:

#e::Run ::{20D04FE0-3AEA-1069-A2D8-08002B30309D}

::{20D04FE0-3AEA-1069-A2D8-08002B30309D} 是“我的电脑”的 CLSID(多谢 IronFeet 的提示),如果需要打开非特种文件夹,就不需要这么麻烦了,直接类似于 #e::Run C:WINDOWS 即可。同理,设置用 Win+C 打开控制面板可以写成:

#c::Run ::{20D04FE0-3AEA-1069-A2D8-08002B30309D}::{21EC2020-3AEA-1069-A2DD-08002B30309D}

利用 AutoHotKey 可以做很强大的事情。比如我在 Linux 下使用 Evince 查看 pdf,可以使用 vim 的习惯,jkhl 上下左右移动 pdf 文档,那么我们可以在 Windows 下用 AutoHotKey 来实现对 Adobe Reader 同样的操控,语句如下:

#IfWinActive ahk_class AcrobatSDIWindow
j::Send {Down}
k::Send {Up}
h::Send {Left}
l::Send {Right}
#IfWinActive

这几句话的意思是,如果 AcrobatSDIWindow 这个 ahk_class 窗口在激活状态下的话,那么 jkhl 就被换成键盘上的上下左右键。AutoHotKey 的高级使用还是很麻烦的,它网站上的 Tutorial 是一个不错的入门教程。其实一般我都是用 Launchy 启动程序,对 AutoHotKey 的需求不是那么多,简单的几个组合键就够了。

我昨天才发现 Windows XP 家庭版和专业版的一个大区别:家庭版没有“组策略”编辑器。我电脑的“所有程序”->"启动"目录不知道被什么安全软件设置成只读了,我以为 ATTRIB 命令是修改文件权限的,却发现无法修改“启动”文件夹的权限。后来找到 CACLS 命令,可以用来指定特定用户对文件的访问权限,才把"启动"文件夹访问权限修改成了完全控制:

cacls 启动 /G Solrex:F

设置可写以后就可以把 AutoHotKey 脚本的快捷方式拖到“启动”文件夹,随系统一起启动了。

SVN 技巧:GUI 版本比较和可执行属性

2009年8月28日 Solrex Yang 1 条评论

我曾经在《使用 kdiff3 进行 svn 版本比较》中介绍了为什么以及如何使用 kdiff3 或者 meld 等 GUI 比较工具进行 SVN 版本比较。但这样做有个小问题,就是如果设置了 GUI 工具作为比较工具,那么就没办法输出 diff 文件,而且每次都要关掉窗口才会出现下一个文件,就无法比较多个文件了。所以我觉得下面这种做法会更好一些:

$ more svndiff
#!/bin/bash
sed -i -e 's/^# diff-cmd.*$/diff-cmd=meld/' ~/.subversion/config
svn diff
sed -i -e 's/^diff-cmd.*$/# diff-cmd = meld/' ~/.subversion/config

其实就是用一个脚本 svndiff 来做 GUI 比较的工作。svndiff 执行时首先将 svn 配置文件中的比较工具改为 meld,然后进行比较,比较完后再将修改注释掉,这样就不会影响正常 svn diff 的功能。这样一来,svndiff 是 GUI diff,svn diff 就是命令行 diff。

设置文件可执行属性对 Windows 用户来说可能没什么用,可是对 Linux 用户来说用处就大了。没人希望每次一 update,就要重新对需要执行的脚本 chmod 一下。svn 修改文件可执行属性的命令太长了,我老记不住,所以放在这里做个笔记吧:

svn propset svn:executable ON filename

分类: Linux, Programming 标签: , , , ,

那些搅屎棍儿们

2009年8月13日 Solrex Yang 3 条评论

最近在社区或者列表里闲逛,总发现有一些有意思的人,他们根本不懂自己在讨论什么东西,却像行家一样置评,还纠缠不休,像搅屎棍似的,搞得让人抓狂。特摘录几个,以飨大家:

1. 我的朋友王聪的博客

... 谁知道这人怎么回复?第一条回复是问我是不是在说判断endian的技巧?扯淡!你自己的留言什么意思你自己不知道?!第二条回复中他似乎意识到自己前一个回复很白痴,于是补了一句Linux内核中没有。放屁!它有才怪呢!它凭什么要有?!貌似他们家的C语言技巧都是出自Linux内核!一个人能傻到这种地步真的挺不容易的!

别慌。他还能继续向我们证明他更傻呢!这个人在链接中给出了这么个地址,稍微有常识的人都看的出来,那是一个patch,那个patch的作者是Changli Gao,我review了这补丁,认为可以接受,然后Linus回复了,回复的意思也很简单,他不喜欢那个patch,他解释说如果用户程序能触发这个问题就说明你那程序是一坨shit。稍微有常识的人都明白这话什么意思:Linus只不过是借虚构的“你那程序”来说明这个问题不应该在内核中修复。而精彩的事情这时发生了!lovecreatesbeauty@gmail.c0m同学成功地把这话联想到了Linus所说的“你那程序”就是我写的程序!太伟大了!真不知道这人上小学时语文怎么学的?!估计他的语文老师看了都会气得跳楼自杀了!唉,语文没学好也就罢了,你找找整个邮件的存档,看看里面到底有没有shit程序啊。问题是他连找到没找就脑残式地下结论了。没找就没找吧,你仔细看看patch不行么?很不幸,他连patch是谁发的到看不出来!所以这个人不光脑残,眼也有问题,那么大大的一行Signed-off-by他看不到!!...more

2. Ubuntu 的 BUG tracker: Kubuntu 9.04 alpha6 panel corruption

#46 dotancohen wrote on 2009-06-14:

Are you trying to piss him off by any way that you can? You are not a developer, and you go around confirming and invalidating components, and playing ping pong confirmed/invalid with a dev. Then you make a remark like that?!? I personally am angry at you right now. I need this bug fixed, and you are going to piss off the developer so that he leaves us _both_ here to rot.

Go away. File a different bug, you have every right to as the dev implies that your issue is not the same as the OP (yes, that's me). Piss the devs off there. But let them do their work here and help those of us who appreciate it. ...more

简单地来说,就是开发者把该 BUG 标记为 Invalid,说该 BUG 应该是属于 Driver 的 BUG,有个用户不满意开发者对 BUG 的处理,就跟开发者对着干,开发者标记为 Invalid,他重新标记成 Confirmed,开发者开启一个新 BUG 报告,他去给人家改成 Invalid。一般来说修改 BUG 的状态应该是开发者来做,用户可以提交 BUG,assign 给某个开发者,但是不应该修改 BUG 状态,这是一种非常不礼貌的行为。一个用户一般情况下不可能比开发者对目标系统了解更多。

3. Wordpress 2.8.x(x<4) 的一个密码重设漏洞

From: laurent gaffie < laurent.gaffie_at_gmail.com >
Date: Tue, 11 Aug 2009 01:11:07 -0400

Mr Fabio,

You dont even understand the bug, so please shut the hell up.

2009/8/11 Fabio N Sarmento [ Gmail ] < fabior2_at_gmail.com >

> if this is an bug, please close Twitter.com, MSN.com and other services,
> because they have the same stupid "Reset password" service.
>
> So please make my day, and create a stupid script to flood with mutiple
> request to reset password. ...more

翻译过来就是,某个人发现了一个 Wordpress 2.8.x(x<4) 的密码重设漏洞,报告了出来。有个人评论说:“如果密码重设是 BUG 的话,那么所有网站都有 BUG 了,你没事干就写点儿傻逼程序去到处重设别人的密码吧。”然后报告漏洞的人就无奈了:“你根本没有理解这个 BUG,那么就请闭上你的臭嘴吧。”过了两天,Wordpress 就紧急发布了新版本 2.8.4,fix 了这个 BUG。

于是,我现在非常理解为什么 Linus 大神说话经常那么难听了,要是我成天跟这种人打交道,我也会抓狂。

有些人根本不了解和别人交流、在社区中交流应该遵循什么样的礼仪,应该使用什么样的方法。我遇到过的不礼貌行为包括(但不限于):不去搜索 BUG 列表和邮件列表,一遍又一遍地提出重复的问题;有 BUG 列表和邮件列表时,还直接与开发者联系,或者只 reply 开发者,不知道 reply all 到邮件列表;提交 patch 时,不知道如何使用 diff 和 patch 工具,而是直接提交整个文件;描述 BUG 时,不提供 BUG 出现的环境和步骤,就来一句“xx出问题了”。尽管有时候我都懒的搭理这些人,但是我不想被别人认为是一个没礼貌的人,所以我都尽量回复,但的确心中很不爽。

我希望那些想要在社区中和别人讨论、交流并想赢得别人尊重的朋友能够多了解点儿社区交往的礼仪,起码应该去了解点儿入门的知识,免得遭受挫折打击积极性,反倒以为别人非常不友好不礼貌。推荐的基本资料包括:

1. 如果您想在邮件列表或者社区中提问,那么请首先阅读 “How To Ask Questions The Smart Way ”,中文翻译《提问的智慧

2. 如果您想提交软件 bug, patch, feature request 并想得到开发者的尊重和重视,那么请首先阅读“The Art of Unix Programming” 第 19 章的“Best Practices for Working with Open-Source Developers”。

Tohr - HTTP 层上的洋葱路由器

2009年8月10日 Solrex Yang 38 条评论

Tohr (The Onion HTTP Router) 是我上个星期写的一个小的研究项目,它的名字起源于 Tor (The Onion Router)。简单地来说,它就是试图在 HTTP 层上实现类似于 Tor 实现的功能—— HTTP 层上的 HTTP(S) 隧道。

这个 idea 不是我想出来的,而是受到 GAppProxy 的启发(GAppProxy 是一个 great work)。但是 GAppProxy 只是利用 Google 的平台,而且受到 GAE 的很多限制。那么我的贡献呢,就是把这个 idea 通用化,设计一个协议使其支持多平台,解决了 GAppProxy 的一些 bug,完善了 HTTPS 的支持。(哦,忘记了,我还给它起了一个很 fancy 的名字 ^_^)目前 Tohr 的路由器可以是 Google App Engine 上的 Python 网站,也可以是普通的 Apache+PHP 站点。

Tohr 是怎么工作的?

Tohr 的工作原理

Tohr 的工作原理见上图。首先您得拥有一个墙外的主机(免费或者收费的)作为 Tohr 路由器,Tohr目前支持 Google App Engine 和 Apache+PHP 服务器,您将对应的 tohr-router 文件上传到服务器上;然后您在本地运行一个 tohr-daemon 守护程序,设置 tohr-daemon 连接 tohr-router 的 url,tohr-daemon 默认会开启 9090 来提供一个 HTTP(S) 代理服务,您只需要将浏览器的 HTTP 代理设置为 localhost:9090,您的访问请求就会通过 tohr-daemon 转发到 Tohr 路由器上,这样就能通过它来访问被防火墙禁止访问的网站了。

Tohr 是给什么人用的?

目前来讲 Tohr 仍然不很完善,而且还需要加入对其它类型的主机,比如 asp.net、jsp 的支持,还有对多跳和匿名的支持,还没有一个针对普通用户易用性的优化。要求普通用户都有一个墙外主机也是件比较为难的事情(虽然申请一个国外免费 PHP 空间并不困难,比如这里),因此 Tohr 目前还仅适合爱折腾的人使用,尤其是懂 Python 或 PHP 的爱折腾的人,所以在这里是找不到一个一步步的图文教程教普通用户怎么配置的。当然,如果哪位用户愿意做一个,请发送到邮件列表或者提交补丁,我很乐意将它放在项目文档里。

分类: Open Source 标签: , , ,