いろいろと事情があって、IRCサーバを作ることになり、そのサーバ上でロギングするボットを書いてみたので公開。
勝手にすべてのチャネルに接続して、全発言をロギングしていきます。
言語はPHPで、pearのNet::SmartIRCと古いながらもDBを使ってサックリ実装。
ログの保存先は後々いろんな抽出条件で引き出したいのでRDBMSを使用してみた。まぁ、ファイルにロギングする仕様に替えてもそう手間ではないはず。

とりあえず使うためにはPEARモジュールのインストールと、あとはデータベースサーバの用意が必要。
テーブル定義はこんな感じ。

実装する上で困ったのは、IRC上での発言は大体が短すぎてmb_convert_encodingの自動変換がほとんど当てにならなかったこと。仕方ないのでググってもっと良い文字コード判定ルーチンをパクってきた。まぁ、サーバ上でやりとりするエンコーディングをあらかじめ固定しておけば不必要なんだけど。
ちなみに文字コード判定ルーチンの元ネタは
¸Ä¿ÍŪ¤Ê¥á¥â¤ÈÈ÷˺Ͽ 2004ǯ11·î
である。感謝感謝。

CREATE TABLE `chat_logs` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `channel` varchar(128) NOT NULL,
  `user` varchar(128) NOT NULL,
  `comment` text NOT NULL,
  `sent_date` datetime NOT NULL,
  PRIMARY KEY (`id`)
)

以下コード。

