12/27/2013

Regex in Java

在 java 中使用正则表达式需要用到以下两个类:
import java.util.regex.Matcher;
import java.util.regex.Pattern;
最简单的使用方法:
        String regex = "test";
        String testString = "test";
        Pattern testPattern = Pattern.compile(regex);
        Matcher testMatcher = testPattern.matcher(testString);
        while (testMatcher.find()) {
            String tmpResult = testMatcher.group();
        }
Pattern.compile(regex) 用来生成一个 Pattern 的实例。我们不能用 new Pattern 来生成一个 Pattern 对象,因为它的构建方法是 private :
    private Pattern(String p, int f) {
        pattern = p;
        flags = f;

        // to use UNICODE_CASE if UNICODE_CHARACTER_CLASS present
        if ((flags & UNICODE_CHARACTER_CLASS) != 0)
            flags |= UNICODE_CASE;

        // Reset group index count
        capturingGroupCount = 1;
        localCount = 0;

        if (pattern.length() > 0) {
            compile();
        } else {
            root = new Start(lastAccept);
            matchRoot = lastAccept;
        }
    }
而当我们调用 Pattern.compile(regex) 的时候,实际上是执行的这段代码:
    public static Pattern compile(String regex) {
        return new Pattern(regex, 0);
    }
Pattern(String p, int f) 的第一个参数是字符串形式的正则表达式,第二个参数是一些特殊选项的开关。它接受如下几个参数:
    /**
     * Enables Unix lines mode.
     */
    public static final int UNIX_LINES = 0x01;

    /**
     * Enables case-insensitive matching.
     */
    public static final int CASE_INSENSITIVE = 0x02;

    /**
     * Permits whitespace and comments in pattern.
     */
    public static final int COMMENTS = 0x04;

    /**
     * Enables multiline mode.
     */
    public static final int MULTILINE = 0x08;

    /**
     * Enables literal parsing of the pattern.
     */
    public static final int LITERAL = 0x10;

    /**
     * Enables dotall mode.
     */
    public static final int DOTALL = 0x20;

    /**
     * Enables Unicode-aware case folding.
     */
    public static final int UNICODE_CASE = 0x40;

    /**
     * Enables canonical equivalence.
     */
    public static final int CANON_EQ = 0x80;

    /**
     * Enables the Unicode version of Predefined character classes and
     * POSIX character classes.
     */
    public static final int UNICODE_CHARACTER_CLASS = 0x100;
一般而言我们可以用这种方法来调用:
        Pattern testPattern = Pattern.compile(regex, Pattern.CASE_INSENSITIVE);
testPattern.matcher(testString) 用来获取一个 Matcher 对象的实例。它会调用如下方法:
    public Matcher matcher(CharSequence input) {
        if (!compiled) {
            synchronized(this) {
                if (!compiled)
                    compile();
            }
        }
        Matcher m = new Matcher(this, input);
        return m;
    }
因为我们的 Pattern 已经编译 (compile) 过了,所以实际上这段代码和 new Matcher(testPattern, testString) 是相同的。不过使用这种方法可以保证 Pattern 是经过编译的。

Matcher.find() 方法搜索 testString 匹配正则表达式的子字符串,Matcher.group() 会调用 Matcher.group(0) 即:
    public String group(int group) {
        if (first < 0)
            throw new IllegalStateException("No match found");
        if (group < 0 || group > groupCount())
            throw new IndexOutOfBoundsException("No group " + group);
        if ((groups[group*2] == -1) || (groups[group*2+1] == -1))
            return null;
        return getSubSequence(groups[group * 2], groups[group * 2 + 1]).toString();
    }
这里的 groups 是一个数组,用于存储每次匹配时匹配的起始与结尾所在的位置。数组的大小由正则表达式中 group 的个数决定。在 Matcher 初始化时候指定:
    Matcher(Pattern parent, CharSequence text) {
        this.parentPattern = parent;
        this.text = text;

        // Allocate state storage
        int parentGroupCount = Math.max(parent.capturingGroupCount, 10);
        groups = new int[parentGroupCount * 2];
        locals = new int[parent.localCount];

        // Put fields into initial states
        reset();
    }
