存档

2009年7月 的存档

豆瓣好友统计图标

2009年7月28日 Solrex Yang 3 条评论

自从 Feedburner 订阅数统计图标成为博客装逼工具之后,各种各样的统计图标层出不穷,比如我也使用的 Twitter Counter。但是我一直没发现我认为很有装逼范儿的豆瓣提供好友数统计图标,因此我就使用豆瓣的 API 自己搞了一个。其实我主要是觉得在博客侧栏放豆瓣图书列表太多了,而一个小“豆”字也没啥意思,搞个好友数图标就挺好玩了。

我想没准你也会感兴趣,所以我把这个服务发布了出来。豆瓣好友统计图标的主页在:

http://solrex.org/douyou/

下面是直接从主页拷贝过来的内容,您也可以到我的博客侧栏看看效果。

介绍

呃——我觉得写主页比写主程序还费劲。简单来说,这个东西就跟 Feedburner 的订阅数统计图标类似,利用豆瓣提供的 API 抓取你的豆瓣好友数量,并做成一个小图片出来让你可以放在自己的博客上秀一秀。比如下面就是我的豆瓣好友统计图标:

豆瓣

你还可以移步到我的博客右侧栏,看看豆瓣好友统计图标和其它统计图标共存的状况。本统计图标一天更新一次,因此统计数并不完全实时,这是为了减轻服务器负载,请理解。

这个小项目完全是出于兴趣写成的,因此很简陋且维持在可用的水平上,我也没有更优化它的想法。在我服务器能承受的情况下我会尽量维持它,但本人不对服务的有效性和可用性做出任何承诺。

我觉得这个服务本身应该由豆瓣提供,如果你是豆瓣的工作人员,觉得这个站点有趣并想在豆瓣中加入此服务的话,欢迎你和我联系,我将无偿提供所有的代码,仅仅希望在对应产品中加上一个 Thanks to 到我的链接。

生成图片

输入豆瓣 UID:
(豆瓣用户 UID,英文或数字,非登录 email 地址)

(若没有即刻显示请稍等后多提交一次,服务器抓取信息可能有延迟。不知道自己的 UID 的话,可以登录豆瓣,查看自己的设置->username项。)

豆瓣

您可以把下面这段代码嵌入到您的博客或者主页中来显示豆瓣好友统计:

<a href="http://www.douban.com/people/solrex" title="豆瓣好友统计"><img src="http://solrex.org/douyou/dc/solrex" style="border: 0pt none ;" alt="豆瓣" height="26" width="88"></a>

分类: IT, Programming 标签: , , , ,

用 Wireshark 分析 RTP 流

2009年7月27日 Solrex Yang 14 条评论

Wireshark 是一个强大的抓包及网络分析软件,可以用来嗅探和分析多种网络协议的数据包和流,RTP 和 RTCP 也是其中的两种。

对 RTP 流的分析过程,在 Wireshark 的 Wiki 上讲得很清楚,下面我只是记录一下我在使用过程中的一些经验:

1. 要想分析 RTP 流,首先要把抓到的 UDP 包用 RTP 协议而不是默认的 UDP 协议 decode; Wireshark 默认只对选中的流(由端口区分)进行 decode,所以对 audio 和 video 流要分别 decode。

2. 直接从菜单中选择 RTP 的 Stream Analysis... 才是对双向的流进行分析,从 Show All Streams 中再分析只是单向的 RTP 流。

3. 不要过度相信 Wireshark 的能力,尤其是在无线网络或者网卡驱动不是很合适的情况下,Wireshark 也会有丢包,所以说 Wireshark 对 RTP 流的分析也是“仅供参考”——除非经过严格测试 Wireshark 不会错过任何包。

4. 这个页面上提到的 Sun 的 JMF JMstudio 的 Linux 版本状况很糟糕。首先其安装文件中使用的 tail 参数和 bash 中的 tail 参数不一样,导致执行安装文件不仅不会安装,反而会清除安装文件的内容。由于其将安装脚本和二进制文件写入到同一个文件中,所以最好是在外部手工用 tail 提取二进制文件的内容;其次无论如何配置,该程序运行时会去监听 IPv6 地址的端口而不是 v4 的端口——我一直想不通是什么原因,所以该程序可以说是基本不可用。

