最近使用 Eclipse 时碰到了一个奇怪的问题, 源代码完全没错, 但 Eclipse 总是报错:

Error generating final archive: Debug certificate expired on XXX

google 了一把, 在 stackoverflow 发现答案:

http://stackoverflow.com/questions/2194808/debug-certificate-expired-error-in-eclipse-android-plugins

问题的产生和 android sdk 有关, 只需要删除文件: ~/.android/debug.keystore , 再重启 eclipse 就行了.

 

 

可视化完全二叉树

2010年8月09日 06:12

 完全二叉树的特性:从根结点开始每一层都从左到右填充” 使得它可以用一维数组直接存储一棵树本身。这个数组虽然逻辑上已经是树型的了,但表现形式却还是一维的,看起来很费劲。因此我写了个脚本,把一个数组转换成png图像,就像下面这样:

 array  {1, 2, 3, 4, 5}
 pic 

直接将一个树显示为png文件是很麻烦的,因为不仅得需要知道使用生成png的相关api(svg就不用了),还得想办法画好各结点的间距、距离、连接线,这些都不是轻而易举能搞定的。不过有前人栽树,后人就好乘凉了,Graphviz 就是要乘凉的那棵树。

Graphviz 提供了一系列的工具,dot 就是其中之一。dot 的功能就能是:用专门的描述语言显示图形,比如上面的 {1,2,3,4,5} 树的 dot 源代码就是:

 

graph
{
1 -- 2
1 -- 3
2 -- 4
2 -- 5
}

 

就这么简单。剩下的工作就更简单了,只需要把数组显示成上面的源代码就行了。

转换代码如下:

 

  ;; emacs lisp
  ;;;;;;;;;;;;;;
  (defun complete-binary-tree-to-dot-script (array)
    "convert complete binary tree to dot script language"
    (when (and (sequencep array) (> (length array) 1))
      (let ((result "graph\n{\n")
            (i 0)
            (N (length array)))
        (while (< i N)
          (setq result (concat result (proc-left  array i)))
          (setq result (concat result (proc-right array i)))
          (setq i (+ 1 i)))
        (concat result "}\n")
        )))
  
  (defun proc-left (array p)
    (when (< (+ 1 (* 2 p)) (length array))
      (concat (number-to-string (elt array p)) " -- " (number-to-string (elt array (+ 1 (* 2 p)))) "\n")))
          
  (defun proc-right (array p)
    (when (< (+ 2 (* 2 p)) (length array))
      (concat (number-to-string (elt array p)) " -- " (number-to-string (elt array (+ 2 (* 2 p)))) "\n")))

 

求一个结点的左、右结点使用下面的公式就能得到:

leftnode=node*2+1

rightnode=node*2+2

 

要转换某个数组时,就使用:(complete-binary-tree-to-dot-script [1 2 3 4 5]) 来进行转换。将得到的结果保存到一个文件,然后再用 dot 编译成 png 就搞定了!

 

dot  -Tpng tree.dot > tree.png

 

 

有一个实例来辅助分析话会更方便,这里使用的实例是:编程找出文件中符合正则表达式 "alpha[alpha|digit]*" 和 "digit+" 的字符串。alpha 就是字母啦:[a-zA-Z];digit就是数字:[0-9]。

先画出DFA:

在上图中,状态只有三个(结束状态可以省略):开始状态、单词状态和数字状态。

接下来要用两种不同的方法来实现这个DFA,第一种是传统的 while&switch 大法,第二种是现在流行的设计模式中的状态模式。

为了方便比较,先抽象出一个名为Parser的接口,它提供了一个名为 parse 的方法,传统状态机状态机模式通过实现这个方法来完成对正则表达式的识别。传统状态机实现的类名叫ClassicalMachine,状态机模式的类名则叫PatternMachine。

Parser接口的定义: 

public interface Parser {
  void parse() throws Exception ;
}

ClassicalMachine 类的实现非常简单,它在 parse() 方法里就完成了干完了一切:

public class ClassicalMachine implements Parser {
    private BufferedReader mFin;
    private String mToken;
	
    public ClassicalMachine( BufferedReader fin ) {
        mFin = fin;
    }
	
    private enum STATUS {START, IS_KEYWORD, IS_NUMBER};
    STATUS mStatus = STATUS.START;

