2013年4月29日月曜日

java のエラーと例外

ざっと java の概要を拾い読みして、特に java のエラーと例外について以下のような疑問をもった。
  • 例外が想定外のエラーなの?
  • エラーと例外を全部catchしないといけないの?
  • catchした例外情報を最上位まで返せないの?
  • catchするけど最上位までスタックトレース情報を返せないの?
  • エラーが起きたときって次行にすすまないの?
  1. 例外が想定外のエラーなのか?
  2. 例外っていうと想定外の事態で、エラーっていいうと一応想定内な事態な印象を持つけれどOOPSでは逆なんですね。例外は通常起こりえるエラーを指し、エラーは致命的なエラーを指しているのですね。で、例外処理で相手にしているのは通常起こりえるエラーの方で、致命的なエラーは java 本体のエラー補足にまかせて異常終了というのが大筋なんですね。

  3. エラーと例外を全部catchしないといけないの
  4. 例外の説明では例外の補足方法について説明されるけれど、返す可能性のある例外は全部 catch しないといけないのか、それとも、必要な例外のみを補足すればよいのかよくわからない場合が多い。catch、throw、throws は密接に関係しているので最後に全部セットにしたエラー処理のサンプルのようなものが欲しいと思う。結論からいえば、catch で全部の例外を補足する必要はなく、返す可能性のあるエラーは全て throws に列挙すれば上位の関数に例外がそのまま伝わるらしい。

  5. catchした例外情報を最上位まで返せないの
  6. 一旦キャッチしたエラーは、throw で自分で例外を上位に投げなければそこでそのエラーは無くなってしまう。一旦 catch して何か処理施した後、上位にエラーを解したい場合は「throw エラー」として上位関数に自らエラーは投げなければならない。もちろん、キャッチしなかったエラーは、throws に定義した通り自動的に上位関数に引き継がれる。

  7. catchするけど最上位までスタックトレース情報を返せないの
  8. catch したエラー情報に含まれれ、e.printStackTrace()で出力できるスタックトレース情報は、catch してただ throw するだけだとそれまでのスタックトレース情報が無くなってしまう。それまでのスタックトーレス情報を引き継ぎながらthrow するには、catch した例外情報 e を throw のパラメータとして上位に投げると最上位までスタックトレース情報が引き継がれる。

  9. 例外時のリソースの解放って終了すれば解放されるの
  10. 例外時にリソースの解放処理を上手に仕組ないとリソースの使い切りに繋がりますという説明をよく見かけるけど、常駐プロセスとして動く場合の注意点だという注意書きが欲しい気がする。オブジェクト指向のクラスとは、再利用性をよく考慮された関数群のようなものだから、再利用を考えればリソースの使いきりの可能性があるコードは確かによくないけれど、利用機会の限られたツールなどを作る場合には絶対に守らなければならないルールではないと思う。

  11. エラーが起きたときって次行にすすまないの
  12. 致命的なエラーが起きたときの処理内容を確かめるのに、致命的なエラーの発生方法がわからないと実験のしようがないので、正しい処理コードの記述方法もわかりません。たとえば、リソースの解放処理とか、次行に進まないための考慮とか必要ないのかなど思い悩みます。そんな時に便利な「int[] arr = new int[0x7fffffff]」である。これでエラー「java.lang.OutOfMemoryError:」が発生させられる。通常はエラーの場合は、try などせず致命的エラーとして java のお世話になれば良いのだと思う。
    import java.io.*;
    public class test03 {
      public static void main(String[] args)
      {
        try {
           int[] arr = new int[0x7fffffff];
           System.out.println("次の処理だ");
        }
        catch(OutOfMemoryError e) {
           System.out.println("メモリエラーだ");
        }
        finally {
           System.out.println("うーーむ");
        }
      }
    }
    
    $ java test03
    メモリエラーだ
    うーーむ
    

強制断捨離(ubuntu13.04)の季節

うかうかとうららかな日々を送っていたら、もう ubuntu13.04 の季節である。 ubuntu マガジンの 12.10 の設定特集の内容にもロクに目を通していないのに困ったものである。暫く Mint14 shinamon に浮気していたが、あえてここは ubuntu への強制送還とあいなった。

