プログラマメモ2 - programmer no memo2

ある文脈時に、変数がとりうる値から状態を決めたいわけです 2009/01/29
2009/01/30

ある状態のときにある動作をするプログラムを書くときに、
実装者に条件判定(if)を書かせないようにしたい。

とくにif文がネストするようなコードを書かせたくない(書きたくない)。

if(){
if(){
if(){

}
}
} else {
if(){


} else {

}
}


こういったコードになりがちなのはアプリケーションのもつ状態を把握していないときにおこると思います。
状態を把握していない場合、実装者が自分に都合のよいフラグを安易に(やむにやまれず)導入したりします。

アプリケーションは、《ある条件のときにある処理を実行してよい》、の積み重ねと考えると、ある条件を、
抽出する方法を簡単に(一目で把握)できないかなと。

アプリケーションのもつ状態をアプリケーションがもつ変数のその瞬間時の組み合わせとするなら、
状態を表にできるかなと考えたわけです。

これは僕の以前からずーともっているテーマなのですが、これをうまく表現するための方法がないかな。

ある文脈時に、変数がとりうる値から状態を決めたいわけです。

アイデアレベル
/* 文脈 abcWindow */
CONTEXT:abcWindow

/* 変数から状態を決定 */
STATE(name:ST_1): a:true, b:false, c:3, d:visible
STATE(name:ST_2):STS_1, e:false
STATE(name:ST_3):STS_2, e:true
STATE(name:ST_4):a:true, b:false, c:3, d:not visible, e:true

/* 変数の取得方法 */
VALUE(name=a):{

}
VALUE(name=b):{

}
VALUE(name=c):{

}
VALUE(name=d):{

}
VALUE(name=e):{

}

タグから類似度をはかる - アイデアレベル 2008/03/03

詳しくみていないのですが、記事の類似度で結ぶサービスがリリースされていました。



どういうふうな仕組みになのかというのは開発者のブログにありました。
記事の類似度を測る方法として、ベクトル空間モデル(TF*IDF)を用いています。こえむの編集後記 » ブログを記事で結ぶブログパーツ『シムエントリ』をリリース


ところで、ベクトル空間モデルから、昔、ちょっとだけ触ったことがあるコンセプトベースのことを思い出しました。

コンセプトベースには概念検索なるものがあったなぁ。

以前、プログラマメモ2: Blogger 関連ありそうな記事のリンクをつける。を試していたとき、タグの付け方から、類似度をもう少し正確に割り出すことができないかなぁと思っていました。

で、記事全体から単語を抽出するのは大変そうなので、単純にタグ(Bloggerならラベル)から、記事の類似度をはかってクラスタリングするのはありなのではないかというふうに考えたわけです。

タグ(ラベル)は記事を書いた作者が、意図をこめてつけるので、その時点である程度記事のグループ化ができているわけでし。

ですが、タグってあんまり細かく分類してつけてないですよね。固有名詞をさほど使っていない。記事が増えると大雑把なくくりで記事が埋没してしまう。タグでそもそも分類しようと考えないほうがいいのかも。

参考


記事から自動でタグの候補をみつけてくれるサービスもありますね。


タグ(ラベル)から記事の類似度をはかるのはありだと思うんですが、どうなんでしょうかね。

過去の記事のほりおこし アイデアレベル 2008/02/17

せっかくBloggerにラベル(タグ)の機能があるので、さらに利用できないかなぁと思いました。
過去の記事が埋没するのをほりおこして、新しい記事と関連づけられたらよさげです。



データをキャッシュさせたり、関連記事を作成するためのルールをいろいろ拡張したりしたいので、サーバにそのロジックをもたせてもいいかなぁと画策中です。

失敗、cometを使ってtail -fの内容を送りたい。 2008/02/03

クライアントでサーバー側のログをみたいということで、tomcat6に入っているcometさんの機能を使えないかなというわけで、頭をひねってみたのでした。

安直にtail -fをコマンド実行して標準出力の内容をせっせっとcomet使って、クライアントに送ればいいじゃんと思ったわけです。

方々を参考にして簡単に実装してみましたが、結果は、「もっと工夫しないとだめ」です。

工夫する必要がある箇所は、ずばりログのとりこぼしがないようにしないといけないところです。

ログのとりこぼしがないようにするためには、どこまでのログをクライアントは受信されたのかという情報をもたせないとできない。それで、その情報をもとにして、サーバーがログを送ってあげる。

あと、CometサーバーとCometクライアントの仕組みがよくわからないです。
基本はLong Pollingなんだというキーワード的にはわかってるんですが....

サーバー側がずーと書き込めるストリームをもちつづけて、だらだら書けば、クライアントに表示できるのであれば簡単だなぁと思ったのですが、その場合のクライアントの実装が思いつかないので、XmlHttpRequest方式(たぶん)で。

しかし、サーバー側の書き込みが終了したということを通知する方法がわからなかったので、BEGINで受け取ったイベントに対してTIMEOUTを設定して、必ずその時間がたったらクライアントはレスポンスを受け取り、処理をして再接続という実装(のつもり)にしてみました。

すぐにクライアントに反映されないので、メリットが感じられないような...

ログのように常に変化し続けるものを表示する場合ってiframe方式(たぶん)がいいのかもしれない。



理解不足、曲解、だめだめですが、とりあえず晒しておくことにします。