    @Override
    public void parse() throws Exception {
        mToken = "";
        while (true) {
            int ch = mFin.read();
            if (-1 == ch)	break;
            char c = (char)ch;

            switch (mStatus) {
            case START:
                if (Character.isLetter(c)) {
                    mToken += c;
                    mStatus = STATUS.IS_KEYWORD;
                }
                else if (Character.isDigit(c)) {
                    mToken += c;
                    mStatus = STATUS.IS_NUMBER;
                }
                break;

            case IS_KEYWORD:
                if (Character.isLetterOrDigit(c)) {
                    mToken += c;
                }
                else {
                    mStatus = STATUS.START;
                    System.out.println("keyword: " + mToken);
                    mToken = "";
                }
                break;

            case IS_NUMBER:
                if (Character.isDigit(c)) {
                    mToken += c;
                }
                else {
                    mStatus = STATUS.START;
                    System.out.println("number: " + mToken);
                    mToken = "";
                }
                break;
            }
        }
    }
	
}

 注意上面有一堆 case xxx: 和 if(xxx),如果DFA中有更多的状态和动作的话,case xxx: 会更多。

接下来实现状态模式类。从DFA图可以看出需要实现的动作只有三个,这三个动作分别在碰到字母、数字和其它字符时触发,因此可以定义状态抽象类如下:

abstract class State {
    public abstract void isAlpha(char c);
    public abstract void isDigit(char c);
    public abstract void isOther(char c);
}

为了方便判断字符是数字还是字母,再加上一个函数dispatch(),于是State类最终是这样:

abstract class State {
    public abstract void isAlpha(char c);
    public abstract void isDigit(char c);
    public abstract void isOther(char c);
    public void dispatch(char c) {
        if (Character.isLetter(c)) {
            isAlpha(c);
        }
        else if (Character.isDigit(c)) {
            isDigit(c);
        }
        else {
            isOther(c);
        }
    }
}

 再看看上面的DFA图,发现状态只有三个,因此接下来从 State 派生出三个类对应这三个状态: 

class StartState extends State {
    public void isAlpha(char c) {
        setState( mKeywordState );
        mToken += c;
    }
    public void isDigit(char c) {
        setState( mNumberState );
        mToken += c;
    }
    public void isOther(char c) {
    }
}
	
class KeywordState extends State {
    public void isAlpha(char c) {
        mToken += c;
    }
    public void isDigit(char c) {
        mToken += c;
    }
    public void isOther(char c) {
        setState( mStartState );
        System.out.println("Keyword: " + mToken);
        mToken = "";
    }
}
	
class NumberState extends State {
    public void isAlpha(char c) {
        setState( mStartState );
        System.out.println("Number: " + mToken);
        mToken = "";
    }
    public void isDigit(char c) {
        mToken += c;
    }
    public void isOther(char c) {
        setState( mStartState );
        System.out.println("Number: " + mToken);
        mToken = "";
    }
}

 万事具备,只欠东风了,剩下的只是将字符流作为燃料,来驱动状态机了:

public void parse() throws Exception {
    while (true) {
        int ch = mFin.read();
        if (-1 == ch) break;
        char c = (char)ch;
        mState.dispatch( c );
			
    }
}

 


上面啰啰嗦嗦写了一堆代码,目的就是要对比传统状态机的实现方式和状态模式的区别。传统的实现方式是使用一大块 if&switch 代码,比如说lua的lex;当然也可以对这段铁板代码进行拆分,python的lex就是这么干的,但这样做仅仅只是将那些头痛的switch&if分散到了其它的函数而已,switch&if 和数量并没有减少。更多的条件判断语句会导致更复杂的逻辑,因此要让逻辑变得更简单, 得减少这些判断语句才行---状态模式办到了,它干掉了至少一半的判断语句。它是怎么做到的?

状态机的特点之一:状态是在运行时确定的,这刚好可以通过多态来实现。多态的特点:在运行时对对象进行动态绑定,绑定是由编译器或运行环境来完成的,无需手工参与,因此也可以说是现代越来越强大的编译器or运行环境干掉了switch&if。

附完整的代码:

ClassicalMachine.java:

package bsg;
import java.io.BufferedReader;
import java.io.IOException;


import bsg.Main.Parser;

import com.sun.tools.hat.internal.parser.Reader;


public class ClassicalMachine implements Parser {
    private BufferedReader mFin;
    private String mToken;
	
    public ClassicalMachine( BufferedReader fin ) {
        mFin = fin;
    }
	
    private enum STATUS {START, IS_KEYWORD, IS_NUMBER};
    STATUS mStatus = STATUS.START;