使ってみての第一印象は、謳い文句どおり画面の描画が若干はやくなっているように思われた。ただ、いつもの強制断捨離で行う設定の際にいくつかの不具合にであった。(脳バグがほとんどだが)

  • samba の設定画面の立ち上げ方法を忘れた(脳バグ)
  • chrome がインストールできない。(chromiumはOK)
  • chrom のリモートデスクトップのマスス操作が聞かない(chrome待ち?)
  • wine で通常の方法だと使えなくなってしまったアプリがでた
  • skype の設定も記録してなかったので変なものを入れてしまった(脳バグ)
  • wine 上のアプリのランチャー登録方法がわからい(脳バグかさえ不明)
  • lisp と slime のインストールも忘れてたので記載しておこう

  1.  固定IPアドレスの設定

  2.  DropBox と chrome のインストール

    普段の勉強ネタや設定ネタは $HOME/work -> $HOME/dropbox/work にリンクして、強制断捨離をしても失わないように配慮している。ブックマークも、hatena のブックマークを定期的に chrome のブックマークに設定している。これは、超絶必要なブックマークを携帯や他のパソコンでも共有したいためである。しかし、chrome を google のサイトよりダウンロードしても展開で失敗してしまった。仕方がないので chromium を導入してブックマーク共有などは概ね満足であるが、リモートデスクトップはキー入力とマウス入力が伝わらなかった。本家が対応されるのをじっと待とう。

  3. Mozc のインストール

    $ sudo apt-get install ibus-mozc mozc-server mozc-utils-gui
    

  4. Samba のインストール

    $ sudo system-config-samba 
    

  5. DDNS の定期通知の設定

    こちらを参照

  6. apache のインストール

    $ sudo apt-get install apache2
    

  7. mysql のインストール

    naoki@naoki-iMac:~$ mysql -u root -p
    Enter password: 
    mysql> CREATE DATABASE wordpress CHARACTER SET utf8;
    Query OK, 1 row affected (0.00 sec)
    
    mysql> GRANT ALL PRIVILEGES ON wordpress.*  
        -> TO naoki@localhost IDENTIFIED BY 'naoki';
    Query OK, 0 rows affected (0.00 sec)
    
    mysql> FLUSH PRIVILEGES;
    Query OK, 0 rows affected (0.00 sec)
    

  8. php と wordpress のインストール

    $ sudo apt-get install php5 php5-mysql
    $ unziip wordpress-3.4.2-ja.zip
    $ chown -R www-data:www-data wordpress
    

  9. wine と各種アプリのインストール

    ubuntu12.10 と wine1.4 の組み合わせで動いていたアプリの幾つかが動かなくなったため、試しに wine 1.5と ps を導入してみたがこれも正常にインストールできるものの2回目以降起動が出来なくなった。試しに indesign を導入したあと ps を導入してみると問題が解消した。なんか、wine 上のアプリは、wine のバージョンなのか、os バージョンなのか、アプリ間の相性なのかまったくわからない。動かしたいソフトが動いたらラッキーという姿勢が大事かもしれない。

  10. virtualbox のインストール

    インストール中に usb にアクセスできないので、vboxuser グループに利用ユーザを追加しろというメッセージがでるが、groupadd なんかしたあほな記憶を思い出した。(こちらを参照)

  11. skype のインストール

    $ sudo apt-get update
    $ sudo apt-get install skype
    

  12. emacs のインストール

    $ sudo apt-get install emacs24
    

  13. eclipse

    emacs と eclipse はドーモ世界が違いすぎるのだけれど、eclipse も強要される場合も多いので導入して置かないと。 まずは、java のインストール
    $ sudo apt-get install openjdk-7-jre
    
    ここよりeclipseをダウンロードして$HOME/eclipse に展開(Eclipse IDE for Java Developers)
    $ cd $HOME
    $ tar xvfz ダウンロード/eclipse-java-juno-SR2-linux-gtk-x86_64.tar.gz
    
    ここよりpleiadesの日本語パッケージをダウンロードして展開後インストール
    $ cd $HOME/eclipse
    $ unzip ../ダウンロード/pleiades_1.4.0.zip
    
    eclipse.ini に以下の定義を追加(フルパス)
    -javaagent:/home/naoki/eclipse/plugins/jp.sourceforge.mergedoc.pleiades/pleiades.jar
    
    ランチャー登録用の定義ファイル作成
    $ cd $HOME/.local/share/applications
    $ cat < eclipse.desktop
    > [Desktop Entry]
    > Version=1.0
    > Type=Application
    > Terminal=false
    > StartupNotify=true
    > Icon=/home/naoki/eclipse/icon.xpm
    > Name=Eclipse Juno
    > Comment=Eclipse Juno
    > Exec=/home/naoki/eclipse/eclipse
    > Categories=Development;
    > EOF
    
    作成した定義ファイルのプロパティファイルの実行権限を付与
    あとは実行中にランチャー登録して登録完了

  14. 言語系(common lisp と slime)

    $ sudo apt-get install clisp
    $ sudo apt-get install slime
    

  15. 言語系(ruby )

    $ sudo apt-get install ruby
    

