ひまlab

ひまな時になんか書く。

Pythonで循環リストっぽいものをやってみる

はじめに

しばらく放置していたので、小ネタを書いてみます。

ちょっとした状態管理を書くときなどに、循環リストが使いたくなる時があります。

起動 → 実行中 → 停止 → 起動みたいに繰り返される状態を表したいなど

使う機会があり、ちょっと書いてみたので公開します。
リストと言いつつ、ジェネレータを使って実装しているため、追加などができませんので悪しからず。

やってみる

def circular_list(list):
    # listの長さは1以上
    index = 0
    while True:
        yield list[index]
        index = (index + 1) % len(list)

使ってみる

試しのテストを書いてみます。

import unittest
class Test(unittest.TestCase):
    def test_circular_list(self):
        list = circular_list(['foo', 'bar', 'baz'])
        self.assertEquals(list.__next__(), 'foo')
        self.assertEquals(list.__next__(), 'bar')
        self.assertEquals(list.__next__(), 'baz')
        self.assertEquals(list.__next__(), 'foo')
        self.assertEquals(list.__next__(), 'bar')
        self.assertEquals(list.__next__(), 'baz')

if __name__ == '__main__':
    unittest.main()

WebSocketを死活監視に使ってみた

はじめに

Websocketを使って、キープアライブのようなこと*1をやってみました。

やってみたキッカケは、お仕事でTomcatのWebSocket Sevletを作った際にAPIを見ていたら
接続が切れた時にイベントが拾えるようで、キープアライブに使えるのでは?と思ったからです。
やってみたら、案外ちゃんと使えたので内容を公開します。

ちなみに、WebSocketの実装にはTomcatのWebSocket Servletを使用します。
WebSocket Servletについては、色々解説しているサイトがあるので、ここでは説明を省きます。

環境

ライブラリ

仕組みについて

ざっくりと流れはこんな感じ

  1. クライアントがサーバにWebSocketで接続する
  2. 接続後に、クライアントからサーバにメッセージを送る
    • この時に、クライアントを識別する情報を渡してあげると、クライアントが識別できます
  3. サーバは、クライアントからのメッセージを受けて、クライアントに応答を返す
  4. クライアントは、サーバからのメッセージを受けて、サーバに応答を返す
    • 正常時は、上のサーバとクライアントのやり取りが繰り返される
  5. (クライアントが切れた時)サーバ側のonCloseが呼ばれる
    • ここで、切れた時に行いたい処理を呼び出す

ソース

サーバ側

以下のライブラリにパスを通す

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.TimeUnit;

import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;

import org.apache.catalina.websocket.MessageInbound;
import org.apache.catalina.websocket.StreamInbound;
import org.apache.catalina.websocket.WebSocketServlet;
import org.apache.catalina.websocket.WsOutbound;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

@WebServlet(name = "KeepAliveServlet", urlPatterns = { "/KeepAliveServlet" })
public class KeepAliveServlet extends WebSocketServlet {

    private static final long serialVersionUID = -1L;
    private static final Log log = LogFactory.getLog(KeepAliveServlet.class);
    private static Set<MessageInbound> messages = new HashSet<MessageInbound>();

    @Override
    protected StreamInbound createWebSocketInbound(String arg0, HttpServletRequest arg1) {
        log.info("called createWebSocketInbound.");
        return new KeepAliveInbound();
    }

    private class KeepAliveInbound extends MessageInbound {
        private WsOutbound outbound;

        private String clientId;

        @Override
        public void onOpen(WsOutbound outbound) {
            log.info("onOpen.");
            this.outbound = outbound;
            messages.add(this);
        }

        @Override
        public void onClose(int status) {
            log.info("onClose.");

            if (clientId != null) {
                log.info(String.format("クライアントID[%s]が切れた", clientId));
            }
            messages.remove(this);
        }

        @Override
        public void onTextMessage(CharBuffer cb) throws IOException {

            if (clientId == null) {
                clientId = cb.toString();
            }

            log.info("onTextMessage. " + cb);

            // すぐにメッセージを返すと通信量が多すぎるので、間隔を設ける
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            outbound.writeTextMessage(CharBuffer.wrap("echo from server."));
        }