parent.capturingGroupCount 表示正则表达式中 group 的个数再加1,因为 0 表示整个匹配项。
而 groups 的大小则是这个数乘以2。这里比较有意思的是 Math.max(parent.capturingGroupCount, 10)。 我弄不明白为什么要这样做,而且我做了几个简单的实验,不用这一步并没有出现 Bug。
需要注意的是,在调用 group() 之前一定要确保 find() 返回的是 true 。如果 find() 返回 false 表示在该字符串中已经找不到更多的匹配项了。这时候调用 group() 会抛出 IllegalStateException 异常。当然如果你调用 group(100) 很可能会抛出 IndexOutOfBoundsException 异常。稳妥的方法是先调用 testMatcher.groupCount() 再根据结果调用 group() 。
find() 方法如下:
    public boolean find() {
        int nextSearchIndex = last;
        if (nextSearchIndex == first)
            nextSearchIndex++;

        // If next search starts before region, start it at region
        if (nextSearchIndex < from)
            nextSearchIndex = from;

        // If next search starts beyond region then it fails
        if (nextSearchIndex > to) {
            for (int i = 0; i < groups.length; i++)
                groups[i] = -1;
            return false;
        }
        return search(nextSearchIndex);
    }
    boolean search(int from) {
        this.hitEnd = false;
        this.requireEnd = false;
        from        = from < 0 ? 0 : from;
        this.first  = from;
        this.oldLast = oldLast < 0 ? from : oldLast;
        for (int i = 0; i < groups.length; i++)
            groups[i] = -1;
        acceptMode = NOANCHOR;
        boolean result = parentPattern.root.match(this, from, text);
        if (!result)
            this.first = -1;
        this.oldLast = this.last;
        return result;
    }
由于一个字符串中可能会有多个子自字符串与正则表达式相匹配。 find() 方法就是确保我们能顺序地得到每组匹配地结果。这里的 last 记录上次匹配的末尾位置。from 和 to 默认值为 0 和整个字符串的长度,也可以通过 public Matcher region(int start, int end) 来设置。所以每次调用 search(nextSearchIndex) 的时候可以保证是从上次匹配结果的末尾开始的。
这里最重要的方法就是:
        boolean result = parentPattern.root.match(this, from, text);
parentPattern 是 Pattern 类的实例,在刚才讲 Matcher 的构建方法时有代码可以证明。再进入 parentPattern.root.match 的方法之后我们可以看到如下代码:
        boolean match(Matcher matcher, int i, CharSequence seq) {
            matcher.last = i;
            matcher.groups[0] = matcher.first;
            matcher.groups[1] = matcher.last;
            return true;
        }
看着非常简单,在这里会修改 matcher 里 groups 的内容,从而得到匹配项的起始和结束的位置。没错这就是 Pattern 类实现正则表达式的方法。但我们知道正则表达式的匹配是用有限状态机来实现的。上面这段代码只是一个名叫 Node 的类的实现。
实际上 Pattern 类中一共有31个子类直接继承了 Node, 24个类间接继承了 Node, 实现了43个 match() 的方法(由于间接继承的存在)。
以下是 Node 的源代码:
    static class Node extends Object {
        Node next;
        Node() {
            next = Pattern.accept;
        }
        /**
         * This method implements the classic accept node.
         */
        boolean match(Matcher matcher, int i, CharSequence seq) {
            matcher.last = i;
            matcher.groups[0] = matcher.first;
            matcher.groups[1] = matcher.last;
            return true;
        }
        /**
         * This method is good for all zero length assertions.
         */
        boolean study(TreeInfo info) {
            if (next != null) {
                return next.study(info);
            } else {
                return info.deterministic;
            }
        }
    }