2013年4月23日火曜日

clisp の cadadr ってなんだ?

「Land of Lisp」という本を買った。3章の最後にあっさり出てくる cadadr は car と cdr の組み合わせだというのは解るのだが、どのように組み合わされたものなのか解読に苦労してしまった。c*r の * の a は car の略称、d は cdr の略称なのは想像がついたのだが・・・ そこで少しググってみて納得がいきました。頭悪いなと実感!

 (defun caar (x) (car (car x)))
 (defun cadr (x) (car (cdr x)))
 (defun cdar (x) (cdr (car x)))
 (defun cddr (x) (cdr (cdr x)))
 (defun caaar (x) (car (car (car x))))
 (defun caadr (x) (car (car (cdr x))))
 (defun cadar (x) (car (cdr (car x))))
 (defun caddr (x) (car (cdr (cdr x))))
 (defun cdaar (x) (cdr (car (car x))))
 (defun cdadr (x) (cdr (car (cdr x))))
 (defun cddar (x) (cdr (cdr (car x))))
 (defun cdddr (x) (cdr (cdr (cdr x))))
 (defun caaaar (x) (car (car (car (car x)))))
 (defun caaadr (x) (car (car (car (cdr x)))))
 (defun caadar (x) (car (car (cdr (car x)))))
 (defun caaddr (x) (car (car (cdr (cdr x)))))
 (defun cadaar (x) (car (cdr (car (car x)))))
 (defun cadadr (x) (car (cdr (car (cdr x)))))
 (defun caddar (x) (car (cdr (cdr (car x)))))
 (defun cadddr (x) (car (cdr (cdr (cdr x)))))
 (defun cdaaar (x) (cdr (car (car (car x)))))
 (defun cdaadr (x) (cdr (car (car (cdr x)))))
 (defun cdadar (x) (cdr (car (cdr (car x)))))
 (defun cdaddr (x) (cdr (car (cdr (cdr x)))))
 (defun cddaar (x) (cdr (cdr (car (car x)))))
 (defun cddadr (x) (cdr (cdr (car (cdr x)))))
 (defun cdddar (x) (cdr (cdr (cdr (car x)))))
 (defun cddddr (x) (cdr (cdr (cdr (cdr x)))))

2013年4月22日月曜日

java でファイルダンプ(クラス風味+)

今回は、16進数の出力の前後に文字列を指定できるクラス(dhex)とキャラクタの前後に文字列を指定できるクラス(dchr)に分けて、ダンプのフォーマットを知っているクラス(dump)でdhexとdchrを使ってダンプするプログラムにしてみた。こうしたことで dump2 の新しいレイアウトダンプフォーマットを書く気力が沸いたので、そう言う意味の再利用性の向上があったと思える。クラスにするのであれば再利用性のあるクラスか、組み立て方をしっているクラスにわけるべきなのだろう。dhex、chex は、最近気になってる clisp の影響で再帰処理にしてみた。さらに、結城先生のデザインパターンのアダプタなどを模してみるとよいのかもしれないが、この内容のプログラムではその有りがたさがまだわからない。
import java.io.*;
import java.util.*;

class dhex {
    String fpad = "";
    String lpad = "";

    public dhex(String f, String l) {
        fpad = f;  
        lpad = l;  
    }

    public String hex(byte buf[],int no,int size) {
        no--;
        if (no>=0) {
            return(this.hex(buf,no,size) 
                 + (no > size-1 ? String.format("%s%2s%s",fpad,"",lpad) 
                       : String.format("%s%02x%s",fpad,buf[no],lpad)));
        }
        return("");
    }
}

class dchr {
    String fpad = "";
    String lpad = "";

    public dchr(String f, String l) {
        fpad = f;  
        lpad = l;  
    }

    public byte trpchr(byte c) {
        if ((0x00<=c && c<=0x1f) || 0x7f<=(c&0xff)) {
            return('.');
        }
        return(c);
    }

    public String chr(byte buf[],int no,int size) {
        no--;
        if (no>=0) {
            return(this.chr(buf,no,size) 
                 + (no > size-1 ? String.format("%s%s%s",fpad," ",lpad) 
                       : String.format("%s%c%s",fpad,trpchr(buf[no]),lpad)));
        }
        return("");
    }
}

class Dump {
    String fname;
    int    max;

    public Dump(String name) {
        fname = name;
        max   = 16;
    }

    public String fhalf(String line) {
        return(line.substring(0,3*(max/2)));
    }