<?php
  include_once "Net/SmartIRC.php";
  include_once "DB.php";

  define("IRC_ENCODING", "utf-8");
  mb_internal_encoding(IRC_ENCODING);
  
  
  $default_channels = array("#oreore");

  class MyIRCBot {
    var $db;
    
    function __construct() {
      $dsn = array(
        'phptype'  => 'mysql',
        'username' => 'user_name',
        'password' => 'pass_word',
        'database' => 'irc_logs'
      );
      $this->db = DB::connect($dsn);
      $res = $this->db->query('SET NAMES utf8;');
    }
    
    function __destruct() {
      $this->db->disconnect();
    }
  
    function onMessage(&$irc, &$data) {
      $res = $this->db->query('INSERT INTO `chat_logs` (`channel`,`user`,`comment`,`sent_date`) VALUES(?,?,?,NOW())',array($this->encode($data->channel),$this->encode($data->nick),$this->encode($data->message)));
    }
        
    function getList(&$irc) {
      $irc->getList();
    }
    
    function onGetList(&$irc, &$data) {
      if ($data->message != 'End of channel list.'){
        $irc->join($data->rawmessageex[3]);
      }
    }

    // PHPシステム環境文字列→IRC日本語文字列の変換
    function encode($str) {
      return mb_convert_encoding($str, IRC_ENCODING, detect_encoding_ja($str));
    }

    // IRC日本語文字列→PHPシステム環境文字列の変換
    function decode($str) {
      return mb_convert_encoding($str, mb_internal_encoding(), IRC_ENCODING);
    }
  }
  
  /**
   * 日本語文字列の文字コード判定(ASCII/JIS/eucJP-win/SJIS-win/UTF-8 のみ)
   */
  function detect_encoding_ja( $str )
  {
      $enc = @mb_detect_encoding( $str, 'ASCII,JIS,eucJP-win,SJIS-win,UTF-8' );

      switch ( $enc ) {
      case FALSE   :
      case 'ASCII' : 
      case 'JIS'   : 
      case 'UTF-8' : break;
      case 'eucJP-win' :
          // ここで eucJP-win を検出した場合、eucJP-win として判定
          if ( @mb_detect_encoding( $str, 'SJIS-win,UTF-8,eucJP-win' ) === 'eucJP-win' ) {
              break;
          }
          $_hint = "\xbf\xfd" . $str; // "\xbf\xfd" : EUC-JP "雀"

          // EUC-JP -> UTF-8 変換時にマッピングが変更される文字を削除( ≒ ≡ ∫ など)
          mb_regex_encoding( 'EUC-JP' );
          $_hint = mb_ereg_replace( "\xad(?:\xe2|\xf5|\xf6|\xf7|\xfa|\xfb|\xfc|\xf0|\xf1|\xf2)", '', $_hint );

          $_tmp  = mb_convert_encoding( $_hint, 'UTF-8', 'eucJP-win' );
          $_tmp2 = mb_convert_encoding( $_tmp,  'eucJP-win', 'UTF-8' );
          if ( $_tmp2 === $_hint ) {

              // 例外処理( EUC-JP 以外と認識する範囲 )
              if (
                  // SJIS と重なる範囲(2バイト|3バイト|iモード絵文字|1バイト文字)
                  ! preg_match( '/^(?:'
                      . '[\x8E\xE0-\xE9][\x80-\xFC]|\xEA[\x80-\xA4]|'
                      . '\x8F[\xB0-\xEF][\xE0-\xEF][\x40-\x7F]|'
                      . '\xF8[\x9F-\xFC]|\xF9[\x40-\x49\x50-\x52\x55-\x57\x5B-\x5E\x72-\x7E\x80-\xB0\xB1-\xFC]|'
                      . '[\x00-\x7E]'
                      . ')+$/', $str ) && 

                  // UTF-8 と重なる範囲(全角英数字|漢字|1バイト文字)
                  ! preg_match( '/^(?:'
                      . '\xEF\xBC[\xA1-\xBA]|[\x00-\x7E]|'
                      . '[\xE4-\xE9][\x8E-\x8F\xA1-\xBF][\x8F\xA0-\xEF]|'
                      . '[\x00-\x7E]'
                      . ')+$/', $str )
              ) {
                  // 条件式の範囲に入らなかった場合は、eucJP-win として検出
                  break;
              }
              // 例外処理2(一部の頻度の多そうな熟語は eucJP-win として判定)
              // (珈琲|琥珀|瑪瑙|癇癪|碼碯|耄碌|膀胱|蒟蒻|薔薇|蜻蛉)
              if ( mb_ereg( '^(?:'
                  . '\xE0\xDD\xE0\xEA|\xE0\xE8\xE0\xE1|\xE0\xF5\xE0\xEF|\xE1\xF2\xE1\xFB|'
                  . '\xE2\xFB\xE2\xF5|\xE6\xCE\xE2\xF1|\xE7\xAF\xE6\xF9|\xE8\xE7\xE8\xEA|'
                  . '\xE9\xAC\xE9\xAF|\xE9\xF1\xE9\xD9|[\x00-\x7E]'
                  . ')+$', $str )
              ) {
                  break;
              }
          }

      default :
          // ここで SJIS-win と判断された場合は、文字コードは SJIS-win として判定
          $enc = @mb_detect_encoding( $str, 'UTF-8,SJIS-win' );
          if ( $enc === 'SJIS-win' ) {
              break;
          }
          // デフォルトとして SJIS-win を設定
          $enc   = 'SJIS-win';

          $_hint = "\xe9\x9b\x80" . $str; // "\xe9\x9b\x80" : UTF-8 "雀"

          // 変換時にマッピングが変更される文字を調整
          mb_regex_encoding( 'UTF-8' );
          $_hint = mb_ereg_replace( "\xe3\x80\x9c", "\xef\xbd\x9e", $_hint );
          $_hint = mb_ereg_replace( "\xe2\x88\x92", "\xe3\x83\xbc", $_hint );
          $_hint = mb_ereg_replace( "\xe2\x80\x96", "\xe2\x88\xa5", $_hint );

          $_tmp  = mb_convert_encoding( $_hint, 'SJIS-win', 'UTF-8' );
          $_tmp2 = mb_convert_encoding( $_tmp,  'UTF-8', 'SJIS-win' );

          if ( $_tmp2 === $_hint ) {
              $enc = 'UTF-8';
          }
          // UTF-8 と SJIS 2文字が重なる範囲への対処(SJIS を優先)
          if ( preg_match( '/^(?:[\xE4-\xE9][\x80-\xBF][\x80-\x9F][\x00-\x7F])+/', $str ) ) {
              $enc = 'SJIS-win';
          }
      }
      return $enc;
  }

  
  $bot = new MyIRCBot();
  $irc = new Net_SmartIRC();

  $irc->connect("localhost", 6667);
  $irc->login("test_bot", "test");
    
  $irc->join($default_channels);
  
  
  $irc->registerActionhandler(SMARTIRC_TYPE_LIST, '.+', $bot, 'onGetList');
  $irc->registerActionhandler(SMARTIRC_TYPE_CHANNEL, '.+', $bot, 'onMessage');
  $irc->registerTimehandler(5000, $bot, 'getList');

  $irc->listen(); 
?>

ブログが更新できない日々。

社会人生活が始まって、あまりにブログが更新できていない現状に愕然としてみる。

まぁ、書けない理由は社会人生活とは全然関係の無いところにあるのですが。

最近の私のトレンドはDIYDIYっつーか、うどん打ったりしています。今度のGWには、遠くに就職した友人も地元に帰ってくるので何か作っておこうかしら。燻製肉とか。
ただ、そんなもん作ってる時間があるかが疑問。よく考えたら今度の日曜日、情報処理技術者試験じゃないか!

別に取得してもこれと言ったメリットも無いのに受けてしまうのは、資格取得から二年間は午前Iが免除されるからです。だからつい、「免除期間が切れる前に」と、思ってしまうんですね。経産省商売が上手い。