5. rtptools 是个好东西。我们可以先用 Wireshark 录制一段 RTP 流,保存成 rtpdump 格式,就可以用 rtpplay 不断地重放它,用来测试网络状况很方便。原本应该用 JMStudio 收听的,既然它不可用,只有用 rtpdump 在另一端收听了。

回复选登:

james:

博主请问有没有办法能够使wireshark能够在ubuntu下捕捉到所有的rtp包?

由于要做老板的项目,所以需要测量一系列delay,jitter等等数据。所以我用vlc做server向外multicast一个rtp stream (拓扑上用的全部是有线)。若传输的stream质量不高(比如dvdrip,大概速度也就1.5mbps),wireshark能够完全捕获所有的包。但是若是使用较高质量的stream(比如1080p,1080i的,大概在20mbps)就会出现wireshark丢包的情况。

所以我想知道wireshark丢包的原因是不是来自于cpu利用率太高?有没有办法在仍然使用wireshark的情况下捕捉到所有的包?如果有其他抓包、分析软件,博主可否给我推荐一下?

非常感谢!

Solrex Yang:

@james
非常抱歉,我所了解的知识无法解决您遇到的问题。如果您找到了解决方法,非常欢迎您回来再次留下您的评论。

james:

博主你好,这个问题已经解决了。

由于wireshark实时捕捉packet会非常消耗cpu资源,所以我使用tcpdump来抓包,并且加大了libpcap的缓冲区,问题就解决了。

当然,若是要在Gbps的网络环境中抓包,linux下的tcpdump的精度完全不够(尤其在包长度小的时候很明显),这个就是跟libpcap函数相关的。有个意大利大牛写了一个PF_RING的类似“zero copy”的应用,可以在很大程度上解决这个问题,如果大家有兴趣可以尝试。google上有相关介绍。

分类: IT 标签: , , ,

JPerf Single Jar with UDP BW Unit Fixed

2009年7月22日 Solrex Yang 没有评论

JPerf is the GUI frond-end of IPerf, a TCP and UDP bandwidth performance measurement tool which allows the tuning of various parameters and UDP characteristics.

The official JPerf release (2.0.2 version) has some flaws. First, it mistakenly uses bytes/sec as the unit of UDP bandwidth, which should be bits/sec according to IPerf man-page:

-b, --bandwidth #[KM]
       for  UDP,  bandwidth  to  send  at  in  bits/sec (default 1 Mbit/sec,
       implies -u)

Second, starting it from command line is error prone. The command to start it (jperf.sh) is:

java -classpath jperf.jar:lib/forms-1.1.0.jar:lib/jcommon-1.0.10.jar:lib/jfreechart-1.0.6.jar:lib/swingx-0.9.6.jar net.nlanr.jperf.JPerf

We can see that all jar paths in classpath are relative paths. So if we create a symbol link to the jperf.sh script, e.g. /usr/bin/jperf -> /opt/jperf-2.0.2/jperf.sh. Then calling /usr/bin/jperf will result in some errors like:

Exception in thread "main" java.lang.NoClassDefFoundError: net/nlanr/jperf/JPerf
Caused by: java.lang.ClassNotFoundException: net.nlanr.jperf.JPerf
at java.net.URLClassLoader$1.run(URLClassLoader.java:200)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:188)
at java.lang.ClassLoader.loadClass(ClassLoader.java:307)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
at java.lang.ClassLoader.loadClass(ClassLoader.java:252)
at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:320)
Could not find the main class: net.nlanr.jperf.JPerf. Program will exit.

This error can be fixed by resolving the real path of the symbol link, as I reported.

However, a better way to solve this problem is to pack all libs JPerf needed(i.e. forms*.jar, jcommon*.jar, jfreechart*.jar, swingx*.jar) to a single jar, and add a proper "Manifest". Then we will be able to start JPerf with a much simpler command:

java -jar jperf.jar

And finally, I gave a try to solve the above 2 flaws and put my work (deb/jar/src packets) on my site. You can find them here .

qRFCview Proxy Patch

2009年7月14日 Solrex Yang 7 条评论

This patch enables qRFCview to load proxy settings from environment variables such as "http_proxy" and "socks_proxy". Yes, popping up a dialog to set these things is fancier, but that means more coding work. I am pretty satisfied with this solution.