    public String lhalf(String line) {
        return(line.substring(3*(max/2),3*max));
    }

    public void normalp() throws FileNotFoundException,IOException {
        byte   buf[] = new byte[16];
        int    size,cnt = 0;
        FileInputStream ifs = null;

        try {
            ifs = new FileInputStream(fname);
            dhex h = new dhex(""," ");
            dchr c = new dchr("","");

            while(ifs.available()>0) {
                size = ifs.read(buf);

                System.out.print(String.format("%08x : ",cnt*16));
                String line = h.hex(buf,16,size);

                System.out.print(fhalf(line));
                System.out.print("- ");
                System.out.print(lhalf(line));
                System.out.print("|");
                System.out.print(c.chr(buf,16,size));
                System.out.printf("|\n");
                cnt++;
            }
        }
        finally {
            if (ifs != null) {
                ifs.close(); 
            }
        }
    }
}

class Dump2 extends Dump {
    public Dump2(String name) {
        super(name);
    }

    public void normalp() throws FileNotFoundException,IOException {
        byte   buf[] = new byte[16];
        int    size,cnt = 0;
        FileInputStream ifs = null;

        try {
            ifs = new FileInputStream(fname);
            dhex h = new dhex(""," ");
            dchr c = new dchr(" "," ");

            while(ifs.available()>0) {
                size = ifs.read(buf);

                System.out.print(String.format("%08x : ",cnt*16));
                System.out.print(h.hex(buf,16,size));
                System.out.printf("\n");
                System.out.print(String.format("         : "));
                System.out.print(c.chr(buf,16,size));
                System.out.printf("\n");
                cnt++;
            }
        }
        finally {
            if (ifs != null) {
                ifs.close(); 
            }
        }
    }
}

class test05 {
    public static void main(String args[]) {
        Dump d = new Dump(args[0]);
        try {
            d.normalp();
        }
        catch(FileNotFoundException e) {
            System.out.println("ファイルオープンエラー");
        }
        catch(Exception e) {
            System.out.println("異常終了");
            e.printStackTrace();
        }
    }
}

2013年4月16日火曜日

facebook のタブアプリの迷宮

今やすっかり人気の無くなってしまったFBの診断アプリだが、なぜか今更ながら作ってみることにした。FBタブアプリの作り方は多くのサンプルが流れているので、簡単なアプリならば何とかなるだろうと思っていた。

こんな書き出しから始まるのはそれ相応の迷宮に迷い込んだ顛末を記載するからだが、それにしても自分のダメさ加減を毎回さらけ出すわけだから、かなりの自虐好きなのだろう。さらに、このダメさ加減については、ネタ切れという物がないのもまた好都合なのである。

いろいろな方が書いているとおり、「開発者登録→サンプルアプリ配置→SSLサーバー構築→アプリ登録」と駒を進めていくと、開発者登録以外の全てのステージではまりました。はまった順番がこの順番だったわけではなく、サンプルアプリを動かしながら各ステージに原因を求めて延々とさまよったのである。

事の顛末は別にして、アプリって診断アプリとかではなくてグループ上での地図連動型共有データベースみたいな物だったら、小規模グルナビだったり、小規模地理研究グループだったり、色々と使いでありそうな気がするのだが・・・

アプリ登録の失敗

ことの始まりは、「いいね」ボタンの押下の有無の情報を取得するgetSignedRequest()の内容が空であることだった。原因は、FBのアプリ登録画面で「ページタブ」以外の「FBのアプリ」の項目が未入力であったことだった。また、App Domains の入力も「FBのアプリ」で利用しているサーバー名を記入しないとエラーコード 191 というエラーが発生した。いずれも、以下に示すFBの基本設定画面で入力チェックできるはずのものなのにと嘆くのは、責任転嫁好きな私の感想である。また、このgetSignedRequest() の取得元変数 $_REQUESTの中身は php.ini の variables_order、request_order の項目でフォーマット指定できることなど余計な事も学ばさせられた。



SSLサーバーの疑惑

節約の為におれおれSSLサーバーを仕立てたが、上記のgetSignedRequest()が取得できないのは偽SSLのせいなのか区別が出来なかったので、サクラレンタルサーバーを契約してみることにした。結論は正SSLサーバーでも解消しなかったのでおれおれSSLサーバーでも何の問題もなかったわけだが、逃げまどうバンビちゃんはこんなこともしてしまうのである。正規のSSLサーバーを追い求めて検索していると、OpenSSL というフリーの認証書の入手手順もあることを知ったが、独自ドメインと独自メールサーバーが必要なので諦めた次第である。ちなみに、サクラレンタルサーバーを契約したことは後悔していない。OSがFreeBSDで日本語環境の設定も良く解らない状況ながら、20Gもの領域を年5000円で取得できてすこぶる高速なのには気を良くしている。負け惜しみではない。