<html>
<head>
<script type="text/javascript" src="jquery-1.2.2.min.js"></script>
<script type="text/javascript" >
var isStop = false;
var cash_log1 ="";
var cash_log2 ="";
var cnt =0;
function oo(){
$.ajax({
url: 'http://localhost:8090/examples/tail',
type: 'POST',
dataType: "text",
timeout: 60000,
error: function(){
if(isStop) return;
alert('Error loading text document');
},
success: function(data){

if(isStop) return;
if(!(0 < data.length)){
setTimeout(oo, 1);
return;
}

cash_log1 = cash_log2;
cash_log2 = data;

$('#pp').val(cash_log1 + cash_log2);
setTimeout(oo, 1);
}
});


}
</script>
</head>
<body onload="oo();">
<input type="button" onclick="javascript:isStop=true;" value="stop"/>
<input type="button" onclick="javascript:isStop=false;oo();" value="start"/>
<div id="p"></div>
<textarea id="pp" cols=100 rows=10>
</textarea>
</body>
</html>


import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Scanner;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;

import org.apache.catalina.CometEvent;
import org.apache.catalina.CometProcessor;

public class TailServlet extends HttpServlet implements CometProcessor {

private static final long serialVersionUID = 1L;
protected ArrayList<CometEvent> connections = new ArrayList<CometEvent>();
protected MessageSender messageSender = null;

public void init() throws ServletException {
messageSender = new MessageSender(getInitParameter("targetFile"));
Thread messageSenderThread = new Thread(messageSender, "MessageSender["
+ getServletContext().getContextPath() + "]");
messageSenderThread.setDaemon(true);
messageSenderThread.start();
}

public void destroy() {
connections.clear();
messageSender.stop();
messageSender = null;
}

public void event(CometEvent event) throws IOException, ServletException {

HttpServletRequest request = event.getHttpServletRequest();
if (event.getEventType() == CometEvent.EventType.BEGIN) {

// timeoutを起こしてクライアントにいったんデータを返す。
event.setTimeout(new Integer(5000));
log("Begin for session: " + request.getSession(true).getId());
log(connections.toString());
synchronized (connections) {
connections.add(event);
}

} else if (event.getEventType() == CometEvent.EventType.ERROR) {
log("Error for session: " + request.getSession(true).getId());
log("EventSubType: " + event.getEventSubType());
synchronized (connections) {
boolean isRemoved = connections.remove(event);
log(" isRemoved:" + isRemoved);
}
event.close();
} else if (event.getEventType() == CometEvent.EventType.END) {
log("End for session: " + request.getSession(true).getId());
log("EventSubType: " + event.getEventSubType());
synchronized (connections) {
boolean isRemoved = connections.remove(event);
log(" isRemoved:" + isRemoved);
}
event.close();
} else if (event.getEventType() == CometEvent.EventType.READ) {
}
}

public class MessageSender implements Runnable {
protected boolean running = true;
String targetFile;

public MessageSender(String targetFile) {
this.targetFile = targetFile;
}

public void stop() {
running = false;
}

public void run() {
String command = "/usr/bin/tail -f " + targetFile;
Runtime runtime = Runtime.getRuntime();
Process process = null;
try {
process = runtime.exec(command);
InputStream in = process.getInputStream();
Scanner scanner = new Scanner(in);

while (scanner.hasNext() && running) {
String s = scanner.nextLine();
// log("o_o!==>" + s);
synchronized (connections) {
Iterator<CometEvent> iterator = connections.iterator();
while (iterator.hasNext()) {
CometEvent event = (CometEvent) iterator.next();
try {

PrintWriter writer = event
.getHttpServletResponse().getWriter();
writer.println(s);
writer.flush();

} catch (IOException e) {
log("IOExeption sending message", e);
} catch (UnsupportedOperationException e) {
e.printStackTrace();
}

}

}
}

} catch (IOException e1) {
e1.printStackTrace();
} finally {
if (process != null) {
try {
process.getErrorStream().close();
} catch (IOException e) {
}
try {
process.getInputStream().close();
} catch (IOException e) {
}
try {
process.getOutputStream().close();
} catch (IOException e) {
}
}
running = false;
}

}
}

}

コントローラーを重ねる 2008/01/30

データオブジェクトを操作するためのクラスを積み重ねる。




import java.awt.GridBagLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JPanel;

public class TestPanel extends JPanel {

private static final long serialVersionUID = 1L;

public static void main(String[] args) {
}

public TestPanel() {
super();
initialize();
addMouseListener(new Controllers());
}


private void initialize() {
this.setSize(300, 200);
this.setLayout(new GridBagLayout());
}

class Controllers extends MouseAdapter{
List<Controller> list = new ArrayList<Controller>();

@Override
public void mousePressed(MouseEvent e) {
for (Controller controller : list) {
controller.mousePressed(e);
}
}
}

class Controller extends MouseAdapter{

}
}

アイデア ローカルホストサーバをたてて、firefoxと通信 2007/07/26

アイデアレベル。

閲覧しているwebページから、特定の部分データをクリッピングする場合、firefoxでgreasemonkeyを動かして、自分のマシン上にlocalhostのwebサーバを動かして、通信させて、ローカルに保存するというのはどうだろうと考えた。

(1)greasemonkeyを使用して、特定部分のデータを取得。
(2)GM_xmlhttpRequestを使用してhttp://localhost:8080/clippingとかに送信して、ローカルサーバがファイルに保存なり、データベースなり保存して後から利用できるようにする。

って感じ。

何故そうしたいかというと、greasemonkeyを使って特定のページの特定の部分を取得してファイルにして保存できるかなと考えていたのだけども、どうも、greasemonkeyから直接ファイル保存はできないみたいだから。

作るなら、jettyをクリッピングサーバーにしてgroovyでコード書いてみたいなぁ

今週は時間がないので来週ためしてみよう。