    @Override
    public void parse() throws Exception {
        mToken = "";
        while (true) {
            int ch = mFin.read();
            if (-1 == ch)	break;
            char c = (char)ch;

            switch (mStatus) {
            case START:
                if (Character.isLetter(c)) {
                    mToken += c;
                    mStatus = STATUS.IS_KEYWORD;
                }
                else if (Character.isDigit(c)) {
                    mToken += c;
                    mStatus = STATUS.IS_NUMBER;
                }
                break;

            case IS_KEYWORD:
                if (Character.isLetterOrDigit(c)) {
                    mToken += c;
                }
                else {
                    mStatus = STATUS.START;
                    System.out.println("keyword: " + mToken);
                    mToken = "";
                }
                break;

            case IS_NUMBER:
                if (Character.isDigit(c)) {
                    mToken += c;
                }
                else {
                    mStatus = STATUS.START;
                    System.out.println("number: " + mToken);
                    mToken = "";
                }
                break;
            }
        }
    }
	
}



public class ClassicalMachine implements Parser {
    private BufferedReader mFin;
    private String mToken;
	
    public ClassicalMachine( BufferedReader fin ) {
        mFin = fin;
    }
	
    private enum STATUS {START, IS_KEYWORD, IS_NUMBER};
    STATUS mStatus = STATUS.START;

    @Override
    public void parse() throws Exception {
        mToken = "";
        while (true) {
            int ch = mFin.read();
            if (-1 == ch)	break;
            char c = (char)ch;

            switch (mStatus) {
            case START:
                if (Character.isLetter(c)) {
                    mToken += c;
                    mStatus = STATUS.IS_KEYWORD;
                }
                else if (Character.isDigit(c)) {
                    mToken += c;
                    mStatus = STATUS.IS_NUMBER;
                }
                break;

            case IS_KEYWORD:
                if (Character.isLetterOrDigit(c)) {
                    mToken += c;
                }
                else {
                    mStatus = STATUS.START;
                    System.out.println("keyword: " + mToken);
                    mToken = "";
                }
                break;

            case IS_NUMBER:
                if (Character.isDigit(c)) {
                    mToken += c;
                }
                else {
                    mStatus = STATUS.START;
                    System.out.println("number: " + mToken);
                    mToken = "";
                }
                break;
            }
        }
    }
	
}


abstract class State {
    public abstract void isAlpha(char c);
    public abstract void isDigit(char c);
    public abstract void isOther(char c);
    public void dispatch(char c) {
        if (Character.isLetter(c)) {
            isAlpha(c);
        }
        else if (Character.isDigit(c)) {
            isDigit(c);
        }
        else {
            isOther(c);
        }
    }
}


class StartState extends State {
    public void isAlpha(char c) {
        setState( mKeywordState );
        mToken += c;
    }
    public void isDigit(char c) {
        setState( mNumberState );
        mToken += c;
    }
    public void isOther(char c) {
    }
}
	
class KeywordState extends State {
    public void isAlpha(char c) {
        mToken += c;
    }
    public void isDigit(char c) {
        mToken += c;
    }
    public void isOther(char c) {
        setState( mStartState );
        System.out.println("Keyword: " + mToken);
        mToken = "";
    }
}
	
class NumberState extends State {
    public void isAlpha(char c) {
        setState( mStartState );
        System.out.println("Number: " + mToken);
        mToken = "";
    }
    public void isDigit(char c) {
        mToken += c;
    }
    public void isOther(char c) {
        setState( mStartState );
        System.out.println("Number: " + mToken);
        mToken = "";
    }
}


public void parse() throws Exception {
    while (true) {
        int ch = mFin.read();
        if (-1 == ch) break;
        char c = (char)ch;
        mState.dispatch( c );
			
    }
}

 PatternMachine.java

package bsg;

import java.io.BufferedReader;

import bsg.Main.Parser;

public class PatternMachine implements Parser {
    private String mToken = "";
    private BufferedReader mFin;
    public PatternMachine( BufferedReader fin ) {
        mFin = fin;
    }
	
    private StartState mStartState = new StartState();
    private KeywordState mKeywordState = new KeywordState();
    private NumberState mNumberState = new NumberState();
    //
    private State mState = mStartState;
    public State getState() {
        return mState;
    }
    public void setState(State state) {
        mState = state;
    }