サンプルアプリの選択

英語が良く読めないことをよいことにFBの開発者ページからPHPのサンプルを適当にコピーして実験用に当てたのだが、タブページ用に利用すべきアプリかどうかの吟味が必要だった。問題は、タブアプリからユーザ認証を呼び出すと認証画面に遷移できずに真っ白な画面になって固まってしまうことである。これの解となる日本語の情報はこちらに見つけたが、難しくて良く解らなかった。だが、そもそもタブページのアプリを起動するユーザは、FB認証したユーザであると仮定してこの問題を無き者することににした。解答らしきページの作者も死にかけたらしいので、命第一である。

FBのアプリ登録が時々おかしくなる

さらに問題の切り分けを難しくしているのが、アプリを登録後に頻繁に修正をしていると、FBのアプリ登録がエラーを返してくるようになることである。一回削除して再度登録し直すか、新しいアプリとして追加登録すると何事もなかったように動き出す。安全な仕様ということで納得することにしよう。

最後に汚いソースだが簡単な診断アプリのソースを記念に貼り付けて終わりとしよう。
  1. 出題定義ファイル
    %cat request.txt
    000:000 ヘビイチゴ
    000:001 ドクイチゴ
    000:002 木イチゴ
    000:IMG ./1.jpg
    001:000 200円
    001:001 400円
    001:002 600円
    001:IMG ./2.jpg
    002:000 ① ヨークシャーテリア
    002:001 ②ゴールデンリトリバー
    002:002 ③フレンチブルドック
    002:IMG ./3.jpg
    END:END 
    
  2. 解凍定義ファイル
    %cat judge.txt
    /000:000/001:000/002:000 パターン1
    /000:000/001:000/002:001 パターン2
    /000:000/001:000/002:002 パターン3
    /000:000/001:001/002:000 パターン4
    /000:000/001:001/002:001 パターン5
    /000:000/001:001/002:002 パターン6
    /000:000/001:002/002:000 パターン7
    /000:000/001:002/002:001 パターン8
    /000:000/001:002/002:002 パターン9
    /000:001/001:000/002:000 パターン10
    /000:001/001:000/002:001 パターン11
    /000:001/001:000/002:002 パターン12
    /000:001/001:001/002:000 パターン13
    /000:001/001:001/002:001 パターン14
    /000:001/001:001/002:002 パターン15
    /000:001/001:002/002:000 パターン16
    /000:001/001:002/002:001 パターン17
    /000:001/001:002/002:002 パターン18
    /000:002/001:000/002:000 パターン19
    /000:002/001:000/002:001 パターン20
    /000:002/001:000/002:002 パターン21
    /000:002/001:001/002:000 パターン22
    /000:002/001:001/002:001 パターン23
    /000:002/001:001/002:002 パターン24
    /000:002/001:002/002:000 パターン25
    /000:002/001:002/002:001 パターン26
    /000:002/001:002/002:002 パターン27
    
  3. ソースコード1
    <?php
      // Remember to copy files from the SDK's src/ directory to a
      // directory in your application on the server, such as php-sdk/
      require_once('facebook.php');
    
      $config = array(
        'appId' => '*******',
        'secret' => '************************',
      );
    
      $facebook = new Facebook($config);
      $user_id = $facebook->getUser();
    
    ?>
    <html>
      <head></head>
      <body>
    
      <?php
        // We have a user ID, so probably a logged in user.
        // If not, we'll get an exception, which we handle below.
        try {
            // 「いいね」の判定
          $signed_request = $facebook->getSignedRequest();
          $like_status = $signed_request['page']['liked'];
          if ($like_status) {
              $par = array(
                'canvas' => 1,
                'fbconnect' => 0,
                'scope' => 'publish_stream,read_friendlists',
                'redirect_uri' => 'http://apps.facebook.com/test-sample-b');
              $fb_login_url = $facebook->getLoginUrl($par);
    
            $user_profile = $facebook->api('/me','GET');
            echo "Name: " . $user_profile['name'];
              include_once('sample.php');
            }
            else {
              echo "<center>";
              echo "いいね押してね";
              echo "</center>";
            }
        } catch(FacebookApiException $e) {
          echo "<center>";
          echo "フェイスブックでログインしてね";
          echo "</center>";
          // If the user is logged out, you can have a 
          // user ID even though the access token is invalid.
          // In this case, we'll get an exception, so we'll
          // just ask the user to login again here.
          $login_url = $facebook->getLoginUrl(); 
    //     echo 'Please <a href="' . $login_url . '">login.</a>';
          error_log($e->getType());
          error_log($e->getMessage());
        }   
      ?>
    
      </body>
    </html>
    
  4. ソースコード2
    <?php
    function endproc($history) {
      // 質問票を連想配列 $LIST に格納
      $lines = file("./judge.txt", FILE_IGNORE_NEW_LINES);
        printf('<p> %s </p>' ,$history);
      foreach ($lines as $line) {
        chop($line);
        list($key,$val) = split("[\t]",$line);
        if ($key === $history) {
            printf('<p> %s </p>' ,$val);
            printf("\n");
            break;
        }
      }
    }
    
    function body1($history) {
      // 選択肢が未選択の場合
      $self   = htmlentities($_SERVER["PHP_SELF"]);
    
      // 質問票を連想配列 $LIST に格納
      $lines = file("./request.txt", FILE_IGNORE_NEW_LINES);
      foreach ($lines as $line) {
        chop($line);
        list($key,$val) = split("[\t]",$line);
        $LIST[$key] = $val;
      }
    
      // 質問項目抽出キーの作成
      list($srh,$dummy) = split("[:]",basename($history));
      if ($srh === "") {
        $srh = "000";
      }
      else {
        $srh = sprintf("%03d",$srh+1);
      }
    
      // 質問画像の貼り付け
      printf('<div>');
      $image = "";
      foreach ($LIST as $key => $val) {
        if(preg_match("/^$srh:IMG/",$key)) {
          $image = sprintf('  <img src="%s" alt="" />',$val);
        }
      }
      if ($image === "") {
        endproc($history);
      }
      else {
        printf("%s\n",$image);
      }
      printf("\n");
      printf("</div>\n");
        
      // リクエストヘッダを作成(form開始)
      if ($image !== "") {
        printf('<div class="sample-down">');
        printf("\n");
        printf('  <form action="'.$self.'" method="GET">');
        printf("\n");
        printf("  <fieldset class=sample-form>\n");
      
        foreach ($LIST as $key => $val) {
          if(preg_match("/^$srh:[0-9]+/",$key)) {
            printf('    <label><input type="radio" ');
            printf('name="ans[]" value="%s"/>%s</label>',$key,$val);
            printf("\n");
          }
        }
    
        printf("  </fieldset>\n");
        printf('  <input type="submit" value="Go!" />');
        printf("\n");
    
        // 画面遷移で共通に利用する変数 
        printf('  <input type="hidden" name="history" value="%s"/>',$history);
        printf("\n");
      }
    
      // リクエストヘッダを作成(form終了)
      printf('</form>');
      printf("</div>\n");
    }
    
    printf("<html>\n");
    printf("  <head>\n");
    printf('  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">');
    printf("\n");
    printf('  <link rel="stylesheet" type="text/css" href="style.css">');
    printf("\n");
    printf("  <title>Buliding a Form</title>\n");
    printf("  </head>\n");
    printf("<body>\n");
    
    printf('<div class="main_style">');
    printf("\n");
    
    if (is_array($_GET["ans"])) {
      // 選択値の取得
      $choice = $_GET["ans"];
    
      // 選択肢が選ばれている場合
      $history = $_GET["history"];
      $history .= ("/" .$choice[0]);
      body1($history,$choice);
    }
    else {
      // 選択肢が選ばれていない場合
      if (isset($_GET["history"])) {
        $history = $_GET["history"];
        body1($history,"");
      }
      else {
        body1($history,"");
      }
    }
    printf("</div>\n");
    printf("</body>\n");
    printf("</html>");
    
  5. 動作サンプル