实际上 Pattern 就是靠 compile() 来实现对正则表达式的编译:
    private void compile() {
        // Handle canonical equivalences
        if (has(CANON_EQ) && !has(LITERAL)) {
            normalize();
        } else {
            normalizedPattern = pattern;
        }
        patternLength = normalizedPattern.length();

        // Copy pattern to int array for convenience
        // Use double zero to terminate pattern
        temp = new int[patternLength + 2];

        hasSupplementary = false;
        int c, count = 0;
        // Convert all chars into code points
        for (int x = 0; x < patternLength; x += Character.charCount(c)) {
            c = normalizedPattern.codePointAt(x);
            if (isSupplementary(c)) {
                hasSupplementary = true;
            }
            temp[count++] = c;
        }

        patternLength = count;   // patternLength now in code points

        if (! has(LITERAL))
            RemoveQEQuoting();

        // Allocate all temporary objects here.
        buffer = new int[32];
        groupNodes = new GroupHead[10];
        namedGroups = null;

        if (has(LITERAL)) {
            // Literal pattern handling
            matchRoot = newSlice(temp, patternLength, hasSupplementary);
            matchRoot.next = lastAccept;
        } else {
            // Start recursive descent parsing
            matchRoot = expr(lastAccept);
            // Check extra pattern characters
            if (patternLength != cursor) {
                if (peek() == ')') {
                    throw error("Unmatched closing ')'");
                } else {
                    throw error("Unexpected internal error");
                }
            }
        }

        // Peephole optimization
        if (matchRoot instanceof Slice) {
            root = BnM.optimize(matchRoot);
            if (root == matchRoot) {
                root = hasSupplementary ? new StartS(matchRoot) : new Start(matchRoot);
            }
        } else if (matchRoot instanceof Begin || matchRoot instanceof First) {
            root = matchRoot;
        } else {
            root = hasSupplementary ? new StartS(matchRoot) : new Start(matchRoot);
        }

        // Release temporary storage
        temp = null;
        buffer = null;
        groupNodes = null;
        patternLength = 0;
        compiled = true;
    }
不同的正则会生成不同类型的 Node 对象,不同对象的 match 方法不同。这里是根据是否开启 LITERAL 选项,分别调用 expr 和 newSlice 来构建正则表达式所对应的 Node 对象。
至于 Pattern 如何构建 Node 对象,基本上就是把正则表达式转换为有限状态机的过程。并伴随着处理不同选项的琐碎细节。
可以参考:
Youtube: Convert Regular Expression to Finite-State Automaton
Implementing Regular Expressions
Regular Expressions and Finite-State Automata
Regular Languages and Finite-State Automata

12/20/2013

To Ensure Vim in Terminal As Same As MacVim

If you have installed Vim and MacVim manually. Please delete/rename MacVim.app, and run "brew uninstall vim".

Run
"brew install macvim --override-system-vim";
"brew linkapps";

And enjoy.

12/02/2013

Mac SSH localhost use key without password

I am able to resolve this issue after excuting the below commands



chmod go-w ~/

chmod 700 ~/.ssh

chmod 600 ~/.ssh/authorized_keys

Actually first command resolved the issue


11/18/2013

Fix a Function matlab-shell-run-cell in Matlab-Emacs

Since the official site of Matlab-Emacs doesn't provide valid download links.


I clone the code from: https://github.com/ruediger/matlab-emacs

Original matlab-shell-run-cell () cannot correctly recognize cells split by "%%".

This is original code of matlab-shell-run-cell ():
Loading ....


This is the fixed code:
Loading ....

Suppose you already got the Matlab-Emacs code.

You just need to:
  1. Open matlab.el
  2. Find the function matlab-shell-run-cell ()
  3. Del or comment all content of this function
  4. Paste my code to the same position.
And enjoy it.

For those who cannot see the code snippets, please visit this link:
https://gist.github.com/xcv58/7534683

xcv58

7/08/2013

Windows 7 锁定后输入法切换快捷键失效

在Windows 7里自定义了切换输入法的快捷键,一旦电脑锁定,就会使该快捷键失效。原因在于调用 LockWorkStation 会使相关配置重置。无论用Win+L、开始菜单选项、rundll32.exe user32.dll,LockWorkStation还是DllCall都会触发这一机制。   

困扰我数年的问题终于找到症结了,但如何解决还没有头绪。

6/16/2013

Closing from Boston Legal 011 - Alan - Warrior Within Belly

Alan在酒吧里雇别人帮他打架,最后还能被判无罪。我觉得就是这句话起了作用:"There's a warrior that lies within the belly of every man." 这一段非常赞哦,貌似Alan讲人性的时候从来没输过。MP3下载:http://jianguoyun.com/p/Dc1-qU8QtYYEGJxW #BL Closing#



第十四集了,第一季还有三集。不过最近几天还是不能保证每天更新。

Closing from Boston Legal 010 - Nansy-Pansy Judge and Law Ban Beef

一个小镇制定了法律禁止销售牛肉。Shirley代理牛排店主起诉镇长。但宪法并没有规定卖汉堡包的权力。Denny深深地了解可爱的Judge Clark Brown,用了Nansy-Pansy战术搞定了法官,挽救了Shirley。这次不仅有结案陈词还加了法官的宣判以及Flirt情节哦。MP3下载:http://jianguoyun.com/p/DRkW9e4QtYYEGJtW #BL Closing#