You can download the modified source code tarball from http://share.solrex.org/ibuild/qrfcview-0.62-solrex2.tar.gz . Binary packets for special Linux distributions can be found at http://share.solrex.org/ibuild/ too.

diff -aurN qrfcview-0.62/src/mainwindow.cpp qrfcview-0.62-solrex/src/mainwindow.cpp
--- qrfcview-0.62/src/mainwindow.cpp    2006-01-13 17:56:45.000000000 +0800
+++ qrfcview-0.62-solrex/src/mainwindow.cpp    2009-07-14 16:03:56.000000000 +0800
@@ -122,8 +122,10 @@
{
   // Load a RFC number
   bool bOK;
+  /* NOTE 20090714/Solrex  <http://solrex.org>:
+     Enlarge RFC number limit to 10000. */
   int iRFCNum = QInputDialog::getInteger(this, tr("Please enter a RFC number"),
-                                             tr("RFC#:"), 0, 1, 5000, 1, &bOK);
+                                             tr("RFC#:"), 0, 1, 10000, 1, &bOK);
   if (bOK)
     RFCLoad( iRFCNum );
}
diff -aurN qrfcview-0.62/src/rfcloader.cpp qrfcview-0.62-solrex/src/rfcloader.cpp
--- qrfcview-0.62/src/rfcloader.cpp    2006-01-13 17:56:45.000000000 +0800
+++ qrfcview-0.62-solrex/src/rfcloader.cpp    2009-07-14 15:58:50.000000000 +0800
@@ -25,11 +25,41 @@
#include <QMessageBox>
#include <QtDebug>
#include <QDir>
+#include <QNetworkProxy>

