2006年07月のアーカイブ

USBの抜き差しが得点になるゲーム

先日の合宿の帰りに提案された、素敵なアイデア。

一定時間内にUSBの抜き出しを繰り返すことで得点を獲得するというゲーム。
もしくは、CD-ROMの出し入れを繰り返すことで得点を獲得する。

このゲームにはまると、USBのコネクタが著しく痛むので、USBメモリやUSBケーブルのメーカーと提携して、新しいコネクタをプレゼントする。

もしくは、音楽にあわせて、USBを抜き差しする、音ゲーというのもアリ。

投稿者 kujira : 10:58 | トラックバック

フォームの自動保存機能をつけるべき

よく掲示板などHTMLのフォームで長い文章を打っているときに、戻るボタンを押してしまって、せっかく書いた文章がパーになってしまうという経験ありませんか?

そんなときは、慌てず、進むボタンを押せば、復活する場合もありますが、多くの場合、無残にも消えてしまいます。そこで、タイマーなどを使って定期的に非同期にサーバーへ一時データを保持しておけば、このような恐ろしい経験をしなくてもすむはずです。

特に、Flashの場合は、クッキーに似た機能で、より多くのデータを保存できる、ローカル共有オブジェクトがあるので、これを使えば、サーバー負荷もかからず、かつ、悲惨な事件はおきにくくなると思います。

投稿者 kujira : 10:55 | トラックバック

伊豆で葵合宿しました!取材されました!

先週末に伊豆で葵の開発合宿を行いました。葵は、WEB 開発環境 で、BASICや日本語プログラミング言語の好きな言語を利用して、Wikiや掲示板など、動的なWEBサイトを構築することができるツールです。現在、鋭意開発中です。

葵の合宿では、今回が初のお泊り合宿で、伊豆に1泊2日しました。(実は、合宿とは名ばかりの日帰り合宿を過去数回行っています。)

その模様が、なんと、AERAで取材されました!!再来週掲載ということで楽しみです。

C言語でガリガリ書いたり、Linuxのインストールが不便な問題を解決したりと、実りの多い合宿となりました。

今回の参加者は、写真や動画の共有サイト「フォト蔵」を開発しておられるウノウの尾藤さん、自作OSの本がブレイク中のOSASK川合さん、自作シンセや自作ゲームなどクリエイティブな活動を幅広く手がけるadasさんと、デザイナーの兎友さんです。

取材が入ったことで、開発メンバーの士気も高くなり、また、温泉宿の一番良い部屋に泊まることが出来て、とても良かったです!(今後とも、何かしらの取材アリと言って部屋の予約をすると良いかも?!)

夏休み1週目の週末ということもあり、車が非常に込んでおり、車内に居る時間が長くなったのですが、その分、車内で、様々な技術情報の交換やアイデアの交換などができました。葵自体の開発もさることながら、車内で圧縮や暗号化、新しいサービスに関してなどなど、普段では話せないような、楽しい技術の話題がたくさんできるのも良い点でした。

特に、葵のLinuxへのインストール部分でウノウの尾藤さんに尽力していただき、加えて、葵の実行速度の高速化の部分を、OSASKの川合さんにずいぶん指摘してもらいました。

とても楽しく実りのあった合宿となりました。

投稿者 kujira : 10:46 | トラックバック

アイデアマラソン用ツール

毎日少しずつアイデアを出していって、数年続けていくうちに、スゴイ!アイデアのデータベースを作るのが、アイデアマラソンです。そんなアイデアマラソンのための管理ツールを作ったら、面白そうだと思っています。

まず、この手のやつは、毎日続けるのが大変なので、アイデアを出さない日は、メールで警告してくるとか、アイデア発想支援ツールなどのオマケ機能も大事だと思います。

発明発見の3大原則。

・何かのきっかけで突然のひらめき(関連物からの連想)によるアイデア
・何か困っていることがあって思いつくアイデア
・既存のもの同士を組み合わせて新しいものを作るアイデア

これを支援するための、アイデアツールが必須です。
昔、Windowsソフトで作って、いろいろやってみたときは、すごく面白くて、そのときのアイデアがたまに役に立ったり立たなかったりなんてことも・・・。

アクセス制御の仕組みも大事で、【公開ネタ】【非公開ネタ】【既存の人にだけ公開】があれば、グループでアイデア共有したり、他人のアイデアから連想したりと、いろいろ楽しそうです。マインドマップとか、既存のアイデアツールなんかと連動すると、さらに面白そうなのです。