发布了FDA vs Doctor之后一直再忙:忙签证,btw:签证顺利通过了;忙着办学校需要的证明;然后我又陪着亲戚在北京玩。想着要保证MP3的品质,一直等到今天有大把的时间和精力了才做。一会还会发Alan精彩的Closing.

6/09/2013

Closing from Boston Legal 009 - Alan & Denny - FDA vs Doctor



Denny接了个FDA起诉医生的案子,医生违反了FDA的规定给一个濒死的胖纸开了未经批准的药,如果原告胜诉医生不仅会被吊销执照还会被判刑。Denny想单干,但大家都不放心,Shirley在卫生间里请Alan去帮忙。结果这俩好基友就共同做了一个结案陈词。MP3下载:http://jianguoyun.com/p/DXFSm98QtYYEGKdT #BL Closing#


这已经是第十三集了,很快第一季就要完了。

在Kindle for Android中使用自定义字体

众所周知,Kindle Apps的体验并不是最好的。但由于在中国区的Kindle上买了很多书,又不想进行破解。只能凑合着使用它家的App,但更改一下默认字体会使体验提高一些。

但Kindle for Android也没有提供自定义字体的选项。只好自己DIY了:

首先你得是Android系统;

找到如下路径:
/sdcard/Android/data/com.amazon.kindle/files/fonts/zh/

把你想用的字体文件(ttf格式)复制进去;

修改该目录下的system_fonts.xml;
你能找到两个类似以下格式的片段:
<fileset>
<file>/storage/sdcard0/Android/data/com.amazon.kindle/files/fonts/zh/STBShusongRegular.ttf</file>
</fileset>

把第二个里边的STBShusongRegular.ttf修改成你自己的字体文件名称即可,应该只支持英文名。

然后强行关闭Kindle再打开就可以了。Bingo.

MIUI v5 小米1、小米2;颜体实测可用。

6/07/2013

Closing from Boston Legal 008 - Give the World A Gay Santa Claus



Alan的客户是一个圣诞老人扮演者,同性恋异装癖,被解雇了。因为有个异装癖的孩子请他把自己变正常。他把自己的故事告诉了孩子。这一次Brad又和Alan打赌了,而且上了手段。Alan不得不向Denny求助,所以可爱的神父Al Sharpton出现了。MP3下载:http://jianguoyun.com/p/DQjAxWQQtYYEGNtR #BL Closing#

昨天没有更新,我看了两集竟然一个Closing都没有。还好今天有一个精彩的。

6/05/2013

Closing from Boston Legal 007 - Alan - Humanity in Medical Case

一个偏头痛的IT男治疗了六个月却没得到实质性的治疗,也没得到正确的医疗建议。在总结了案情之后,Alan开始对Jury讲人性,要知道一旦Alan讲人性那就是必胜的。最后IT男得到了32万美刀的判决。估计他六个月的医疗费也不到2万美刀吧。MP3下载:http://jianguoyun.com/p/DQDPRo8QtYYEGIdP  #BL Closing#

6/04/2013

Closing from Boston Legal 006 - Denny Got A Mistrial for Delay of A Medical Class Action Lawsuits and Humiliate Judge

Edwin的案子上庭前一天才开始接手。这还是个集体诉讼。Paul和Denny去请求法官延期,法官由于私心不批准,Denny放了狠话。最后Denny把该案弄成了无效审判,让案件延期并且使法官不能审理该案。好像他在申请延期失败时就想好了这招,但在该集末尾他否认了。MP3下载:http://jianguoyun.com/p/DcfGokMQtYYEGIxN  #BL Closing#