QRFCLoader::QRFCLoader(QObject *parent)
  : QObject(parent)
{
   m_qHttp=new QHttp(this);
+  /* NOTE 20090714/Solrex <http://solrex.org>:
+     Detect proxy settings via system environment variable
+     ``http_proxy'' and ``socks_proxy''. */
+  char *p;
+  QNetworkProxy qNetworkProxy(QNetworkProxy::NoProxy);
+  if ((p = getenv("socks_proxy")) != NULL) {
+    qNetworkProxy.setType(QNetworkProxy::Socks5Proxy);
+  } else if ((p = getenv("http_proxy")) != NULL) {
+    qNetworkProxy.setType(QNetworkProxy::HttpProxy);
+  }
+  if (p != NULL) {
+    QString proxyStr = p;
+    proxyStr = proxyStr.trimmed();
+    proxyStr.remove("http://");
+    QStringList list = proxyStr.split("@");
+    QStringList list1 = list[0].split(":");
+    if (list.count() > 2) {
+      qNetworkProxy.setType(QNetworkProxy::NoProxy);
+      qDebug() << "Unresolvable proxy setting:" << list;
+    } else if ( list.count() == 2) {
+      qNetworkProxy.setUser(list1[0]);
+      qNetworkProxy.setPassword(list1[1]);
+      list1 = list[1].split(":");
+    }
+    qNetworkProxy.setHostName(list1[0]);
+    qNetworkProxy.setPort(list1[1].toInt());
+  }
+  m_qHttp->setProxy(qNetworkProxy);
+  qDebug() << "Loaded proxy:" << p;
   connect(m_qHttp, SIGNAL( requestStarted(int) ), this, SLOT( startDownload(int) ) );
   connect(m_qHttp, SIGNAL( requestFinished(int, bool) ), this, SLOT( fileDownload(int, bool) ) );
   connect(m_qHttp, SIGNAL( responseHeaderReceived(QHttpResponseHeader) ), this, SLOT( receivedHeader(QHttpResponseHeader) ) );

RFC number limit issue was discussed at deb-packages-of-qrfcview-and-jabref.html .

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

浏览器自动选择 Proxy 配置案例

2009年7月13日 Solrex Yang 9 条评论

本文主要讨论的是浏览器代理服务器设置技术,文中出现的人名、公司名或者域名均为化名,如有雷同,纯属巧合。

在某些地方上网时,比如南京大学的校园网中,某些公司的局域网中,我们可能需要用到代理服务器。代理服务器的切换一直是一个让人头痛的话题,IE 浏览器有一个 ProxySwither Lite 软件可以用来切换代理,Firefox 有一批插件可以用来切换代理,但是,很难用它们来解决全局性的问题,使用前的配置也是比较麻烦的事情。那么,有没有一种方法可以一劳永逸地解决这个问题呢?答案是有的,那就是 PAC(Proxy Auto-Config) 文件。

使用 PAC 文件我们可以做到:1. IE、Firefox、Opera...浏览器使用同一个代理配置方案,Windows、Linux多系统使用同一个代理配置方案;2. 针对特定的域名,使用特定的代理;3. 针对特定的 IP 范围,使用特定的代理;4. 针对特定的 URL 模式,使用特定的代理。

下面我们来看一个案例:

假设小明的电脑位于 C 公司的局域网中,C 公司为了某些需要禁止员工访问某些站点,例如: alogspot.com 和 bwitter.com ,但是小明的工作和学习需要经常访问这些站点,公司的网管给小明带来了很大不便。不过小明很聪明,他找到了一个可以访问被禁那些站点的一个代理 127.0.0.1:8000。虽然通过该代理小明可以访问这些站点,但是切换代理和浏览器设置始终是麻烦;特别是在用 doogle.com 搜索到的某些文章位于 alogspot.com 时,一不小心点了搜索结果,到搜索引擎 doogle.com 的连接就会有很大一会儿被重置。因为小明的代理速度比较慢,总不能用代理上所有网站吧?这真是件麻烦事,小明该怎么办呢?

虽然很头痛,但是互联网的开拓者们给我们留下了那么多遗产,怎么能不好好利用呢?小明翻出了一个尘封已久的 Wiki 页面,缓缓回忆起那古老的 Javascript 语言,顿时有了主意,于是他写出了下面这个 PAC 脚本:

// 看看域名是不是本地站点
function isLocalHost(host)
{
  if( dnsDomainIs(host, "localhost") )
    return true;
  return false;
}
// 看看域名是不是禁止访问的站点
function isBlockedHost(host)
{
  if( dnsDomainIs(host, "alogspot.com") ||
      dnsDomainIs(host, "bwitter.com") )
    return true;
  return false;
}
// 看看搜索结果 URL 中是不是包含被禁止访问的关键字
function isBlockedURL(url, host)
{
  if( dnsDomainIs(host, "doogle.com") ) {
    if ( shExpMatch(url, "*alogspot.com*") ||
         shExpMatch(url, "*bwitter.com*") )
      return true;
  }
  return false;
}
// 看看 IP 在不在本地 IP 范围内
function isLocalIP(addr)
{
  if( isInNet(addr,"127.0.0.0","255.0.0.0") ||
      isInNet(addr,"10.0.0.0","255.0.0.0") ||
      isInNet(addr,"192.168.0.0","255.255.0.0") ||
      isInNet(addr,"172.16.0.0","255.255.0.0") )
    return true;
  return false;
}
// 看看 IP 在不在被禁止访问的 IP 范围内
function isBlockedIP(addr)
{
  return false;
}
// 看看 IP 地址是不是 IPv6 地址
function isIPV6(addr)
{
  if( shExpMatch(addr, "*:*") )
    return true;
  return false;
}
// 这是浏览器默认调用的函数接口
function FindProxyForURL(url, host)
{
  var direct      = "DIRECT";
  var httpProxy   = "PROXY localhost:8000";
  var socksProxy  = "SOCKS localhost:9050"// 留着做个参考
 
  if(isLocalHost(host)) {
    // 如果是本地域名,那就直连
    return direct;
  } else if(isBlockedURL(url, host) || isBlockedHost(host)) {
    // 如果是被禁止访问的域名,或者搜索结果 URL 中含有被禁止访问的关键词,那就走代理
    return httpProxy;
  }

  if(!isResolvable(host)) {
    // 如果域名不能解析,那就直连
    return direct;
  }
  // 解析域名到 IP 地址
  var IpAddr = dnsResolve(host);

  if(isLocalIP(IpAddr) || isIPV6(IpAddr)) {
    // 如果是本地 IP 或者 IPv6 地址,那就直连
    return direct;
  } else if(isBlockedIP(IpAddr)) {
    // 如果是被禁止访问的地址,那就走代理
    return httpProxy;
  } else {
    // 剩下的,唉,就直连吧
    return direct;
  }
}

小明将以上内容保存为 C:proxy.pac(~/proxy.pac),然后到

Firefox 中,选择 工具->选项->高级->网络->设置(Edit->Preferences->Advanced->Network->Settings),将 file:///c:/proxy.pac(file:///home/username/proxy.pac)填入“自动代理配置 URL”(Automatic proxy configuration URL)文本框中;

再到

IE 中,选择 工具->Internet 选项->连接->局域网设置,勾选使用自动配置脚本,填入 file://c:/proxy.pac;

再到

Opera 中,选择 Tools->Preferences->Advanced->Network->Proxy Servers,勾选上 Use automatic proxy configuration,填入 file://c:/proxy.pac。

从此,小明就开始了自己幸福的互联网冲浪生活,再也没有看到那曾经熟悉的“到该网站的连接已被重置”消息了。

PS:若要 Firefox 和 Chrome 支持远端 DNS 解析,需使用 SOCKS5 作为代理的前缀。

解决 GAppProxy Set-Cookie 和 HTTPS Cert Bugs

2009年7月9日 Solrex Yang 15 条评论

我自己写了一个类似 GAppProxy 的工具,支持 Python 和 PHP,有兴趣可以看这里

研究 GAppProxy 有两个原因:一、最近 Twitter 不能用,而我常用的 GAppProxy 却不支持我登录 Twitter;二、我最近在琢磨 SSL 证书的问题,正好用 GAppProxy 登录 Twitter 也有证书错误。

第一个 BUG:Set-Cookie Bug

GAPPProxy 目前对 Cookie 的处理有一些问题,主要出在对 header 中的多个 Set-Cookie 域处理错误,就会导致用户登录一些网站错误,无法获得正确的会话 Cookie。

举例,当服务器返回的 header 中有多个 Set-Cookie 域时,比如一般的 wordpress 返回的 header 中,Set-Cookie 域至少有三个:

Set-Cookie:
wordpress_776c41a2fee8d137928f3750eb1f0736=admin%7C1247298611%7C8b89cfc80161853957182ddfc481cd72;
path=/wp-content/plugins; httponly
Set-Cookie:
wordpress_776c41a2fee8d137928f3750eb1f0736=admin%7C1247298611%7C8b89cfc80161853957182ddfc481cd72;
path=/wp-admin; httponly
Set-Cookie:
wordpress_logged_in_776c41a2fee8d137928f3750eb1f0736=admin%7C1247298611%7C545dcea44d5e69aec5c1203c64bee061;
path=/; httponly

GAPPProxy 会把它作为一个串传给本地浏览器:

Set-Cookie:
wordpress_776c41a2fee8d137928f3750eb1f0736=admin%7C1247298611%7C8b89cfc80161853957182ddfc481cd72;
path=/wp-content/plugins; httponly,
wordpress_776c41a2fee8d137928f3750eb1f0736=admin%7C1247298611%7C8b89cfc80161853957182ddfc481cd72;
path=/wp-admin; httponly,
wordpress_logged_in_776c41a2fee8d137928f3750eb1f0736=admin%7C1247298611%7C545dcea44d5e69aec5c1203c64bee061;
path=/; httponly

这样本地浏览器对 Cookie 的设置就会错误。解决办法很简单,将这个长串用split(', ')切开,同样设置三个 Set-Cookie 域即可。

Update 20090710/Solrex:
有人评论说 ', ' 也是可能在 Cookie 中出现的合法字符串;那么我就另外想了一个办法,先用正则表达式替换将 ', ***=' 替换成 'n***=',再用 'n' 对字符串进行切割。由于在 Cookie 中正常出现的 ', ' 后面会首先跟着 ';' 或 ',',然后才可能出现 =,因此用 ‘, ([^,;]+=)’ 匹配就可以了。而且这次把修改放到服务器端了,原来的客户端就不需要修改了

Patch:

Index: fetchserver/fetch.py
===================================================================
--- fetchserver/fetch.py    (revision 92)
+++ fetchserver/fetch.py    (working copy)
@@ -29,6 +29,7 @@
from google.appengine.ext import webapp
from google.appengine.api import urlfetch
from google.appengine.api import urlfetch_errors
+import re
# from accesslog import logAccess

@@ -153,14 +154,12 @@
             if header.strip().lower() in self.HtohHdrs:
                 # don't forward
                 continue
-            ## there may have some problems on multi-cookie process in urlfetch.
-            #if header.lower() == 'set-cookie':
-            #    logging.info('O %s: %s' % (header, resp.headers[header]))
-            #    scs = resp.headers[header].split(',')
-            #    for sc in scs:
-            #        logging.info('N %s: %s' % (header, sc.strip()))
-            #        self.response.out.write('%s: %srn' % (header, sc.strip()))
-            #    continue
+            # NOTE 20090710/Solrex: Fix multi-cookie process problem
+            if header.lower() == 'set-cookie':
+                scs = re.sub(r', ([^,;]+=)', r'n1', resp.headers[header]).split('n')
+                for sc in scs:
+                    self.response.out.write('%s: %srn' % (header, sc.strip()))
+                continue
             # other
             self.response.out.write('%s: %srn' % (header, resp.headers[header]))
             # check Content-Type

第二个 BUG:HTTPS Cert Bug

简单地来说,GAppProxy HTTPS 连接的实现是一个欺骗本地浏览器的过程,类似于中间人攻击。它首先用 GAE 获得页面的明文,抓到本地,然后假冒 HTTPS 站点与本地浏览器通信。因此它就需要提供一个 SSL 证书,来完成 HTTPS 连接的建立。

但这就有一个问题,SSL 证书哪儿来的?目前 GAppProxy 对所有的站点都使用一个证书,而且这个证书是未经任何授权 CA 认证的证书,因此就会产生很多错误。首先,该证书中的授权机构不是可信 CA,Firefox 和 IE 中捆绑的证书中没有该 CA 的证书;其次,该证书的 CN (Common Name)与站点域名不同,不可用于站点的通信。因此可能每次都需要用户自己点击添加证书例外。

为了避免这种缺陷,我想出来的做法是——自己做 CA,正所谓做事情要专业,要骗就骗彻底点,骗得浏览器神不知鬼不觉。首先,建立 CA 的密钥,自己给自己签发一个证书作为 CA 的根证书,将该 CA 的证书安装到 Firefox 浏览器中,在运行时使用该 CA 为每个 HTTPS 连接的站点签发对应于该站点的证书。由于 Firefox 中已经安装了该 CA 的证书,那么所有该 CA 签发的证书都能够通过 Firefox 的检测了。

这个方法比较麻烦,而且需要电脑上有 openssl,对于 Linux 完全没有问题,对于 Windows 可能就有点儿困难了。所以我这里就给出个思路,具体实现就不谈了。
您可以在 http://share.solrex.org/ibuild/ 找到我修改后的代码,感兴趣的话可以下载下来看看。

在 Ubuntu 9.04 上安装 Kscope

2009年7月8日 Solrex Yang 5 条评论

Kscope 是我很喜欢的 Linux 平台上的代码查看工具,因为我不会用 Emacs,vim + ctags 又用得不熟,看看小程序还可以,看大项目就傻眼了。以前也尝试过 Source-Navigator(这个项目N年没更新,06年时候我装都装不上,08年底居然又复活了,有空了再去试试)、Eclipse、Kdevelop、CodeBlocks,总之都没有 Kscope 用着最舒服。Kscope 让我欣赏的特点主要有:

1. 它号称是代码编辑环境(source-editing environment),而不是IDE。我不用在建立 Kscope 项目时烦心地去选择项目类型、编译器、编译选项等等。编译我有 Makefile,我就是找个工具看看代码,用得着那么麻烦吗。 建立 Kscope 项目时只需要干两件事:选择项目名、项目保存地址和添加源文件。

2. 它不会在源文件目录下建立一堆乱七八糟的文件,影响市容。我记得 Eclipse、CodeBlocks 等都会把项目信息保存在源文件目录下,而 Kscope 的项目保存位置可以自己选,比如我一般都保存在 workspace/kscope 目录下面,这样对要查看的源文件目录没有任何影响。因此 Kscope 的项目和源文件基本没关系,我可以添加任何位置的源文件到某个项目中去。

3. 它不会去读非指定类型的文件。这是针对 Eclipse 来说的,每次在 Eclipse 项目中搜索时,一堆 .svn 目录中文件的结果让我感觉非常闹心,两年没用不知道现在的 Eclipse 是不是更智能点儿了,但是 Eclipse 改不了的毛病就是慢和吃内存。

4. 它支持代码查看的基本功能。其实我最常用的也就那么几个功能:语法高亮、同时打开多文件、整个项目中搜索字符串、查找函数定义位置和引用、项目文件列表+搜索。在这些条上据说 Windows 下的 SourceInsight 做得更好,但我没用过没有发言权。

简而言之,Kscope 与其它工具比就是快、简单、省心。但是时代在变革呀,转眼到了 KDE4 的时代,而 Kscope 仍然停留在 KDE3.5 上。现在的 Ubuntu 9.04 的依赖关系里,居然已经撤掉了 Kscope,在 9.04 上 sudo apt-get install kscope,会得到这样的消息:E: Couldn't find package kscope,真是让人丧气。

其实 Kscope 之所以不能安装,主要原因是它依赖于 Kate 的两个库:libkateinterfaces.so.0 和 libkateinterfaces.so.0,只需要从 KDE3.5 的 Kate 中提取出来这两个库安装到系统中后,Kscope 就可以正常运行了。Ubuntu 9.04 的依赖关系中虽然找不到 Kscope,但是 Ubuntu 的软件仓库中还有 Kscope 的包,我们可以手动下载安装。下面这个脚本的功能就是自动安装 kscope 到 Ubuntu 9.04,稍微修改一下也可以用于在其它 KDE4 桌面系统中安装 Kscope,或者解决 Kscope 无法运行的问题。您也可以从这里下载到该脚本:

#!/bin/bash
# This script helps you install Kscope on Ubuntu 9.04.
# You can also use it to fix "Kscope doesn't run in KDE4" bug.

echo "Determining machine hardware name... "
MACHINE=`uname -m`
case "$MACHINE" in
  i386 | i586 | i686)
    ARCH="i386"
    ;;
  x86_64)
    ARCH="amd64"
    ;;
  *)
    ARCH="i386"
    ;;