2013年4月7日日曜日

急遽俺おれSSLサーバーを立ち上げ

FB アプリ開発の見積もりの為急遽FBのデベロッパー登録することになったが、SSLサーバーを登録しないといけないらしい。取りあえず、今動いている apache2 を俗に言う俺おれ認証サーバーにしてみる。
$ sudo a2enmod ssl
Enabling module ssl.
See /usr/share/doc/apache2.2-common/README.Debian.gz on how to configure SSL and create self-signed certificates.
To activate the new configuration, you need to run:
  service apache2 restart
$ sudo /etc/init.d/apache2 restart
 * Restarting web server apache2                                                 ... waiting                                                             [ OK ]
$ sudo a2ensite default-ssl
Enabling site default-ssl.
To activate the new configuration, you need to run:
  service apache2 reload
$ sudo /etc/init.d/apache2 restart * Restarting web server apache2                                                 ... waiting                                                             [ OK ]

最初に

次に

次に

次に


以降、ブラウザで強制的に認証していけばSSLで通信できた。しかし、facebook アプリから起動してみると黙り。端末から直にモジュールを起動してみると、何かパッケージが足らない旨のエラーがでているので不足のモジュールをインストールしてテスト環境構築完了。

sudo apt-get install php5-curl

2013年4月5日金曜日