2013年6月4日

  到今年中共已经建政64周年,同时今天也是第24个64纪念日。刚才在看维园六四烛光晚会的直播,但中间直播中断了大概1小时,有朋友说直播可以看了的时候我还是看不了。最后找了一个音频直播的链接。期间也在微博上发了一些感触。现在写博客的越来越少,可能一个重要的原因就是想说什么就直接在微博上发了,想表达的欲望直接被满足了。很难再沉下心来写博客。我现在就是这个状态,待我把微博都整理到这篇博客里吧。
  昨天晚上睡觉前就发了这条:都24年了,也没见什么长进。」每年的这个时候都特别感慨,审视下当下发现进步确实乏善可陈、退步倒是数不胜数。
  今天早上起床前发的:贵国拥有全世界最知名的广场,知道为什么最知名吗?
  发送时间同上,纯粹是向 让子弹飞 致敬刚过完儿童节就枪杀人民,这不是两千万人头能打发走的。
  打开电脑看UB的简介时发的:About UB - University at Buffalo http://t.cn/zHCrOhU 纽约大学有64个分校。64个!」这条虽有64,但并没被小秘书删除或加密,难道有洋文就不敢动?
  维园晚会刚开始时发的:开始唱 血染的风采 。」这条很快就被加密了。
  发送时间同上:无论雨怎么打,自由仍是会开花。」也是很快就被加密了。这句歌词真是太好了!写到Twitter的个人简介上了。
  不能看直播之后发的:我觉得维园活动的口号有点问题。平反了又能如何呢,我认为应该在法治的基础上公开信息、惩罚凶手、纠正冤案、进一步进行政治体制改革才对。」
  时间同上:凶手之一的陈希同已于六月二日死亡?」这个应该是真的,多个消息源都已确认了。
  看到@songma这条tweet之后把图都存下来之后发的:我爱祖国天安门,天安门旁水箱开。
」这条目前还没被黑。
  以上都是听着平反六四的口号写出来的。我对这篇博客很不满意,感觉很多想法憋在心里很难表达出来。另外也有可能是被最近一系列反宪政的官方言论恶心到了。
  2013年5月22号,我相信这一天会被写到历史上的。这一天的前一天《红旗文稿》发了一文名为:宪政与人民民主制度之比较研究;而紧接着的第二天日人民报发了党员相信党性如同基督徒相信“上帝”解放军报发了《我们信仰的主义乃是宇宙的真理、环球时报发了社评“宪政”是兜圈子否定中国发展之路》。我觉得这是一件非常恐怖的事,恐怕这是共产党历史上第一次公开地否认宪政吧。而且我深深地觉得这个政权已经精神分裂了。一边讲着法治,另一边说不能搞宪政。一边宣称自己是无神论者,另一边说自己的党性如果上帝。既然你有宇宙的真理,那让实践是检验真理的唯一标准往何处放?一边宣称自己有道路自信、理论自信、制度自信,另一边觉得别人说句话自己就会被颠覆。
  另外有人说这是阳谋,可以引蛇出洞,把不支持宪政的人都暴露出来。我实在难以接受如此阿Q的逻辑。这就好像是说你被人暴打了一顿,心里却想:哼哼,这下把敢打我的人都引出来了。
  每每这种时候我都会想到南都1999年的主编寄语:让无力者有力,让悲观者前行与诸位共勉

  陈毅鸿 2013年6月4日晚 于北京昌平

6/03/2013

Closing from Boston Legal 005 - Sally - Confession of Murderer without Other Evidence

Lori代理一个杀人犯,其实这案子是Edwin从精神病院里跑出来到法庭揽下的。客户枪杀了警察,后来被抓住在医院里承认了自己的罪行。后来律师发现医生骗他要死了他才承认的。但Edwin却没准备结案陈词,Lori临时顶替。其实这案子完全能无罪的,可惜没准备好。MP3下载:http://jianguoyun.com/p/DYhSm_MQtYYEGJ1O #BL Closing#

Closing from Boston Legal 004 - Christine & Alan - Alan vs. Christine about Sexual Harassment

Alan代理一位女士起诉她的前情夫和老板性骚扰,而对方律师恰好是Christine,就是那个被Alan从精神病院救出来的前女友。她非常明确的指出现有的性骚扰法律歧视妇女,把妇女当成预设的弱者,而不能平等地对待她们。非常精彩但不够有力。MP3下载: http://t.cn/zHKsO3Z #BL Closing#

这个是用手机写的,昨天下午去参加了个活动。晚上去和同学吃了烤羊腿(PS:链接内有帅哥),吃嗨了之后又去看了星际迷航,看完都晚上11点多了,就住我同学家了。btw:今天我又看了一遍星际迷航,真的挺好看的。

6/01/2013

Closing from Boston Legal 003 - Sally - Stole Wallet or Just Mistaken

Sally接了一个案子,一个穷人被控告偷了一位女士的钱包。但他辩称以为那是自己的钱包才拿过来看看。他也挺逗的,在庭上突然把自己的钱包拿出来。最后Sally靠着Alan的帮助,用一个关于兔子的故事成功地获得一个无罪判决。第三集有三个案件穿插着,比较精彩。MP3下载:http://jianguoyun.com/p/DZXZ7HQQtYYEGOtM #BL Closing#