        @Override
        public void onBinaryMessage(ByteBuffer bb) throws IOException {

        }

        @Override
        public int getReadTimeout() {
            // 初期状態だとクライアントと通信が切れても待ち続けるので、時間を指定しています。
            return 10000;
        }
    }
}

クライアント側

以下のライブラリにパスを通す

  • java_websocket.jar
import java.net.URI;
import java.net.URISyntaxException;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.java_websocket.client.WebSocketClient;
import org.java_websocket.drafts.Draft_17;
import org.java_websocket.handshake.ServerHandshake;

public class KeepAliveClient extends WebSocketClient {

    private static final Log log = LogFactory.getLog(KeepAliveClient.class);
    private static final String CLIENT_ID = "123";

    private KeepAliveClient(URI serverURI) {
        super(serverURI, new Draft_17());
    }

    @Override
    public void onClose(int arg0, String arg1, boolean arg2) {
        // サーバ側と接続が切れた時に呼ばれる
        log.info("onClose.");
    }

    @Override
    public void onError(Exception arg0) {
        log.error("onError. " + arg0.toString());
    }

    @Override
    public void onMessage(String arg0) {
        log.info(arg0);
        this.send("echo from client.");
    }

    @Override
    public void onOpen(ServerHandshake arg0) {
        log.info("onOpen called. " + arg0.getHttpStatus());
        this.send(CLIENT_ID);
    }

    public static KeepAliveClient getInstance() {
        URI uri;
        try {
            // 環境に合わせて接続先を変更
            uri = new URI("ws://localhost:8080/TomcatProject/KeepAliveServlet");
        } catch (URISyntaxException e) {
            throw new RuntimeException(e);
        }
        KeepAliveClient client = new KeepAliveClient(uri);
        return client;
    }

}

実行用のメインクラス

public class Main {

    public static void main(String[] args) {
        KeepAliveClient client = KeepAliveClient.getInstance();
        client.connect();
    }

}

動かしてみる

まず、Mainクラスを適当に実行 クライアント側のログはこんな感じ

KeepAliveClient onOpen
情報: onOpen called.
KeepAliveClient onMessage
情報: echo from server.
KeepAliveClient onMessage
情報: echo from server.
KeepAliveClient onMessage
情報: echo from server.

サーバ側のログはこんな感じ

sample.KeepAliveServlet createWebSocketInbound
情報: called createWebSocketInbound.
KeepAliveServlet onOpen
情報: onOpen.
KeepAliveServlet onTextMessage
情報: onTextMessage. 123
KeepAliveServlet onTextMessage
情報: onTextMessage. echo from client.
KeepAliveServlet onTextMessage
情報: onTextMessage. echo from client.

ここで、クライアント側の接続を切る(LANを切るとか) そうすると、しばらくしてサーバ側にクライアントが切れたとログが出る

KeepAliveServlet onClose
情報: クライアント[123]が切れた

このような感じで、クライアント側の死活を監視することができる

終わりに

WebSocketのちょっと変わった使い方を紹介してみました。
あまりミッション・クリティカルな用途には向きませんが
比較的簡単に、キープアライブ的なことができるのでお試しあれ!*2

*1:ここでは、サーバに接続してきたクライアントの死活(ネットワークの切断など)
調べるという普通とは逆のパターンについて書いてます

*2:僕はAndroidクライアントとサーバの接続状態の確認にこのような仕組みを使ってみました

VirtualBoxでCentOS6.4が起動しない時には

結論

この通りやればOK

説明は英語ですが、分からなくてもOK。画面に出る指示通りにやれば大丈夫です。

なんでこうなった

どうやら、Guest Additions入れたCentOSのバージョンを6.4に上げると起こるものらしい。

辿った道

  1. ちょっと調べたいことがあってVirtualBoxCentOSを起動しようとしたら起動しなかった。
  2. VirtualBoxのバージョンを最近あげていたのでそれが原因かと思って、バージョンを戻してもダメ。
  3. 諦めて、OSを再インストールしたら一旦は起動したもののyum updateをしたらまた起動しなくなった。
  4. 困り果てて、ぐぐってみたら上の動画がヒット(゚∀゚)
  5. 誰か他の人も同じ問題にハマるかもしれないので、記事を書く
    • この記事よりも動画が先に見つかると思うけど・・。