esac

# If Kscope is not installed, install it.
which kscope &> /dev/null
if [ $? -ne 0 ]; then
  echo "Installing kscope..."
  sudo apt-get install kscope || \
  wget http://archive.ubuntu.com/ubuntu/pool/universe/k/kscope/kscope_1.6.0-1_${ARCH}.deb && \
  sudo dpkg -i kscope_*.deb || \
  sudo apt-get -fy install || \
  echo "Oops, some error happens..."
fi

kscope -v &> /dev/null
if [ $? -eq 0 ]; then
  echo "Kscope works fine."
  exit
fi

echo "Downloading KDE3 libraries needed by kscope..."
wget http://ftp.debian.org/debian/pool/main/k/kdebase/kate_3.5.9.dfsg.1-6_${ARCH}.deb
dpkg -x kate_3*.deb kate

echo "Installing KDE3 libraries..."
sudo cp kate/usr/lib/libkateinterfaces.so.0.0.0 /usr/local/lib/
sudo cp kate/usr/lib/libkateutils.so.0.0.0 /usr/local/lib
sudo ln -s /usr/local/lib/libkateinterfaces.so.0.0.0 /usr/local/lib/libkateinterfaces.so.0
sudo ln -s /usr/local/lib/libkateutils.so.0.0.0 /usr/local/lib/libkateutils.so.0
sudo ldconfig