今天还比较顺利,大概十来分钟就搞定了。

5/31/2013

Closing from Boston Legal 002 - Donny - Brad - Debate of Salmon

第三集是可爱的Donny Crane第一次出场。他打算阻止一项建设计划,原因是一条河里有野生三文鱼卵,而野生三文鱼是保护物种。辩论的核心是能否把家养三文鱼计入三文鱼种群总数,这将决定三文鱼是否是濒危物种。最后以Brad的败北而告终。Donny确实挺有天赋的。MP3下载:http://jianguoyun.com/p/DUpuhJYQtYYEGLJM #BL Closing#


昨天今天发的晚了点。现在发的还是以前的老本,没想到光整理来龙去脉、组织语言都花了半个多小时才搞定。sigh

5/30/2013

Closing from Boston Legal 001 - Give the American People A Black Orphan Annie

一个黑人女孩想演电视,但由于剧本里的脚色是个白人孤儿被拒演。决定聘Alan Shore以种族歧视来起诉。在即将败诉的时候,神父Al Sharpton出现并进行了一场非常富有激情的演讲:Give the American People A Black Orphan Annie. 最终法官不得不判决原告胜诉。MP3下载:http://jianguoyun.com/p/DfRyP5kQtYYEGM5L #BL Closing#

4/04/2013

拿到一个Buffalo的Offer,但没奖学金。怎么办?

目前为止,就拿到一个Buffalo的PhD Offer,但是没有奖学金。2013.4.15之前需要给回复。

目前已经被拒了6所,还有三四所没给消息。

如果去的话,至少需要$33,443的资金(资产证明的要求)。

虽然家里可以支付的起,但一下子拿出这么多还是比较紧张。而且非常麻烦,要把钱存到银行冻结一段不低于一个月的时间……

去还是不去?是个问题。

请各位读者、亲朋好友给我些意见。
知道手机号的可以直接短信我,我给你打过去。
不知道的:
  新浪微博:@xcv58_
  Twitter:@xcv58

3/28/2013

Ubuntu下的Privoxy使用与配置同步方案

在笔记本上装了64位版的Ubuntu 12.10,第一件事就是配置如何Fuck GFW,下载Chromium。

由于流量有限,自然用Privoxy比较合适。但在修改/etc/privoxy/config的时候一不小心就把默认的config文件给覆盖了,而且还是用的Windows版本的文件。然后无论如何都不能启动/etc/init.d/privoxy start。 重装privoxy,提取源码包中的config文件都不行。

后来自己手写了一个config文件,可以勉强启动并且根据规则判断是否转发。但http://p.p/页面一直显示:

"500 Internal Privoxy Error
Privoxy encountered an error while processing your request:
Could not load template file default or one of it's
included components.
Please contact your proxy administrator.
If you are the proxy administrator, please put the
required file(s)in the (confdir)/templates directory.

这时候我强迫症发作了:用VirtualBox全新安装了一个Ubuntu,然后把默认的配置文件提取出来:点此下载(/etc/privoxy目录下的所有文件)。

对比可以发现原因是Linux和Windows下的config和config.txt不能通用。主要在于目录变量以及功能的支持上:Linux下的config默认内容:
user-manual /usr/share/doc/privoxy/user-manual
confdir /etc/privoxy
logdir /var/log/privoxy
actionsfile match-all.action # Actions that are applied to all sites and maybe overruled later on.
actionsfile default.action   # Main actions file
actionsfile user.action      # User customizations
filterfile default.filter
filterfile user.filter      # User customizations
logfile logfile
listen-address  localhost:8118
toggle  1
enable-remote-toggle  0
enable-remote-http-toggle  0
enable-edit-actions 0
enforce-blocks 0
buffer-limit 4096
forwarded-connect-retries  0
accept-intercepted-requests 0
allow-cgi-request-crunching 0
split-large-forms 0
keep-alive-timeout 5
socket-timeout 300

Windows下的config.txt默认内容:
confdir .
logdir .
actionsfile match-all.action # Actions that are applied to all sites and maybe overruled later on.
actionsfile default.action   # Main actions file
actionsfile user.action      # User customizations
filterfile default.filter
filterfile user.filter      # User customizations
logfile logfile
listen-address  127.0.0.1:8118
toggle  1
enable-remote-toggle  0
enable-remote-http-toggle  0
enable-edit-actions 0
enforce-blocks 0
buffer-limit 4096
enable-proxy-authentication-forwarding 0
forwarded-connect-retries  0
accept-intercepted-requests 0
allow-cgi-request-crunching 0
split-large-forms 0
keep-alive-timeout 5
tolerate-pipelining 1
socket-timeout 300