    abstract class State {
        public abstract void isAlpha(char c);
        public abstract void isDigit(char c);
        public abstract void isOther(char c);
        public void dispatch(char c) {
            if (Character.isLetter(c)) {
                isAlpha(c);
            }
            else if (Character.isDigit(c)) {
                isDigit(c);
            }
            else {
                isOther(c);
            }
        }
    }
	
    class StartState extends State {
        public void isAlpha(char c) {
            setState( mKeywordState );
            mToken += c;
        }
        public void isDigit(char c) {
            setState( mNumberState );
            mToken += c;
        }
        public void isOther(char c) {
        }
    }
	
    class KeywordState extends State {
        public void isAlpha(char c) {
            mToken += c;
        }
        public void isDigit(char c) {
            mToken += c;
        }
        public void isOther(char c) {
            setState( mStartState );
            System.out.println("Keyword: " + mToken);
            mToken = "";
        }
    }
	
    class NumberState extends State {
        public void isAlpha(char c) {
            setState( mStartState );
            System.out.println("Number: " + mToken);
            mToken = "";
        }
        public void isDigit(char c) {
            mToken += c;
        }
        public void isOther(char c) {
            setState( mStartState );
            System.out.println("Number: " + mToken);
            mToken = "";
        }
    }
	

    @Override
    public void parse() throws Exception {
        while (true) {
            int ch = mFin.read();
            if (-1 == ch) break;
            char c = (char)ch;
            mState.dispatch( c );
			
        }
    }

}


package bsg;
import java.io.BufferedReader;
import java.io.IOException;


import bsg.Main.Parser;

import com.sun.tools.hat.internal.parser.Reader;


public class ClassicalMachine implements Parser {
    private BufferedReader mFin;
    private String mToken;
	
    public ClassicalMachine( BufferedReader fin ) {
        mFin = fin;
    }
	
    private enum STATUS {START, IS_KEYWORD, IS_NUMBER};
    STATUS mStatus = STATUS.START;

    @Override
    public void parse() throws Exception {
        mToken = "";
        while (true) {
            int ch = mFin.read();
            if (-1 == ch)	break;
            char c = (char)ch;

            switch (mStatus) {
            case START:
                if (Character.isLetter(c)) {
                    mToken += c;
                    mStatus = STATUS.IS_KEYWORD;
                }
                else if (Character.isDigit(c)) {
                    mToken += c;
                    mStatus = STATUS.IS_NUMBER;
                }
                break;

            case IS_KEYWORD:
                if (Character.isLetterOrDigit(c)) {
                    mToken += c;
                }
                else {
                    mStatus = STATUS.START;
                    System.out.println("keyword: " + mToken);
                    mToken = "";
                }
                break;

            case IS_NUMBER:
                if (Character.isDigit(c)) {
                    mToken += c;
                }
                else {
                    mStatus = STATUS.START;
                    System.out.println("number: " + mToken);
                    mToken = "";
                }
                break;
            }
        }
    }
	
}



public class ClassicalMachine implements Parser {
    private BufferedReader mFin;
    private String mToken;
	
    public ClassicalMachine( BufferedReader fin ) {
        mFin = fin;
    }
	
    private enum STATUS {START, IS_KEYWORD, IS_NUMBER};
    STATUS mStatus = STATUS.START;

    @Override
    public void parse() throws Exception {
        mToken = "";
        while (true) {
            int ch = mFin.read();
            if (-1 == ch)	break;
            char c = (char)ch;

            switch (mStatus) {
            case START:
                if (Character.isLetter(c)) {
                    mToken += c;
                    mStatus = STATUS.IS_KEYWORD;
                }
                else if (Character.isDigit(c)) {
                    mToken += c;
                    mStatus = STATUS.IS_NUMBER;
                }
                break;

            case IS_KEYWORD:
                if (Character.isLetterOrDigit(c)) {
                    mToken += c;
                }
                else {
                    mStatus = STATUS.START;
                    System.out.println("keyword: " + mToken);
                    mToken = "";
                }
                break;

            case IS_NUMBER:
                if (Character.isDigit(c)) {
                    mToken += c;
                }
                else {
                    mStatus = STATUS.START;
                    System.out.println("number: " + mToken);
                    mToken = "";
                }
                break;
            }
        }
    }
	
}


abstract class State {
    public abstract void isAlpha(char c);
    public abstract void isDigit(char c);
    public abstract void isOther(char c);
    public void dispatch(char c) {
        if (Character.isLetter(c)) {
            isAlpha(c);
        }
        else if (Character.isDigit(c)) {
            isDigit(c);
        }
        else {
            isOther(c);
        }
    }
}