葵でこつこつ作ってみようっと。

投稿者 kujira : 10:31 | トラックバック

Delphi7でDPIの取得

画面のプロパティでDPIを変更した場合、独自描画したピクセルがずれることがあります。 そんなときは、DPIを取得して、座標を計算させてから描画する必要があります。 ---( dpiValue := GetDeviceCaps(Self.Canvas.Handle, LOGPIXELSY); r := 96 / dpiValue; // DPIに沿って座標を変更 x1 := Trunc(x1 * r); y1 := Trunc(y1 * r); ---)
投稿者 kujira : 11:29 | トラックバック

Delphi7で管理者権限の判定

Delphi7で管理者権限の判定をする方法。Windows2000以降に対応。 ---( // 新しい Windows APIの関数を宣言 function IsUserAnAdmin():BOOL; external 'shell32.dll'; // 利用するとき procedure check_admin begin if IsUserAnAdmin = False then begin ShowWarn(GetLang('error.admin')); Halt; end; end; ---)
投稿者 kujira : 12:22 | トラックバック

ActionScript2.0でMD5

ActionScript2.0でMD5を得たいと思い、標準クラスをチェックしたけどなかったので、検索してみたら、MD5を得る関数が見つかりました。 MD5 in ActionScript: http://www.nurs.or.jp/~b3/scripts/md5as/ ただ、せっかくなのでASのクラスとして使いたかったので、上のソースをクラスにしてみました。 以下のような感じで使えます。 ---( hash_str = new MD5("strstr...").value; trace(hash_str); ---) 関数の場合と違って、include したりしなくても良いのが唯一のメリットです。 それで以下のプログラムをMD5.as という名前で保存しておきます。 ---( //---------------------------------------------------------------------- // MD5 Message-Digest // RFC1321 //---------------------------------------------------------------------- // (クラス化 ) http://kujirahand.com // (オリジナル) http://www.nurs.or.jp/~b3/scripts/md5as/ //---------------------------------------------------------------------- // USES: // hash = new MD5(str).value; // hash = new MD5(str).toString(); //---------------------------------------------------------------------- class MD5 { var g_dataArray:Array; function MD5(seed) { g_dataArray = MD5_hash(seed); } function toString() { var i, out, c; out = ""; for ( i = 0; i < 16; i++ ) { c = g_dataArray[i]; out += "0123456789abcdef".charAt((c >> 4) & 0xf); out += "0123456789abcdef".charAt(c & 0xf); } return out; } function get value():String { return this.toString(); } var MD5_T = [ 0x00000000, 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8, 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391 ]; var MD5_round1 = [ [0, 7, 1], [1, 12, 2], [2, 17, 3], [3, 22, 4], [4, 7, 5], [5, 12, 6], [6, 17, 7], [7, 22, 8], [8, 7, 9], [9, 12, 10], [10, 17, 11], [11, 22, 12], [12, 7, 13], [13, 12, 14], [14, 17, 15], [15, 22, 16] ]; var MD5_round2 = [ [1, 5, 17], [6, 9, 18], [11, 14, 19], [0, 20, 20], [5, 5, 21], [10, 9, 22], [15, 14, 23], [4, 20, 24], [9, 5, 25], [14, 9, 26], [3, 14, 27], [8, 20, 28], [13, 5, 29], [2, 9, 30], [7, 14, 31], [12, 20, 32] ]; var MD5_round3 = [ [5, 4, 33], [8, 11, 34], [11, 16, 35], [14, 23, 36], [1, 4, 37], [4, 11, 38], [7, 16, 39], [10, 23, 40], [13, 4, 41], [0, 11, 42], [3, 16, 43], [6, 23, 44], [9, 4, 45], [12, 11, 46], [15, 16, 47], [2, 23, 48] ]; var MD5_round4 = [ [0, 6, 49], [7, 10, 50], [14, 15, 51], [5, 21, 52], [12, 6, 53], [3, 10, 54], [10, 15, 55], [1, 21, 56], [8, 6, 57], [15, 10, 58], [6, 15, 59], [13, 21, 60], [4, 6, 61], [11, 10, 62], [2, 15, 63], [9, 21, 64] ]; var MD5_round = new Array( new Array(MD5_F, MD5_round1), new Array(MD5_G, MD5_round2), new Array(MD5_H, MD5_round3), new Array(MD5_I, MD5_round4) ); function MD5_F(x, y, z) { return (x & y) | (~x & z); } function MD5_G(x, y, z) { return (x & z) | (y & ~z); } function MD5_H(x, y, z) { return x ^ y ^ z; } function MD5_I(x, y, z) { return y ^ (x | ~z); } function MD5_pack(n32) { return new Array(n32 & 0xff, (n32 >>> 8) & 0xff, (n32 >>> 16) & 0xff, (n32 >>> 24) & 0xff); } function MD5_hash(seed) { var f, r, tmp; var i, j, k; var state = new Array(0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476); var abcd = new Array(0, 1, 2, 3); var x = new Array(16); var s = new Array(4); var dataArray = new Array(); var currentChar = 0; // // UCS2 or 4 -> UTF-8 // http://www.unicode.org/versions/corrigendum1.html // for (i = 0; i < seed.length; i++) { j = seed.charCodeAt(i); if ( j <= 0x7F ) { dataArray[currentChar++] = j; } else if ( j <= 0x7FF ) { dataArray[currentChar++] = ((j >> 6) & 0x3F) | 0xC0; dataArray[currentChar++] = ( j & 0x3F) | 0x80; } else if ( j <= 0xFFFF ) { dataArray[currentChar++] = ((j >> 12) & 0x0F) | 0xE0; dataArray[currentChar++] = ((j >> 6) & 0x3F) | 0x80; dataArray[currentChar++] = ( j & 0x3F) | 0x80; } else { dataArray[currentChar++] = ((j >> 18) & 0x07) | 0xF0; dataArray[currentChar++] = ((j >> 12) & 0x3F) | 0x80; dataArray[currentChar++] = ((j >> 6) & 0x3F) | 0x80; dataArray[currentChar++] = ( j & 0x3F) | 0x80; } } var len = dataArray.length; var index = len & 0x3f; var padLen = ( index < 56 )? 56 - index : 120 - index; if ( padLen > 0 ) { dataArray[currentChar++] = 128; for (i = 0; i < padLen-1; i++, currentChar++) { dataArray[currentChar] = 0; } } dataArray = dataArray.concat(MD5_pack(len * 8), MD5_pack(0)); len += padLen + 8; for ( k = 0; k < len; k += 64 ) { for ( i = 0, j = k; i < 16; i++, j += 4 ) { x[i] = dataArray[j] | (dataArray[j+1] << 8) | (dataArray[j+2] << 16) | (dataArray[j+3] << 24); } for ( i = 0; i < 4; i++ ) { s[i] = state[i]; } for ( i = 0; i < 4; i++ ) { f = MD5_round[i][0]; r = MD5_round[i][1]; for ( j = 0; j < 16; j++ ) { MD5_apply_round(x, s, f, abcd, r[j]); tmp = abcd[0]; abcd[0] = abcd[3]; abcd[3] = abcd[2]; abcd[2] = abcd[1]; abcd[1] = tmp; } } for ( i = 0; i < 4; i++ ) { state[i] += s[i]; state[i] = MD5_number(state[i]); } } dataArray = new Array(); return dataArray.concat(MD5_pack(state[0]), MD5_pack(state[1]), MD5_pack(state[2]), MD5_pack(state[3])); } function MD5_number(n) { while ( n < 0 ) { n += 4294967296; } while ( n > 4294967295 ) { n -= 4294967296; } return n; } function MD5_apply_round(x, s, f, abcd, r) { var a, b, c, d; var kk, ss, ii; var t, u; a = abcd[0]; b = abcd[1]; c = abcd[2]; d = abcd[3]; kk = r[0]; ss = r[1]; ii = r[2]; u = f(s[b], s[c], s[d]); t = s[a] + u + x[kk] + MD5_T[ii]; t = MD5_number(t); t = (t << ss) | (t >>> (32 - ss)); t += s[b]; s[a] = MD5_number(t); } } ---)
投稿者 kujira : 00:49 | トラックバック

Windowsでコントロールパネルのタイムゾーン設定を得る

Windowsでコントロールパネルのタイムゾーン設定を得る方法です。 ---(  TIME_ZONE_INFORMATION info;  GetTimeZoneInformation( &info ); printf("%d", info->bias); ---) 上のプログラムで、info-biasには、時差が分で入っています。
投稿者 kujira : 12:35 | トラックバック

スパムや悪戯と戦う

■スパムや悪戯と戦う

WEBサイトを運営していると、様々な問題が起きます。その問題の中で一番面倒なのが、うんざるするほどたくさん来るスパムメールや、掲示板へのスパム書き込みです。また、宣伝目的意外にも、誹謗中傷を行う悪戯やサイトのシステムを壊したりする悪戯も深刻な問題です。

なでしこのWEBサイトでも、多くのスパムと悪戯と戦っています。今日はいくつかその戦闘の様子をご紹介しようと思います。

●スパムメールとの戦い

まずはサポート用のメールアドレスに寄せられるスパムメール(迷惑メール)からです。スパム対策を行う前は、1日に100通ほどの宣伝目的のメールが送られていました。Webページでメールアドレスを公開していると、メールアドレスを自動収集するロボットに拾われて、スパム業者の標的になります。

そのため、ロボットに自動収集されないように、メールアドレスを掲載する場合に細工を施しています。スパムメールが増えてきた頃は、メールアドレスを全角アルファベットを書くだけで、スパムは減ったのですが、最近では、それだけでは不十分です。ロボットが賢くなり、全角で書かれたメールアドレスを半角に変換して収集するからです。

そこで、現在は、メールアドレスを画像にして掲載するようにしました。画像になっていれば、なかなかロボットが自動収集することが難しいからです。しかし、それでも、スパムメールはやってきます。たぶん、画像のメールアドレスをOCRなどのソフトと同じような仕組みで文字認識して収集しているのでしょう。ですので、わざとメールアドレスの画像に、ノイズを混ぜてOCRで読み取られにくくすると完璧です。ただ、こうすると、人間の目にも読みにくく、サポート用に公開しているのに、ユーザーに不便をかけることになります。

このような現状では、どうしてもメールを公開する限り、スパムメールと付き合わなければなりません。そこで、メールソフトで受信する前に、スパムかどうかを判断するフィルタリングソフトを利用しています。私が利用しているのは、Quick POPFileというソフトです。これは、オープンソースのPOPFileをより使いやすくカスタマイズしたもので、振り分け精度が良いので愛用しています。

クイックPOPFile
http://www.quickpopfile.com/

それから、実は、現在、研究用にダミーのメールアドレスを用意して、わざとメールアドレス収集ロボットに拾われるようにしています。最近のスパムメールの内容は、出会い系サイトへの勧誘メールや、フランチャイズへの勧誘、アダルトサイトへの誘導、親しげな友人を装うオレオレ詐欺に似たメールなどです。特に、親友を装うメールなどは、注意していないとうっかり返信してしまいそうになります。

これらの収集したスパムメールは、将来的に、スパム対策のために、利用しようと思っています。いくつかスパムを撃退するアイデアがあるので、そのうちに撃退用のソフトなどの形にすることができたらいいなぁと思っています。


●掲示板やブログへのスパムとの戦い

メールの次は掲示板です。なでしこでは、ユーザーが質問する掲示板、プログラムを掲載できる掲示板、要望や質問を書き込むことのできる掲示板など、多くの掲示板があります。実は、これらの掲示板の多くは、私自身は管理しておらず、有志の方が運営されています。ですが、私が設置している掲示板もたくさんありまして、スパム書き込みに困っていました。

そこで、掲示板を書き込むときに、あるキーワードを入力しないと書き込みができないように改造してみました。すると、1日に数件あったスパム書き込みがほとんど0になりました。簡単な工夫ですが、効果があるようです。

しかし、キーワードを突破するツワモノもあり、完全ではありません。そこで、スパムを見つけたら削除するように、信頼できるユーザーに掲示板の削除用のパスワードを教えて、見つけた人が削除するようにしました。結局、最後は人力で解決です。

特に、ブログなど自分では改良できないサービスやプログラムを利用している場合は、ブログへのコメントをつけられないように設定を変更するか、それが嫌なら、やはり自分でこまめに削除するしか方法はないようです。

大手のブログだとコメントスパムやトラックバックスパムに対処するために、キーワード入力を求めたり、ブラックリストを用意して対処してくれているようなので、ユーザーの負担は減っているようです。


●Wikiへの悪戯との戦い

なでしこの命令リファレンスは、Wiki形式になっており、ユーザー自身がリファレンスを追加したり、修正できる仕組みになっています。なかなか私一人だけでは、細かくサンプルプログラムを用意したり、詳しい解説を書くことができないので、ユーザーの人たちと協力して、「一緒にマニュアルを育てていく」感じがとても素晴らしいのです。

しかし、最近、悪意のあるユーザーによって、命令リファレンスが真っ白に消されてしまうという事件が起きました。せっかくたくさんのユーザーが協力して作ってきたものが、壊されてしまったのです。定期的にデータをバックアップしていたので、バックアップで補うことで対処したのですが、多くのデータが失われてしまいました。非常に残念です。

それで追加は誰でもできるのですが、削除は信頼できる人のみできるようにプログラムを改良して対処しました。誰でも書き込めるのが、掲示板やWikiの魅力ですが、「誰でも」という部分につけこんで、酷いことをする人がいるというのは、仕方のないことかもしれません。今回のように制限をつけることで対処はできますが、これによって使い勝手が悪くなってしまうのでは本末転倒な気がしますし難しいところです。


●誹謗中傷やユーザー同士の言い争いとの戦い

難しいと言えば、ユーザー同士の感情的な部分への配慮です。掲示板を利用するユーザーが皆優しい気持ちで利用できれば一番なのですが、誰かが誰かのコメントに傷ついたり、言葉の応酬になったりすることがあります。

明らかに宣伝目的であったり、掲示板の意図と違うスパム書き込みは簡単に消すことができますが、冗談なのか本気なのか微妙なコメントだったり、掲示板の常連さんの発言だったりすると、無為に消すことはできませんので、感情に配慮した難しい対応に追われることになります。どうしても解決できない問題が持ち上がると、掲示板の閉鎖に追い込まれることもあります。

他に、法律の問題もあります。著作権を侵害する書き込みがあったり、盗作疑惑もあります。こうした問題に対しては、プログラムの改良だけでは対処できませんので、なんとか運営でフォローしていかなくてはなりません。利用規約を用意したり、ユーザー登録を必須にしたりと個人を特定できるようにすると解決できるかもしれません。


●最後に

以上、何点か問題と解決法を提案しました。感情的な問題は頻繁に起きるものではないのですが、スパム業者との戦いは、イタチごっこ的な問題でありますので、今後もしばらく戦い続けることになるかもしれません。

現在は、簡単な認証キーを導入することでスパム書き込みを排除することができていますが、今後は、メールと同じようにスパム書き込みかどうかを判定するプログラムを導入したり、書き込みの重要度やユーザーがクリックした回数から表示順位を入れ替えたりと、掲示板に特化した仕組みを導入することで対処していこうと思います。

投稿者 kujira : 09:41 | トラックバック

日本語プログラミング言語「なでしこ」をバージョンアップ

クジラ飛行机です。こんにちは。
日本語でプログラミングができるスクリプト言語「なでしこ」を1.40にバージョンアップしました。
最近、バグフィックスが多かったのですが、今回は久々に機能を追加しました。

特に、今まで適当な暗号化しかできなかったのですが、暗号化ライブラリで有名なBLOWFISHを利用した暗号化ができるようにしました。これで、自作アプリでちょっとした暗号化を行う場合にちょっと安心度が上がると思います。(これをネタにコラムを書く予定です。)

プログレスバーは要望が多かったので追加しました。それから、メール送信は、ユーザーの方から熱心な不具合レポートがあったので修正することができました。感謝です。また、実験的に、一部のGUI部品をUNICODEコントロール(Tntコンポーネント)に差し替えてみました。

あと、思い立って、テキスト音楽「サクラ」のMML変換エンジンを梱包することにしました。
これで気軽に自作アプリにBGMがつかられると思います。
学校などでなでしこを試してもらう場合も、楽しく授業ができそうです。

2006/07/02 version 1.40
・プログレスバーを実装。
・「Blowfish暗号化」命令を追加。
・メール送信で添付ファイル名が文字化けするなどの不具合を修正。
・標準のボタンやエディタの一部のGUI部品をUNICODEコントロールに変更。
・MIDI関連の命令を追加。サクラのエンジンを標準添付。

日本語プログラミング言語「なでしこ」
http://nadesi.com/

投稿者 kujira : 21:07 | トラックバック