一年に素数は何個ある??

初めに

きっかけは、今日見たツイート

  • 数人が似たツイートしていて、誰が最初にツイートしたのか分からなかったので文章のみコピってます
 
    一般人「3月9日だー!卒業シーズンだしレミオロメンだねー」 
     
    ボカロ厨「ミクの日!」 
     
    バンギャ「SuGの日!」 
     
    ガンダム「ザクの日」 
     
    東工大生「そ、素数…」 
    
    _人人人人人人人_ 
    >  突然の素数 < 
     ̄Y^Y^Y^Y^Y^Y ̄

これを見た時、3月9日が素数って言うのがよく分からなかった。

3 + 9が素数?
それはない・・

月と日をくっつけた数 → 39が素数?
それっぽいけど、違う

そんなことを考えていると別の疑問が湧いた

あ、でも月と日をくっつけた数が、素数って一年に何個あるんだろう??

調べてみた

まずは、条件を考える

  • 範囲は、2012年の1年間(1月1日から12月31日)
    • 閏年だったので・・
  • 月と日のくっつけ方は、3月9日が39になるようにくっ付ける
    • 日の頭が0になる時は、0をとるようにする(3月9日 ≠ 309)
      • 最初に思いついたのが、この形式だったので・・

次に、調べる用のコードを書く

    def is_prime(number):
        if number % 2 == 0 or number % 3 == 0:
            return False

        for x in range(5, int(number ** 0.5) + 1):
            if number % x == 0:
                return False
        return True

    import time
    from datetime import date

    A_DAY = date.resolution
    prime_numbers = [ ]
    other_numbers = [ ]
    day = date(2012, 1, 1)
    while day <= date(2012, 12, 31):
        # 日付の先頭から0を削る 例: 1/1 → 11
        _day = int(str(day.month) + str(day.day))
        if is_prime(_day):
            prime_numbers.append(_day)
        else:
            other_numbers.append(_day)
        day += A_DAY
    assert len(prime_numbers) + len(other_numbers) == 366

    print (prime_numbers)
    print ('size = %s' % len(prime_numbers))

実行してみる

f:id:kanjin:20130309232301p:plain

今回の条件では、一年に素数は67個ある!

  • これ見た時、思ったより多いなって思いました

最後に

酔った勢いで書いた
反省している

読み返すとコードがごちゃごちゃしてるので、次はもっとスッキリしたコードを書くように頑張ろう
でも、結構楽しめたのでよかった

Tomcat7にEclipseからアプリケーションをデプロイする方法

前置き

Tomcat7に対して、EclipseからAntを使ってデプロイしようとした際に、色々苦戦したのでやり方を記録に残します。
やることはそれほど多くありませんが、Tomcat6とは違いがあるので、これからTomcat7を使う方は参考にどうぞ。

環境

手順

Tomcatの設定

  • デプロイに使うTomcatユーザのロールに"manager- script"を追加します。
    • TOMCAT_HOME/conf/tomcat-users.xmlを開き、以下のようにrolesのとこに、manager-scriptを追加
    <tomcat-users>
        <user name="admin" password="tomcat" roles="manager-gui,manager-script"/>
    </tomcat-users>

Eclipseの設定

Eclipseを使用せずに、Antのみで行いたい場合は、参考のページを見てください

  • Antが使用するjarを追加
    • build.xmlを用意
      • warを作れる定義を用意。詳細は省略
    • プロジェクトエクスプローラ上で、Build.xmlを右クリック
    • Run As → Ant Build を選択 f:id:kanjin:20130302213916p:plain
    • 上部のタブから、Classpathを選択 → Add External JARsを押下 f:id:kanjin:20130302214037p:plain
    • 事前に取得した以下の7つのjarを選択し、Applyを押下
      1. tomcat-juli.jar
      2. catalina-ant.jar
      3. tomcat-coyote.jar
      4. tomcat-util.jar
      5. jasper.jar
      6. jasper-el.jar
      7. servlet-api.jar
        • jasper.jar, jasper-el.jar, servlet-api.jarはドキュメントに載ってないので要らないかも・・。消すとエラーが出るので追加しています