class StartState extends State {
    public void isAlpha(char c) {
        setState( mKeywordState );
        mToken += c;
    }
    public void isDigit(char c) {
        setState( mNumberState );
        mToken += c;
    }
    public void isOther(char c) {
    }
}
	
class KeywordState extends State {
    public void isAlpha(char c) {
        mToken += c;
    }
    public void isDigit(char c) {
        mToken += c;
    }
    public void isOther(char c) {
        setState( mStartState );
        System.out.println("Keyword: " + mToken);
        mToken = "";
    }
}
	
class NumberState extends State {
    public void isAlpha(char c) {
        setState( mStartState );
        System.out.println("Number: " + mToken);
        mToken = "";
    }
    public void isDigit(char c) {
        mToken += c;
    }
    public void isOther(char c) {
        setState( mStartState );
        System.out.println("Number: " + mToken);
        mToken = "";
    }
}


public void parse() throws Exception {
    while (true) {
        int ch = mFin.read();
        if (-1 == ch) break;
        char c = (char)ch;
        mState.dispatch( c );
			
    }
}

Main.java 

package bsg;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;


public class Main {
    public interface Parser {
        void parse() throws Exception ;
    }
	
    public static void main(String[] args) {
        if (0 == args.length) return;

        BufferedReader fin = null;
        try {
            fin = new BufferedReader( new FileReader(args[1] ) );
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
		
        Parser parser = null;
        if (args[0].equals("cla")) {
            parser = new ClassicalMachine( fin );
        } else if (args[0].equals("pat")){
            parser = new PatternMachine( fin );
        }
		
        long beg = System.currentTimeMillis();
        try {
            parser.parse();
            fin.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        long end = System.currentTimeMillis() - beg;
        System.out.println("" + end);
    }
}


package bsg;

import java.io.BufferedReader;

import bsg.Main.Parser;

public class PatternMachine implements Parser {
    private String mToken = "";
    private BufferedReader mFin;
    public PatternMachine( BufferedReader fin ) {
        mFin = fin;
    }
	
    private StartState mStartState = new StartState();
    private KeywordState mKeywordState = new KeywordState();
    private NumberState mNumberState = new NumberState();
    //
    private State mState = mStartState;
    public State getState() {
        return mState;
    }
    public void setState(State state) {
        mState = state;
    }

    abstract class State {
        public abstract void isAlpha(char c);
        public abstract void isDigit(char c);
        public abstract void isOther(char c);
        public void dispatch(char c) {
            if (Character.isLetter(c)) {
                isAlpha(c);
            }
            else if (Character.isDigit(c)) {
                isDigit(c);
            }
            else {
                isOther(c);
            }
        }
    }
	
    class StartState extends State {
        public void isAlpha(char c) {
            setState( mKeywordState );
            mToken += c;
        }
        public void isDigit(char c) {
            setState( mNumberState );
            mToken += c;
        }
        public void isOther(char c) {
        }
    }
	
    class KeywordState extends State {
        public void isAlpha(char c) {
            mToken += c;
        }
        public void isDigit(char c) {
            mToken += c;
        }
        public void isOther(char c) {
            setState( mStartState );
            System.out.println("Keyword: " + mToken);
            mToken = "";
        }
    }
	
    class NumberState extends State {
        public void isAlpha(char c) {
            setState( mStartState );
            System.out.println("Number: " + mToken);
            mToken = "";
        }
        public void isDigit(char c) {
            mToken += c;
        }
        public void isOther(char c) {
            setState( mStartState );
            System.out.println("Number: " + mToken);
            mToken = "";
        }
    }
	

    @Override
    public void parse() throws Exception {
        while (true) {
            int ch = mFin.read();
            if (-1 == ch) break;
            char c = (char)ch;
            mState.dispatch( c );
			
        }
    }

}


package bsg;
import java.io.BufferedReader;
import java.io.IOException;


import bsg.Main.Parser;

import com.sun.tools.hat.internal.parser.Reader;


public class ClassicalMachine implements Parser {
    private BufferedReader mFin;
    private String mToken;
	
    public ClassicalMachine( BufferedReader fin ) {
        mFin = fin;
    }
	
    private enum STATUS {START, IS_KEYWORD, IS_NUMBER};
    STATUS mStatus = STATUS.START;

    @Override
    public void parse() throws Exception {
        mToken = "";
        while (true) {
            int ch = mFin.read();
            if (-1 == ch)	break;
            char c = (char)ch;

            switch (mStatus) {
            case START:
                if (Character.isLetter(c)) {
                    mToken += c;
                    mStatus = STATUS.IS_KEYWORD;
                }
                else if (Character.isDigit(c)) {
                    mToken += c;
                    mStatus = STATUS.IS_NUMBER;
                }
                break;

            case IS_KEYWORD:
                if (Character.isLetterOrDigit(c)) {
                    mToken += c;
                }
                else {
                    mStatus = STATUS.START;
                    System.out.println("keyword: " + mToken);
                    mToken = "";
                }
                break;

            case IS_NUMBER:
                if (Character.isDigit(c)) {
                    mToken += c;
                }
                else {
                    mStatus = STATUS.START;
                    System.out.println("number: " + mToken);
                    mToken = "";
                }
                break;
            }
        }
    }
	
}



public class ClassicalMachine implements Parser {
    private BufferedReader mFin;
    private String mToken;
	
    public ClassicalMachine( BufferedReader fin ) {
        mFin = fin;
    }
	
    private enum STATUS {START, IS_KEYWORD, IS_NUMBER};
    STATUS mStatus = STATUS.START;

    @Override
    public void parse() throws Exception {
        mToken = "";
        while (true) {
            int ch = mFin.read();
            if (-1 == ch)	break;
            char c = (char)ch;

            switch (mStatus) {
            case START:
                if (Character.isLetter(c)) {
                    mToken += c;
                    mStatus = STATUS.IS_KEYWORD;
                }
                else if (Character.isDigit(c)) {
                    mToken += c;
                    mStatus = STATUS.IS_NUMBER;
                }
                break;

            case IS_KEYWORD:
                if (Character.isLetterOrDigit(c)) {
                    mToken += c;
                }
                else {
                    mStatus = STATUS.START;
                    System.out.println("keyword: " + mToken);
                    mToken = "";
                }
                break;

            case IS_NUMBER:
                if (Character.isDigit(c)) {
                    mToken += c;
                }
                else {
                    mStatus = STATUS.START;
                    System.out.println("number: " + mToken);
                    mToken = "";
                }
                break;
            }
        }
    }
	
}


abstract class State {
    public abstract void isAlpha(char c);
    public abstract void isDigit(char c);
    public abstract void isOther(char c);
    public void dispatch(char c) {
        if (Character.isLetter(c)) {
            isAlpha(c);
        }
        else if (Character.isDigit(c)) {
            isDigit(c);
        }
        else {
            isOther(c);
        }
    }
}


class StartState extends State {
    public void isAlpha(char c) {
        setState( mKeywordState );
        mToken += c;
    }
    public void isDigit(char c) {
        setState( mNumberState );
        mToken += c;
    }
    public void isOther(char c) {
    }
}
	
class KeywordState extends State {
    public void isAlpha(char c) {
        mToken += c;
    }
    public void isDigit(char c) {
        mToken += c;
    }
    public void isOther(char c) {
        setState( mStartState );
        System.out.println("Keyword: " + mToken);
        mToken = "";
    }
}
	
class NumberState extends State {
    public void isAlpha(char c) {
        setState( mStartState );
        System.out.println("Number: " + mToken);
        mToken = "";
    }
    public void isDigit(char c) {
        mToken += c;
    }
    public void isOther(char c) {
        setState( mStartState );
        System.out.println("Number: " + mToken);
        mToken = "";
    }
}


public void parse() throws Exception {
    while (true) {
        int ch = mFin.read();
        if (-1 == ch) break;
        char c = (char)ch;
        mState.dispatch( c );
			
    }
}

 

 

手机话费的新用途

2010年7月27日 18:38

(消息来源: www.geek.com)

上周五 (ADB)Android Developers Blog 宣布将提供除信用卡外的另一种付费方式,但具体是什么,ADB 却没有说明,倒是有人通过分析新旧 DDA(Developer Distribution Agreement) 得到了一些信息。
DDA 最新版本做了如下修改:

  • In Section 13.1, “authorized carriers” have been added as an indemnified party.
  • Section 13.2 is new in its entirety, covering indemnity for payment processors for claims related to tax accrual.

因此可以猜到,google 准备向用户提供通过手机话费来购买应用程序的服务。 

目前只有 T-Mobile 和 google 有这方面的合作关系。