echo "Finished."

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

车祸及好心大叔

2009年7月3日 Solrex Yang 7 条评论

今天我在保福寺桥北发生一场小型车祸,一个逆行的中年妇女将我的前轮撞成了弯的,这是我第一次体验轮子被撞弯的感觉。由于着急赶校车,而且想着两人撞车没有倒没有伤已经很幸运了,所以也没有纠缠谁的责任,道歉两句各自走开。

总之有不幸有幸运吧,碰见一个骑车路过的特别好心的大叔,帮我在路边石上把车圈揉了揉,勉强能推走。我是不是该感叹一下北京人民的热心肠呢?当看到一个小伙子对着被撞弯的自行车发愁时,能停下车来帮忙,我认为是件很了不起的事情。

后来过四环路时,在红灯后又碰上这位大叔,他看我着急赶路,还一把抓过我的车把,要边推车边载我走。我费了好大劲向他解释说我就到前面天桥,他才没有再坚持载我。这位大叔是我出门在外遇到的陌生人中最最好心的一个!!!

我当时也带着手机,真后悔没有把这位大叔拍下来,好歹也留个纪念。在这样一个邻居、同事都形同陌路的社会里,碰到这么一个古道热肠的大叔,对我有着莫大的震动。也许我以前把这个社会想得太坏了。