Build.xmlの編集

  • 以下の内容をBuild.xmlに追加
    • プロパティ値は、環境に合わせて書き換える
 <!-- プロパティ値 -->
    <property name="manager.url"   value="http://192.168.0.2:8080/manager/text"/>
    <property name="manager.username"   value="admin"/>
    <property name="manager.password"   value="tomcat"/>
    <property name="manager.context.path"   value="/TomcatProject"/>
    <property name="manager.war.file"   value="file:./dist/TomcatProject.war"/>  
    <property name="manager.update"   value="true"/>
    
    <target name="manager.deploy.war"
        depends="context.status"
        if="context.deployable">
        <deploy url="${manager.url}"
            username="${manager.username}"
            password="${manager.password}"
            path="${manager.context.path}"
            update="${manager.update}"
            war="${manager.war.file}"/>
    </target>

    <target name="manager.undeploy.war" 
        description="context.status"
        if="context.undeployable">
        <undeploy url="${manager.url}" 
            username="${manager.username}" 
            password="${manager.password}" 
            path="${manager.context.path}" />
    </target>

    <target name="context.status">
        <property name="running" value="${manager.context.path}:running"/>
        <property name="stopped" value="${manager.context.path}:stopped"/>

        <list url="${manager.url}"
            outputproperty="ctx.status"
            username="${manager.username}"
            password="${manager.password}">
        </list>

        <condition property="context.running">
            <contains string="${ctx.status}" substring="${running}"/>
        </condition>
        <condition property="context.stopped">
            <contains string="${ctx.status}" substring="${stopped}"/>
        </condition>
        <condition property="context.notInstalled">
            <and>
                <isfalse value="${context.running}"/>
                <isfalse value="${context.stopped}"/>
            </and>
        </condition>
        <condition property="context.deployable">
            <or>
                <istrue value="${context.notInstalled}"/>
                <and>
                    <istrue value="${context.running}"/>
                    <istrue value="${manager.update}"/>
                </and>
                <and>
                    <istrue value="${context.stopped}"/>
                    <istrue value="${manager.update}"/>
                </and>
            </or>
        </condition>
        <condition property="context.undeployable">
            <or>
                <istrue value="${context.running}"/>
                <istrue value="${context.stopped}"/>
            </or>
        </condition>
    </target>
  • プロパティ値について
    • manager.url
      • デプロイ先のサーバを示すURL
        • http://<hostname>:<port>/manager/text
    • manager.username
      • デプロイに使用するtomcatのユーザ名
    • manager.password
      • デプロイに使用するtomcatのパスワード
    • manager.context.path
      • デプロイするアプリケーションのコンテキストパス
        • /<任意のコンテキストパス>
          • /を忘れずにつける
    • manager.war.file
      • warへのパス
    • manager.update
      • すでにデプロイされている場合に、更新するか
        • 更新する場合: true, 更新しない場合: false

デプロイ

  • プロジェクトエクスプローラ上で、Build.xmlを右クリック
  • Run As → Ant Build を選択
  • manager.deploy.warを選択し、Runを押下

アンデプロイ

  • プロジェクトエクスプローラ上で、Build.xmlを右クリック
  • Run As → Ant Build を選択
  • manager.undeploy.warを選択し、Runを押下

以上、思ったより長かった

参考

Mountain Lionを使い始めて、選んだアプリたちを紹介

MacBook Air(11.6)を使い始めて、1ヶ月が経ちました。
# 普段は、Windowsをメインで使ってます。
使い始めた感想は、一言で言って快適!
OSの操作は自然で、ほとんど考えずに使えました。
また、Bashや各種コマンドが最初から使えるのが便利。

ただ、困ったことが1つがあります。
Windowsで使い慣ればアプリケーションの幾つかが使えないこと。
そんな中で、選んだアプリケーションを一ヶ月の記念に書きます。
これから、使う人に少しでも参考になればいいな~と

コンセプト

なるべく使い慣れたアプリと同じ感じのものを選んでます。
また、情報が豊富な定番の中から選んだつもりです。
それと、Macの主な使い方がお布団でネットを見るのとコードを書くことなので
そっち方面にアプリケーションが偏っています^^;

アプリケーション