perl でファイルダンプ(クラス風味)

perl のファイルダンプをクラス風味に書き直してみた。perl には例外処理は実装されていないようだ。代わりとなるモジュールやevalがそれに当たるとされているが、代替モジュールは正式サポートされているものでもなく、evalは意味合いが異なる。クラスと継承くらいを利用しておくのが良いのだろう。
#! /usr/bin/perl

package main;
{
   package Dump;
   sub new {
      my $pkg = shift;
      bless {
         file => shift,
      },$pkg;
   }
   
   sub adrdump {
      my $self = shift;
      my($adr) = @_;
   
      printf("%08x :",$x);
      1;
   }
   
   sub hexdump {
      my $self = shift;
      my($buf) = @_;
      my($cnt) = 0;
      my($out) = "";
   
      foreach $x (unpack("C*",$buf)) {
         $out .= sprintf("- ") if ($cnt == 8);
         $out .= sprintf("%02x ",$x);
         $cnt++;
      }
      printf("%-50s",$out);
      1;
   }
   
   sub chrdump {
      my $self = shift;
      my($buf,$size) = @_;
      my($out) = "";
   
      foreach $x (unpack("C*",$buf)) {
         if ((0x00 <= $x && $x <= 0x1f) || 0x7f <= $x) {  
            $out .= "." 
         }
         else {
            $out .= sprintf("%c",$x);
         }
      }
      printf("| %-16s",$out);
      1;
   }
   
   sub display {
      my $self = shift;
      my($cnt,$size) = 0;
      my($buf) = undef;

      if (!open(fp,$self->{file})) {
         printf(STDERR "Can't open file[%s]\n",$self->{file});
         return(undef);
      }
      while($size=read(fp,$buf,16)) {
         $self->adrdump($adr*16);
         $self->hexdump($buf);
         $self->chrdump($buf);
         printf("\n");
     
         $cnt++;
      }
      close(fp); 
      1;
   }
}

if (scalar(@ARGV) != 1) {
   printf(STDERR "Usage : test02.pl file\n");
   exit(1);
}

my $dump = Dump->new(@ARGV[0]);
if (!$dump->display()) {
   printf(STDERR "エラー:display()\n");
   exit(1);
}
exit(0);

php でファイルダンプ(クラス風味)

php もファイルダンプをクラス風味で作成してみた。これも標準ライブラリが例外を発生しないので例外処理については中途半端に印象だが、c++よりは記述しやすいかもしれない。
#! /usr/bin/php
<?php
class Dump {
   private $file;
   private $fp;

   public function __construct($name) {
      $this->file = $name;
   }

   public function adrdump($adr) {
      printf("%08x : ",$adr);
   }
   
   public function hexdump($buf) {
      $out = ""; $cnt = 0;
      foreach (unpack("C*",$buf) as $x) {
         if ($cnt == 8) { $out .= "- ";}
         $out .= sprintf("%02x ",$x);
         $cnt++;
      }
      printf("%-50s",$out);
   }
   
   public function chrdump($buf) {
      $out = "";
      foreach (unpack("C*",$buf) as $x) {
         (0x00 <= $x && $x <= 0x1f) || 0x7f <= $x ?
            $out .= "." : $out .= sprintf("%c",$x);
      }
      printf("| %-16s\n",$out);
   }

   public function display() {
      $fp = fopen($this->file,"r");
      if (!$fp) {
          throw new Exception("ファイルオープンエラー");
      }
      
      $cnt = 0;
      while($buf = fread($fp, 16)) {
         $this->adrdump($cnt*16);
         $this->hexdump($buf);
         $this->chrdump($buf);
      
         $cnt++;
      }
      if ($fp) fclose($fp);
   }
}

if ($argc != 2) {
   printf("Usage : test02.php file\n");
   exit(1);
}

try {
   $dump = new Dump($argv[1]);
   $dump->display();
}
catch(Exception $e) {
   printf("エラー:%s\n",$e->getMessage());
   exit(1);
}
exit(0);
?>

2013年4月4日木曜日

c++ でファイルダンプ(クラス風味)