最后完全重写了转发的规则,以前都是直接写在config文件里。但现在需要多平台同步,并且config文件不能通用,只好把forward规则改写成action的方式。
要感谢 七星庐:强大的代理调度器代理 Privoxy 和 cckpg的autoproxy2privoxy 的帮助。其实改写过程就几分钟,但苦在Privoxy的action功能太强大,这种简单的功能反而不知道如何下手。

然后就是把新写好的config和proxy.action文件放到Dropbox里Windows版的Privoxy目录下,再用硬链接链接到/etc/privoxy目录下。

这样Windows直接打开Dropbox中的exe程序就可以使用,Ubuntu下也可以同步到最新的规则。

但是经过多机实验,发现一个BUG,如果在Windows平台下修改proxy.action文件,会导致Ubuntu的硬链接失效。初步认为是坚果云同步文件的实现方式造成的。但由于网络环境导致Dropbox不能实时同步,所以不能确定原因。

EOF

3/17/2013

The Old Reader的全屏模式Bookmarklet

Google Reader要关了,The Old Reader是个不错的替代品。但是没有全屏模式这一点我有点小不爽。所以自己DIY了一个Bookmarklet凑合用着。 

update:HeiNotes指出了这个脚本不能适用于https的theoldreader,已经改正 http://www.heinotes.com/2013/03/HTTPS-The-Old-Reader-Fullscreen.html


JavaScript 代码:

javascript:(function(){var v=new RegExp('theoldreader.com');if(!v.test(document.URL)){alert('The script can only work in theoldreader.com!');}else{a=document.getElementById('main');b=document.getElementById('sidebar');c=document.getElementsByClassName('subscribe-fixed-top');d=document.getElementsByClassName('navbar-fixed-top');e=document.getElementsByClassName('container-fluid');if(typeof top == 'undefined'){var top='';}if('none' != b.style.display){top=window.getComputedStyle(e[0],null).getPropertyValue('top');e[0].style.top='5px';left=a.style.left;width=a.style.width;b.style.display='none';c[0].style.display='none';d[0].style.display='none';a.style.left='-25px';a.style.width='99%';}else{b.style.display='block';c[0].style.display='block';d[0].style.display='block';e[0].style.top=top;a.style.left=left;a.style.width=width;}return;}})();

直接复制再粘贴到收藏夹栏里即可。或者直接拖动下面一句文字:


下面是代码的简短注释:

//a means main body that display the real entities.
//b means the sidebar on the left.
//c means the add subscription button.
//d means the header in the top
//e means the container of the main(a), the sidebar(b) and the ADD BUTTON(c).

仅在Chrome和IE 10上测试通过。

FullScreen for the Old Reader

It's a bookmarklet for The Old Reader, the best alternative of the Google Reader. It can toggle the interface of your Old Reader just like the fullscreen feature of Google Reader with one click.


Here is the JavaScript code:

javascript:(function(){var v=new RegExp('theoldreader.com');if(!v.test(document.URL)){alert('The script can only work in theoldreader.com!');}else{a=document.getElementById('main');b=document.getElementById('sidebar');c=document.getElementsByClassName('subscribe-fixed-top');d=document.getElementsByClassName('navbar-fixed-top');e=document.getElementsByClassName('container-fluid');if(typeof top == 'undefined'){var top='';}if('none' != b.style.display){top=window.getComputedStyle(e[0],null).getPropertyValue('top');e[0].style.top='5px';left=a.style.left;width=a.style.width;b.style.display='none';c[0].style.display='none';d[0].style.display='none';a.style.left='-25px';a.style.width='99%';}else{b.style.display='block';c[0].style.display='block';d[0].style.display='block';e[0].style.top=top;a.style.left=left;a.style.width=width;}return;}})();

PS: You can copy this code and paste it on your browser's bookmarks bar. Or just try dragging the fonts below.


And here is simple comments:

//a means main body that display the real entities.
//b means the sidebar on the left.
//c means the add subscription button.
//d means the header in the top
//e means the container of the main(a), the sidebar(b) and the ADD BUTTON(c).

I just test the code in chrome and IE 10.