分類 Winアプリ Macアプリ コメント
ブラウザ Firefox Firefox マウス操作系のアドオンが気に入ってるけど、マウス使っていないので、Chromeにしようか検討中
Twitter Saezuri 夜フクロウ Macアプリの中で一番使って見たかった。とっても素敵。
メモ Evernote Evernote 同じだけど、UIが違う(バージョンの違い?)。
日本語入力 Google日本語入力 Google日本語入力 悩まなくて済んだ。Googleさまさま。
圧縮解凍 Lhaz Stuffit Expander 定番っぽい?
ストレージ Dropbox Dropbox
クリップボード拡張 Clibor ClipMenu 使いやすい
画像閲覧 MassiGra (なし) 標準のものを使ってる
動画再生 MPC VLC, QuickTime たまに動画を見るときに
音楽再生 foobar2000 iTunes バージョン11がシンプルで使いやすいと思う
ウィルス対策 Microsoft Security Essentials ClamXav たまーにスキャンしてる
2画面ファイラー あふ (なし) 代わりが見つからないので、Finder使う
キーカスタマイズ keyhac (なし) OSの使い勝手がいいので、いらないかも
エディタ Vim(KaoriYa) MacVim ド安定
エディタ EmEditor CotEditor さっと使う用
ランチャー fenrir Alfred 一番迷った。Alfredは高機能だけど、fenrirを フォルダ移動用に使ってたので、ちょっと違う
SCM Mercurial Mercurial Macと使うと、日本語ファイル名の問題が・・・。 Gitもいいな
SCM(GUI) TortoiseHg SourceTree インストールが簡単なので、使って見てる
マージツール WinMerge p4merge なかなか変わりが見つからなかったけど、これに落ち着いた
grep Devas (なし) GUIでサクッと置換できるものを探し中
シェル bash(Cygwin) bash 最初から使えるのが嬉しい
SCP WinSCP (なし) 探し中
パッケージ管理 (なし) Homebrew あると楽。MacPortsと迷う

あとがき

さっと書いたので、忘れてるものもある気がします。
まだまだ慣れていないので、いい情報があったら教えていただけると嬉しいです。

のんびりしてたら、今年もあと少しになりました。
それでも、まだ時間があるので、楽しく過ごせるといいと思います。
# 自分は、今年やるやる詐欺をしていたScalaを楽しみます

では、メリークリスマス and いいお年を!

TortoiseHgをコマンドラインから使う

快適なMercurialライフのために、役立つかもしれない情報をお送りします。

前置き

TortoiseHgは、使い勝手の良いMercurialGUIクライアントです。
そんなTortoiseHgは、コマンドラインから(も)使用できます*1
コマンドラインなら、CUIを使ったほうがいいのではとおもわれるかもしれません。
しかし、これが意外と便利なのです。
たとえば、普段はCUIを使っていても、次のようなことはGUIのほうが使いやすことがあります。

  • ログを追いながら、変更内容を確認する
  • リビジョンとの差分を確認する

そこで、CUIGUIを組み合わせて、よりMercurialを便利に使う方法を紹介します。

環境

使い方

1. TortoiseHgをインストール
2. TortoiseHg(thg.exe)にパスを通す

  • デフォルトでは、C:\Program Files\TortoiseHg

3. ログを確認する

 > thg log

f:id:kanjin:20121209191730p:plain

  • 画像は、TortoiseHg履歴を使用しています

3. 差分を確認する

 > thg vdiff -r <rev>

f:id:kanjin:20121209191750p:plain

  • GUI diffツールに、WinMergeを使用するように設定しています

4. その他のコマンドを知る

 > thg help

f:id:kanjin:20121209191802p:plain
コマンド体系は、Mercurialと近いです。

おまけ

TortoiseHgは、Windows shellと統合されています。
しかしこれは便利な半面、いくつか問題があります。

  • 動作が重くなったり、右クリックのメニューがごちゃごちゃしたりとか

インストール時のオプションを変更することで、shellとの統合をやめることができます。

手順

  1. インストーラを起動し、Custom Setupまで進める
  2. Shell Extension x64(84)を選択しクリック
  3. Entrie feature will be unavailableを選択

f:id:kanjin:20121209191815p:plain

*1:マニュアルにも書かれており、知っている方も多いと思います