c++ のファイルダンププログラムもクラス風味にしてみました。c++ でも例外処理はサポートしているものの標準クラスライブラリではこの仕組みが使われていない。どうも、C言語とC++の棲み分けが曖昧で解りづらい印象が拭いきれない。Dump d(argv[1])も Dump d(new string(argv[1])) だとエラーになるのもなんだか釈然としないままです。
#include <fstream>
#include <string>
#include <iostream>
#include <boost/format.hpp>
using namespace std;
using boost::format;

class Dump
{
private:
    string file;
    char buf[17];
    int  cnt;
    int  error;
public:
    Dump(string s) {
        file = s;
        cnt  = 0;
        error = 0;
        std::fill_n(buf,sizeof(buf),'\0');
    }

    void adrdump(int adr) {
        cout << format("%08x : ") % adr;
    }

    void hexdump(unsigned char *buf, int size) {
        string out;
    
        for(int i=0;i<size;i++) {
            if (i == 8) { out += "- "; }
            out += (format("%02x ") % (int)buf[i]).str();
        }
        cout << format("%-50s") % out;
    }

    void chrdump(unsigned char *buf, int size) {
        string out;
    
        for(int i=0;i<size;i++) {
            out += (0x00 <= buf[i] && buf[i] <= 0x1f) || 0x7f <= buf[i] 
                ? "." : (format("%c") % buf[i]).str();
        }
        cout << format("| %-16s") % out;
    }

    int display() {

        error = 0;
        ifstream ifs(file.c_str());
        if (!ifs.is_open()) {
            cerr << format("Can't open file[%s]\n") % file;
            return(false);
        }
        while(!ifs.eof()){
            std::fill_n(buf,sizeof(buf),'\0');
            ifs.read((char *)&buf, sizeof(buf)-1 );
            if (ifs.bad()) {
                cerr << format("Read failed\n"); 
                return(false);
            }
    
            adrdump(cnt*16);
            hexdump((unsigned char *)buf,ifs.gcount());
            chrdump((unsigned char *)buf,ifs.gcount());
            cout << endl;
     
            cnt++;
        }
        ifs.close();
    }
};

int main(int argc, char *argv[])
{
    if (argc!=2) {
        cerr << format("Usage : test02 file\n"); 
        return(1);
    }

    Dump d(argv[1]);
    if (!d.display()) {
        cerr << format("Display error\n"); 
        return(EXIT_FAILURE);
    }
    return(EXIT_SUCCESS);
}

2013年4月3日水曜日

ruby でファイルダンプ(クラス風味)

ruby のファイルダンププログラムも java で試したクラス風味に変更してみた。ruby でも例外処理の考え方は python と同じ以下の方針と考えました。
Javaとは違い、Pythonの関数は、自身がどのような例外を送出するのかを宣言しない。発生しうる例外のうち捕捉すべきものを見定めるのはあなたの責任だ。
しかし、open エラーの場合、例外が Errno::ENOENT が返却されているので、errno に設定されうる値を全て捕捉しないといけいないのかと悩みました。その後、SystemCallError クラスがあることに気づき、これを rescue することでシステムコールエラーをもれなく捕捉した上で、raise e とすることで詳細情報の引き継ぎもできました。ちょっとしたことに悩むのは相も変わらずです。
#! /usr/bin/ruby
# coding: utf-8

class Dump
  def initialize(file)
    @offset = 0
    begin
      @fp = open(file,"r")
    rescue SystemCallError => e
      raise e
    end
  end

  def address()
    printf("%08x : ",@offset)
  end

  def hexdump(line)
    disp=""
    cnt=0
    line.each_byte do |c|
      if (@cnt == 8) then
          @disp << "- "
      end
      disp << sprintf("%02x ",c)
      cnt+=1
    end
    printf("%-50s ",disp)
  end
  
  def chrdump(line)
    disp="| "
    line.each_byte do |c|
      if ((0x00 <= c and c <= 0x1f) or 0x7f <= c) then
          disp << sprintf(".")
      else
          disp << sprintf("%c",c)
      end
    end
    printf("%-16s\n",disp)
  end

  def isnext()
    return(@fp.eof())
  end

  def next()
    @offset += 16
    return(@fp.read(16))
  end

  def display()
    while(!self.isnext()) 
        self.address()
        line = self.next()
        self.hexdump(line)
        self.chrdump(line)
    end
    @fp.close()
  end
end  

begin
  dump = Dump.new(ARGV.shift)
  dump.display()
rescue SystemCallError => e
  printf("ファイルオープンエラー\n")
  exit(1)
rescue Exception => e
  printf("異常終了\n")
  p e.class,e.backtrace
  exit(2)
end
exit(0)