2012年1月22日星期日

emacs利用g-client发blog

首先介绍和感谢下emacspeak的作者T. V. Raman。Wikipedia中是这 么写的:
T. V. Raman is a computer scientist who is blind.His accessibility research interests are primarily auditory user interfaces and structured electronic documents. He has worked on speech interaction and markup technologies in the context of the World Wide Web at Digital's Cambridge Research Lab (CRL), Adobe Systems and IBM Research.[2] He currently works at Google Research.
这样的牛人,着实让人敬仰。

要在emacs中向托管在blogger的博客发blog,emacswiki上介绍了好几种方案,比较流行的方 法是使用weblogger,我试验了一下,并不管用。最后我选择使用 g-client + emacs-w3m 的 方案。g-client是emacspeak中的一个组 件,利用Google DATA API 来访问google的服务,emacs-w3m是w3m的emacs前端。当然,还需 要emacs。

得到这个方案并不是轻松的。原因是网上仅有的一些关于g-client的介绍也都 已经过时,还起了误导作用;为了贪图方便,g-client 和 emacs-w3m 都是在其主页下载的 压缩包,但其实打包的版本过于陈旧,这也增加了我按图索骥的困难。最后摸索出来的教训 是:

  • g-client
    下载emacspeak的最新版,编译后,从/lisp/g-client提取到emacs load-path。
  • emacs-w3m
    emacs-w3m的主页上的稳定版居然是2005年 的,我还以为这项目没有更新了而已。这个版本中甚至g-client所需要的一些函数。应该下载cvs版

配置文件如下:

;;=========== emacs-w3m ====================
(require 'w3m)
;;=========== emacs-w3m END ================

;; =============== g-client =================
(add-to-list 'load-path "~/.emacs.d/g-client/")
(load-library "g")
(setq g-user-email "yournamee@gmail.com")
;;设置访问时的代理, 后面的参数是默认的
(setq g-curl-common-options "--proxy 127.0.0.1:8087 --compressed --silent --location --location-trusted")
;;使用emacs-w3m访问
(setq browse-url-browser-function 'w3m-browse-url)
;; ================ g-client END ========================

2012年1月18日星期三

euler 3: Largest prime factor

题出自 Project Euler Problem 3:
The prime factors of 13195 are 5, 7, 13 and 29.
What is the largest prime factor of the number 600851475143 ?

我自己的解法思路是先判断该数(记为A)是否为prime,如果是,则直接返回它本身。否则从该数的一半开始(记为index),判断index是否能被A整数以及index是否是prime,当两者同时满足时,返回index,否则index自减1。 判断某数是否为prime的算法,是从该数的平方根数开始一个一个检查。代码如下:

#include <stdio.h>
#include <math.h>

//#include <limits.h>

int is_prime(long l);
long largest_prime_factor(long l);

int main(int argc, char *argv[])
{
  long result = largest_prime_factor(600851475143L);
  printf("%ld\n",result);
  return 0;
}

int is_prime(long l){
  long l_sqrt = (long)sqrt(l);
  long i = 2L;
  for(; i <= l_sqrt; i++){
    if(l % i == 0)
      return 0;                 /* is not prime */
  }

  /* is prime */
  return 1;
}


long largest_prime_factor(long l){
  if(is_prime(l))
    return l;
 
  long l_mid = l/2;
  long l_ind;
  for(l_ind = l_mid; l_ind >=2; l_ind--){
    if((l%l_ind == 0) && is_prime(l_ind))
      return l_ind;
  }

  return 1; // never come here
}



上面的算法很惨,算了几十分钟都没有算出结果。所以最后我放弃了,google到了下面这个算法:

#include <stdio.h>

long largest_prime_factor(long l);

int main(int argc, char *argv[])
{
  long result = largest_prime_factor(600851475143L);
  printf("%ld\n",result);
  return 0;
}

long largest_prime_factor(long l){
  long factor = 2L;
  while(l > 1L){
    while(l % factor == 0 ){
      l = l / factor;
    }
    factor++;
  }

  return (factor-1);
}

细想一下,这个算法与筛选法类似。但是,我怎么就没想到呢?FAIL!!!

2012年1月6日星期五

cURL “虾米” 签到的小脚本

这个脚本用于登陆虾米网站,并进行签到。虽然只是个二三十行的脚本,但由于对cURL不甚
了解,还是搞了几天。主要的经验有:

  1.  curl 用 -d 发送表单时,要把按钮的值也加进去("submit=登录")
  2.  curl 处理 ajax,应该通过分析javascript脚本,找到真正接收请求的url
  3.  curl 模拟 ajax时,添加 HTTP头 "X-Requested-With: XMLHttpRequest",更好的方法是观察实际的HTTP头,并构造出个一样的
  4.  总之,分析浏览器的HTTP请求,再用 cURL构造即可。


#! /bin/bash

declare -r SCRIPT="${0##*/}"

SITE="http://www.xiami.com"
USERAGENT="Mozilla/5.0 (compatible; MSIE 6.0; Windows NT 5.0)"
COOKIEFILE="cookie.txt"

USER="********@gmail.com"
PASSWORD="******"

# 检测cookie
if [[ ! -e $COOKIEFILE ]];then
    # 登录xiami
    curl -c $COOKIEFILE -d "email=$USER&password=$PASSWORD&submit=登录"  "$SITE/member/login"
fi

# 单击"签到"
curl -s  -b $COOKIEFILE -A "$USERAGENT" -e "$SITE" -H "X-Requested-With: XMLHttpRequest" -X POST -d "" "$SITE/task/signin" --retry 5 -H "Connection: keep-alive" 1>/dev/null

# 删除cookie
#rm $COOKIEFILE

2012年1月1日星期日

判断无符号整数二进制中1的个数(外一则)


三种算法。

算法1:
比较容易想到的算法,逐位比较,最多需要32次。
int count_ones_01(unsigned int n)
{
    int i;
    for(i = 0;n > 0;n >>= 1)
         i += (n&1);
    return i;
}

算法二:
Monster级算法。比较次数比算法1少,最多需要32次(如果int长度为32位的话)。
int count_ones_02(unsigned int n){
  int count=0;
  while(n>0){
    n &= (n-1);
    count++;
  }
  return count;
}

算法三:
二分法。遗憾的是不具有跨平台性。运算次数为5次(\(\log_{2}{32}\))
int count_ones(unsigned int n)
{
    n = (n & 0x55555555) + ((n >> 1) & 0x55555555);
    n = (n & 0x33333333) + ((n >> 2) & 0x33333333);
    n = (n & 0x0f0f0f0f) + ((n >> 4) & 0x0f0f0f0f);
    n = (n & 0x00ff00ff) + ((n >> 8) & 0x00ff00ff);
    n = (n & 0x0000ffff) + ((n >> 16) & 0x0000ffff);

    return n;
}

算法的思路是这样的:2位为一组,相加,看看有几个1。再4位为一组,相加,看看有几个1,
以此类推。
为了简单说明,先看看8位的情形。
x = (x & 0x55) + ((x >> 1) & 0x55);    (1)
x = (x & 0x33) + ((x >> 2) & 0x33);    (2)
x = (x & 0x0f) + ((x >> 4) & 0x0f);    (3)
return x;

对于语句(1)

当x=11111111
x= (x & 0x55) + ((x >> 1) & 0x55);
之后x=10101010。你2位2位地看,10=2, 就是2 2 2
2, 就是说各组都是2个1。

当x=00101001
x= (x & 0x55) + ((x >> 1) & 0x55);
之后x=00010101。你2位2位地看,就是0 1 1 1, 前
1组只有0个1,后面的组都是1个1。

接着看语句(2)

当x=abcdefgh
x=(x & 0x33)+((x >> 2)&0x33);
相当于 00cd00gh + 00ab00ef。

因为语句(1)之后,每两位表示该两位有几个1,相加就指示每4位有多少个1。这样就是4位
4位为一组。注意这样的分组,组与组之间永远都不会产生进位的。正因为不会产生进位,才
可以分开来看。

8位,16位,32位依上类推。

外一则:
利用算法三类似的思想,进行反转一个字节的二进制次序。
unsigned char reverse8( unsigned char c )
{
     c = ( c & 0x55 ) << 1 | ( c & 0xAA ) >> 1;
     c = ( c & 0x33 ) << 2 | ( c & 0xCC ) >> 2;
     c = ( c & 0x0F ) << 4 | ( c & 0xF0 ) >> 4;
     return c;
}

2011年12月28日星期三

最大的子序列和问题


最大的子序列和问题描述:
给定整数A1,A2,…,AN,求SUM(Ak),k从i到j,的最大值。为了方便起见,如果所有整数均为
负数,则最大子序列和为0。

例:
输入-2,11,-4,13,-5,-2时,答案为20(从A2到A4)

最大子序列和问题的解。
算法一:
穷举,复杂度为O(N^3)
int maxsubsequencesum(const int A[],int N){
    int thissum,maxsum,i,j,k;
   
    maxsum=0;
    for(i=0;i<N;i++)
        for(j=i;j<N;j++){
                thissum=0;
                for(k=i;k<=j;k++)
                        thissum += A[k];
               
                if(thissum > maxsum)
                        maxsum = thissum;
        }
    return maxsum;
}
算法二:
对算法一进行优化,减少内循环,复杂度为O(N^2)
int maxsubsequencesum_2(const int A[],int N){
    int thissum,maxsum,i,j;
   
    maxsum=0;
    for(i=0;i<N;i++){
        thissum=0;
        for(j=i;j<N;j++){
             thissum += A[j];
                    
             if(thissum > maxsum)
                   maxsum = thissum;
        }
    }
    return maxsum;
}
算法三:
分治:最大子序列可能在三处出现,或者整个出现在数据的左半部,或者整个出现在右半部,
或者跨越输入数据的中部而占据左右两半部分。前两种情况可以递归求解,第三种情况的最
大和可以通过求出前半部分的最大和(包含前半部分的最后一个元素)以及后半部分的最大
和(包含后半部分的第一个元素),将这两个和相加而得到。
复杂度为O(NlgN)
int maxsubsum(const int A[], int left,int right){
    int maxleftsum,maxrightsum;
    int maxleftbordersum,maxrightbordersum;/*包含边界的最大值*/
    int leftbordersum,rightbordersum;
    int center,i;

    if(left == right){
         if(A[left] > 0)
             return A[left];
         else
             return 0; /*由题给条件,负数的最大子序列长度为0*/
    }

    /* divide */
    center = (left + right)/2;
    maxleftsum = maxsubsum(A,left,center);
    maxrightsum = maxsubsum(A,center+1,right);

   /*conquer*/
   maxleftbordersum=0;
   leftbordersum=0;
   for(i=center; i>=left;i--){
       leftbordersum += A[i];
       if(leftbordersum > maxleftbordersum)
          maxleftbordersum = leftbordersum;
   }

  maxrightbordersum=0;
  rightbordersum=0;
  for(i=center+1; i <= right; i++){
      rightbordersum += A[i];
      if(rightbordersum > maxrightbordersum)
          maxrightbordersum = rightbordersum;
  }

  /* max3 取三者最大值 */
  return max3(maxleftsum, maxrightsum, maxleftbordersum + maxrightbordersum);
}

int maxsubsequencesum_3(const int A[], int N){
    return maxsubsum(A,0,N-1);
}
算法四:
在线算法,复杂度O(N),
int maxsubsequencesum(const int A[],int N){
    int thissum,maxsum,j;
    thissum = maxsum = 0;

    for(j=0; j < N; j++){
        thissum += A[j];
       
        if(thissum > maxsum)
            maxsum = thissum;
        else if(thissum < 0)
            thissum = 0;
    }
    return maxsum;
}

2011年12月14日星期三

Blogger使用SyntaxHighlighter插件及测试

Blogger中,也就是这个博客,使用SyntaxHighlighter来实现语法高亮,需要在模板文件中加入以下语句:

<head>
     <b:include data='blog' name='all-head-content'/>
     <!-- adel zhang 20111214 -->
     <!-- syntaxhighlighter -->
     <script src="http://sites.google.com/site/triadelphous/filestorage/shCore.txt" type="text/javascript">
     <script src='http://sites.google.com/site/triadelphous/filestorage/shBrushCpp.txt' type='text/javascript'/>
     <script src='http://sites.google.com/site/triadelphous/filestorage/shBrushJScript.txt' type='text/javascript'/>
     <script src='http://sites.google.com/site/triadelphous/filestorage/shBrushXml.txt' type='text/javascript'/>
     <script src='http://sites.google.com/site/triadelphous/filestorage/shBrushJava.txt' type='text/javascript'/>
     <script src='http://sites.google.com/site/triadelphous/filestorage/shBrushBash.txt' type='text/javascript'/>
     <script src='http://sites.google.com/site/triadelphous/filestorage/shBrushCss.txt' type='text/javascript'/>
     <link href='http://sites.google.com/site/triadelphous/filestorage/shThemeEmacs.css' rel='stylesheet' type='text/css'/> 
     <script type='text/javascript'>
     SyntaxHighlighter.defaults["quick-code"]=false;
     SyntaxHighlighter.config.bloggerMode = true;
     SyntaxHighlighter.defaults["toolbar"] = false;
     SyntaxHighlighter.all();
     </script>

因为Blogger无法存储外部文件,所以将需要的js文件托管在Google Sites上。至于文件名为什么要改成txt,这是由于有帖子
But Google Sites, like most free host doesn’t accept javascripts. Luckily there is a workaround -change the javascript file into a text file, by changing the file extension from .js to .txt.


Update:20111217
本来将下载的SyntaxHighlighter托管在Google Sites上,但不知为何链接不到了(上回测试时是可以的)。所以重新修改了模板,使用的是SytaxHighlighter作者提供的pub服务。
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shCore.js' type='text/javascript'/>
    <script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushCpp.js' type='text/javascript'/>
    <script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushJScript.js' type='text/javascript'/>
    <script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushXml.js' type='text/javascript'/>
    <script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushJava.js' type='text/javascript'/>
    <script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushBash.js' type='text/javascript'/>
    <script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushCss.js' type='text/javascript'/>
    <link href='http://alexgorbatchev.com/pub/sh/current/styles/shThemeEmacs.css' rel='stylesheet' type='text/css'/>

Update: 20120107
遇到的问题是如果代码行太长,则显示时会换行,这样就造成syntaxhighlighter的行号显示出现混乱,极为丑陋。后来发现添加shCore.css这个css后,它会出现滚动条,缓解了行号混乱的问题。但不爽的地方在于会出现竖直滚动条,原因在于shCore.css中对overflow属性使用了visible。所以我们在模板文件中加入下面这些css语句(这些类名是shCore.css里面定义的),以消除竖直方向上的滚动条。特别注意 !important 的用法,它使得css不是按照通常的定义顺序来使用,而是使用有 !important 的css语句。

/* adel: 20120107
------------- for syntaxhighlighter -----------
------------- get rid of y-sroll --------------*/
.syntaxhighlighter a,
.syntaxhighlighter div,
.syntaxhighlighter code,
.syntaxhighlighter table,
.syntaxhighlighter table td,
.syntaxhighlighter table tr,
.syntaxhighlighter table tbody,
.syntaxhighlighter table thead,
.syntaxhighlighter table caption,
.syntaxhighlighter textarea {
   overflow-y: hidden !important;
}

之前的设置去掉了 toolbar,也就是提示syntaxhighlighter信息的小问号,想想还是加上为好。所以最终的代码为:
<!-- adel zhang 20120107 -->
<!-- syntaxhighlighter -->
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shCore.js' type='text/javascript'/>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushCpp.js' type='text/javascript'/>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushJScript.js' type='text/javascript'/>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushXml.js' type='text/javascript'/>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushJava.js' type='text/javascript'/>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushBash.js' type='text/javascript'/>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushCss.js' type='text/javascript'/>
<link href='http://alexgorbatchev.com/pub/sh/current/styles/shCore.css' rel='stylesheet' type='text/css'/>
<link href='http://alexgorbatchev.com/pub/sh/current/styles/shThemeEmacs.css' rel='stylesheet' type='text/css'/>
<script type='text/javascript'>SyntaxHighlighter.config.bloggerMode = true;SyntaxHighlighter.all();</script>

2011年12月10日星期六

IPV6下GoAgent的使用

先说FAIL的部分。
今天启动系统的时候,在正常的登陆界面下输入用户名和密码后,就出现花屏,进不去系统。当时第一反应是:完蛋鸟,又得折腾一番,而且很大可能是搞不定然后重装系统,毕竟这不是X就是驱动出问题了,我完全没概念的。
更要命的是我刚把网络通给关了(见下文),也就是说不能求助GOOGLE大神。还好在Grub启动项里有个叫Resume的选项,或许能启动系统。在输入用户名和密码后,果不其然能启动到文字界面,还出现了可疑的出错信息sogouproxy.py。我才想起昨天修改过~/.profile文件,在其中添加执行sogouproxy.py,用于启动搜狗代理服务器。罪魁祸首就是系统启动时当执行用户配置文件时,sogouproxy,py就卡住了,造成X不能正常启动。只能说,学术不精,FAIL!!!

再说说IPV6下GoAgent的使用。
以前介绍过GoAgent,主要是备不时之需(你懂的)。最近校园网络改造,原本寝室可以上教育网,现在只能上校内网络(鸡肋),开通10元的网络通才只能有个教育网出口的国内权限(鸡肋),非得20元的网络通才能有国际权限(抢钱阿)。但神奇的是,即使只有校内权限,但IPV6是不受限制的,所以修改过IPV6 host的google系网站还是可以蹭的。
GoAgent是部署在GAE上的,所以很自然地想是否能通过IPV6连接GoAgent,以此作为IPV4的代理。庆幸的是,GoAgent默认支持IPV6的,只要简单地修改配置文件即可:
在proxy.ini 的 [appspot] 节中有
hosts = cn
修改为:
hosts = ipv6
在 [google]节中,默认使用cn的hosts,注释掉了hk和ipv6的hosts。为了使用ipv6,将cn的hosts注释掉,并去掉ipv6的注释。
重启Goagent,就可以通过ipv6免费上网拉,速度很OK。