ネット上で無料で読めるプログラミングとかの本をかき集めてみた。

さーて、この間の木曜日からケツの青い社会人になりましたcalcsです。

まぁそれはそれとして、個人的に記録しているネット上でタダで読める本が割と集まって来ているので、まとめてみました。意外と「あー、ちょっと読みたかった」的な本もあったりするので、まず試し読みするのにもいいですね。本を置く場所も買いにいく手間もいりませんし。

さらに言うなら電子出版がもっと普及すれば、良いんですけどねぇ。もしくはリアル本に全文検索機能をつけるべきw

本のリストは以下になります。

続きを読む

新人研修行ってきた。

どもども。来週からお世話になる会社の新人研修ということで、京都から千葉まで適当に行って参りました。新習志野とかいうところで、習志野と聞いても空挺の駐屯地があるぐらいしか私にはまったく分からんのですが。
しかしまぁ、まだ私は社員でもないのに、交通費と研修費を負担してもらって勉強してこれるってのは、かなりお得で良いですね。偶に専門研修の広告なども、メールボックスに入ったりしているのですが大体どれもビックリ高いですし。ただ、貴重な春休みと天秤にかければそのお得度がどう傾くのかは分かりませんがw

ま、それはそうと新幹線乾燥しすぎ。風邪ひいたかも分からん。喉が痛い。

さーて、何か何だかんだで2日間ぐらい殆ど寝られなかったので寝ます。勉強せにゃならん事はたくさんあるんだが。とりあえず英語力が最近ヤバいので絞らねば。電子辞書どっか行った。アレが無いとなかなか洋書読む気しないんだよなぁ。型落ち品を探すか。

春休みのすごし方

先々週に卒業旅行がてらイタリアにいってから更新止まりっぱなしでワロタw

生存報告がてら最近の活動でもすこし。

まずなんといってもboogie boardを買ってしまったこと。まぁ、一言で言えば電子ペーパーなのですが、軽くて楽しい。ただし使い道がいまいち不明。
とりあえずPCのそばにおいて、ディクテーションのときにチョコチョコ使ってます。

あと、電子タバコ

Health e-Cigarette2 煙の出る電子タバコ ヘルスイーシガレット2 メンソール味 本体

Health e-Cigarette2 煙の出る電子タバコ ヘルスイーシガレット2 メンソール味 本体

)とかもタバコ吸わないのにかってみた。感想としては、吸い慣れるとまぁまぁイケる。口寂しいときに飴代わりに吸ってます。ただ壊れやすいらしいので、そこだけ戦々恐々と言った感じ。

他はもう本読んだり、靴磨いたり、包丁研いだりかなりまったりと過ごし中。あ、後今日うどんを打って昼夜二食ともウドンだった。うどんうまい。でも一週間ぐらいいらん。今度はチーズでも作ろうかしらん。

やっぱりUbuntu9.10でWebSocketsが動かない。

前回に引き続いて。

結論としてはやっぱり動かないのだけれども、続報を。
WebSocketsが動くサイトと動かないサイトがあるのはなぜか?つーか何でローカルに置いてあるサンプルが動かないのか。

ひょっとして、と思ってグローバルIPからアクセスしてみたら、ずっと0(CONNECTING)だったreadystateが2(CLOSED)になった。
なんでやねん! しかもoncloseイベントも発生しないし…。

でもまぁ、とりあえずubuntu版のchromeにはホスト名解決にエラーがあるってことで良いのかしらん。

しかし readystate == 1(OPEN) への道は遠い。

中高生に送りたい数学の本まとめ

 最近は春休みなので、本棚の本を一挙に整理していたのですが、どうも本棚を見ていると「ああ、この本、中高生のときに読みたかったなぁ…」という数学の本が意外と多かったのでまとめて見ました。(読んでいた本もありますが)

 と言うかこれは常々思っていることなんですが、数学は教育課程から専門書への導入が比較的少ない気がします(ただし大学を除く)。すくなくとも中高六年間における、数学の教育カリキュラムはかなり良い出来で、紀元前から19世紀あたりまでの数学数千年の歴史がわずか六年でマスターできる優れものです。が、いかんせんそれだけでは味気ないというかなんというか。まぁ、歴史小説を読んだり旧跡を歩いて歴史知識を深めるかんじで、数学も教科書や参考書出ない本を読む事も、肥やしになってくれるようなそうでないような。
 そもそも高校の数学教科書って、カリキュラムはよくできていても教科書自体の記述はスカスカでとても独習に耐えたもんではない気がする。

 簡単に言うと、中高生も教育指導要領外の数学にもっと萌えようってことで。うん。難易度目安は数学がそこそこ好きな中高生なら読みこなせることです。

続きを読む