WINAMP 5.55 公開

http://www.winamp.com/

 ipod関連の機能が追加されたWINAMPの最新バージョンが公開されたようです。

 これで終了時に一般保護エラーがでてしまうバグなどは改善されたのか不安ですが,EeePC901に入れて試す価値がありそうです。

Comet技術

Lingr and Comet – 技術解説編
Lingr and Comet – 技術解説編:江島健太郎 / Kenn's Clairvoyance – CNET Japan

 これを読んで思うのは,よくこんなおもしろいアイデアを考えたもんだとおもう。考え方としては単純だが,こんな考えができるのも,今世の中にある様々な技術を熟知しているからこそなんだと思う。

 リクエストに対してレスポンスを返さずにそのまま持っておいて,ある程度リクエストがたまったらいっきに各クライアントへレスポンスを返すのがComet技術。

 これをやるとなると,タイムアウトにはならないのか,プロバイダによる同時接続数制限などがちょっと心配になる。でも,それはそれでタイムアウトになったらもう一度リクエスト送るだけで解決できるのかもしれない。

 comet技術とIRCのプロトコルを組み合わせたりするのを考えるだけで楽しくなってしまうのはなんなんだろう・・・。

IEコンポーネント制御はWeb2.0よりすごいかもしれない

IEコンポーネントの使い方 [VC++の使い方

 ここのサイトで詳しく説明されているIEコンポーネントの使い方だが,特にJavascriptのようにIEコンポーネントに表示されている内容自体を,自由に書き換えたりすることができるインターフェイスについて,詳しく書かれている。

 これを読んでおもったのだが,javascriptがHTMLを書き換えられるのではなく,もともとブラウザエンジンというものはinnerHTMLという書き換えるためのメソッドが備わっていて,それをjavascriptが“ただ”呼び出しているだけなんじゃないかと思ってきた。そうなると,今まで私は,javascriptが最強だと勘違いしてたのかもしれないと,薄々おもうようになってきた。

 ajaxによってweb2.0とも言われ,インターネットに革新を巻き起こしたjavascriptだが,よく考えてみるとそれは二次的な利用で,直接ブラウザインターフェースから提供されているメソッドを利用しているわけではない。

 そこで私は思った。IEには4.0からIEコンポーネントが利用できるようになったわけだが,もちろん,COMインターフェースなのでinnerHTMLなど様々なメソッドが用意されている。このインターフェースをブラウザの表示のためではなく,innerHTMLのデータを解析し,その結果をアプリケーションの画面として表示させれば,HTMLに依存することない様々な制御ができるのではないのかとおもう。

 例えば,Lingrというajaxを利用したIRCにも似たブラウザ上のチャットサービスだが,このサイトへIEコンポーネントを利用しアクセスし,ログを取得し,自作したアプリケーション画面に表示させたらどうだろうか。

 メンバーリストのエレメントも取得し,WindowsのListboxを使って表示してみたり,入力ボックスをINPUTにしてみたりと,ここまでやってしまうと,それはもうブラウザ上のサービスとは思えなくなる。

 実際にIEでログインして会話してることには代わりはないが,明らかにこれはクライアントとしか見えなくなる。

 

 今のところ,このような処理を行っているものとしてはGrease Monkeyがある。これはjavascriptを使って現存のウェブページの表示を自分で自由にローカルに書き換えられるというものだが,IEコンポーネント制御は,GreaseMonkeyの機能をアプリケーション開発レベルまで引き上げたようなものだろう。Web3.0の時代はもしかしたらこういったものになってくるのだろうか。

暗号化モジュール

 以前つくって,後になってバグがでてしまっていた暗号化モジュールなんですが,やっと作り直すことができました。ほとんどスクリプトを書き換えたのでかなり大変でしたが,うまく動作してくれているようです。

詳細

ライセンスご自由にお使いください。(NYSL
対応Hot Soup Processor ver.3.0 以上
種別HSPモジュール
/* Copyright (C) 2007-2009 By As(http://hp.vector.co.jp/authors/VA034028/) 文字処理機能付き暗号化モジュール ascrypt  //文字列の符号化を行う ascrypt_enc 暗号化を行う文字列の入った変数, キーの入った文字列型変数, 文字処理を行うアスキーコードが入った配列変数*1 //文字列の復号化を行う ascrypt_enc 暗号化を行う文字列の入った変数, キーの入った文字列型変数, 文字処理を行うアスキーコードが入った配列変数*1 *1 配列変数の0番目の配列は0x00で予約されているため,使用することは出来ません。1番目以降を使用してください また1番目以降においても,0x00~0x80までは使用できません //SAMPLE a = "test" key = "key" word = 0x00, 0x0a, 0x0d //改行させないようにする ascrypt_enc a, key, word */#define global ascrypt_enc(%1, %2, %3, %4=0xff) ascrypt 0, %1, %2, %3, %4#define global ascrypt_dec(%1, %2, %3) ascrypt 1, %1, %2, %3#module module_ascrypt//キー生成#deffunc ascrypt_keygen array _key, var _randomize, var _keystr, local s1, local s2, local s3, local s4, local s5
s1 = _keystr //キーの文字列が代入されるs2 = strlen(s1) //キーの文字数が代入される_randomize = 1randomize s2 //乱数の初期化repeatif rnd(2):s5=1:else:s5=-1 //ランダムに入れ替えるs3 = strf("%d", cnt)if instr(s3, 0, "3")!-1{//繰り返し回数に3が付く場合実行_key(cnt)=-rnd(33)*s5^rnd(s2)if _key(cnt) == 0 : _key(cnt) = 1continue}if cnt\5=0{//5の倍数の場合実行_key(cnt)=-rnd(55)*s5^rnd(s2)if _key(cnt) == 0 : _key(cnt) = 1continue}
_key(cnt)=peek(s1, s4)*s5^rnd(s2) //キー配列if _key(cnt) == 0 : _key(cnt) = 1_randomize+=rnd(_key(cnt)*_key(cnt))+1 //乱数初期化用数値s4++ //キーの位置のカウントif s4 = s2+1 : break //キーの最後まで行ったらループを抜けるloopreturn _randomize//単純な暗号化を行う(関数)#deffunc func_ascrypt_ecrypt int _type, var _var, int _randomize, int _rect, int _shift
randomize _randomize
repeat strlen(_var)switch _typecase 0poke _var, cnt, peek(_var, cnt) +rnd(_rect) + _shift
swbreakcase 1poke _var, cnt, peek(_var, cnt) -rnd(_rect) - _shift
swbreak
swend
loopreturn//単純な暗号化を行う(命令)#defcfunc ascrypt_ecrypt int _type, str _str, int _randomize, int _rect, int _shift, local s1
s1 = _str
randomize _randomize
repeat strlen(s1)switch _typecase 0poke s1, cnt, peek(s1, cnt) +rnd(_rect) + _shift
swbreakcase 1poke s1, cnt, peek(s1, cnt) -rnd(_rect) - _shift
swbreak
swend
loopreturn s1//処理文字の修正#deffunc ascrypt_worddisp var _var, array _word, int _wordlen, int _rect, int _shift, int _size_rect, int _size_shift, local s1, local s2, local s3, local s4, local s5, local s6, local s7, local s8, local s9, local s10
s1 = strlen(_var) //符号化されたデータの全体サイズs2 = int("$"+ascrypt_ecrypt(1, strmid(_var, s1-8, 8), s1, _size_rect, _size_shift)) //符号化する文字列のサイズif (s2 >=s1-_wordlen*8)|(s2 <=0) : return 0 //エラー回避s3 = strmid(_var, s2, s1-s2-8) //抽出した文字位置情報if s3 == "" : return 0 //エラー回避func_ascrypt_ecrypt 1, s3, s2, _rect, _shift //文字位置情報の復号s4 = strlen(s3) //抽出した文字位置情報のサイズrepeat _wordlen
s6 = cnt
s7 = int("$"+strmid(s3, s5,8))
repeat limit(s7, 0, s7)
s5 += 8poke _var, int("$"+strmid(s3, s5, 8)), _word(s6)
loop
s5 += 8loop
memset _var, 0x00, s1-s2, s2 //データ末端の位置情報を削除するreturn s2//符号化&暗号化を行う//ascrypt フラグ(0=符号化 | 1=復号化), 符号化もしくは復号化する文字列型変数, 鍵として使用する文字列, 文字処理を行うアスキーコードが入った配列変数#define size_cirect 26 //文字位置情報を符号化するための乱数範囲(size_cirect+size_shiftで26以上になるとエラーになります)#define size_shift 0 //文字位置情報を符号化するためのシフト範囲#define addcharinfo(%1, %2) s3+=%1 : s3+=strf("%08x", %2)#deffunc ascrypt int _type, var _var, var _key, array _word, int _afterword, local s1, local s2, local s3, local s4, local s5, local s6, local s7, local s8, local s9, local s10, local s11, local s12, local s13, local s14, local s15, local s16, local s17, local s18, local s19, local s20, local s21if (_var == "")|(_key == "") : _var = "" : return 0if _word(0) != 0x00 : dialog "処理する文字の配列変数の0番目に0x00以外の文字を指定することは出来ません",1,"ascryptエラー" : returns1 = length(_word)//文字位置情報で該当の文字にならないようにするs2 = 255repeat s1if _word(cnt) > s3 : s3 = _word(cnt)if _word(cnt) < s2 : s2 = _word(cnt)
loop
s4 = limit (s3-s2 + 1, 1, s3-s2 + 1)
s5 = limit (255 - s3 - s4, 1, 255 - s3 - s4)if _type == 0 {//置き換える文字列if (_afterword == 0x00)|(_afterword>255){
s6 = 0xff} else {
s6 = _afterword
}
}
sdim s7, 8 : sdim s8, 8 : sdim s9, 8 : sdim s10, 8, s1 : dim s11, s1
ascrypt_keygen s12, s13, _key //符号化に使われるキーを生成する//符号化データ 仕様//<符号化されたデータ><0x0D文字があった位置 int型ffffffff>...<0x0D文字の数 ffffffff><0x0D文字があった位置 int型ffffffff>...<NULL文字の数 ffffffff><int型の符号化されたデータのサイズ ffffffff><EOF>s14 = length(s12) //キー配列の数switch _typecase 0//符号化する場合s9 = strlen(_var) //符号化する文字列のサイズswbreakcase 1//復号化する場合ascrypt_worddisp _var, _word, s1, s5, s4, size_cirect, size_shiftif stat == 0 {//エラー処理_var = ""return 0}
s9 = stat //符号化する文字列のサイズswbreak
swend
randomize s13 //乱数の初期化repeat limit(s9, 0, s9) //符号化する文字列のサイズの分だけループif rnd(2) : s15 = 1 : else : s15 = -1 //ランダムに入れ替えるswitch _typecase 0//符号化poke s16, 0, peek(_var, cnt) + (rnd(s12(s17))+rnd(s13))*s15 //s16に一時的に符号化した文字を書き込みs18 = peek(s16, 0)//文字の処理を行うs19 = 0s20 = cnt
repeat s1if s18 == _word(cnt) {
poke _var, s20, s6 //書き換えるs10(cnt) += strf("%08x", s20)
s11(cnt)++
s21 += 8s19 = 1break}
loopif s19 == 0 : poke _var, cnt, s16 //符号化データの書き込みswbreakcase 1//復号化poke _var, cnt, peek(_var, cnt) - (rnd(s12(s17))+rnd(s13))*s15 //直接符号化データを復号化swbreak
swend
s17++ //キーコードのカウントif s17>=s14 : s17 = 0 //キーコードのループloopif _type == 0{//符号化する場合sdim s14//ascrypt_worddisp_addinfo s14, s1 //位置情報の追加repeat s1
s14 += strf("%08x", s11(cnt))
s14 += s10(cnt)
s21 += 8loop
s12=s9 + 8 + s21 //文字情報も含む符号化データ全体のサイズmemexpand _var, s12 //メモリの再確保//符号化データの代入_var+=ascrypt_ecrypt(0, s14, s9, s5, s4) + ascrypt_ecrypt(0, strf("%08x", s9), s12, size_cirect, size_shift)
}return s12
#global#define SAMPLE 0/////サンプル1///////////////////////////////////////////////////////////#if SAMPLE == 1sdim a,4080sdim key,1024sdim b,4080key="test"a="test"word=0x00, 0x0A, 0x0Dinput key,ginfo_winx,21mesbox a, ginfo_winx, 200, 3button gosub "暗号化",*go
button gosub "復号化",*go2
mesbox b, ginfo_winx, 200, 3stop
*go
b=a
ascrypt_enc b, key, word
objprm 4,breturn*go2
a=b
ascrypt_dec a, key, word
objprm 1,areturn#endif/////サンプル2///////////////////////////////////////////////////////////#if SAMPLE == 2sdim a
sdim key
sdim b
a="test"key="test"word = 0x00, 0x0a, 0x0dascrypt_enc a, key, word
sdim key2, 256sdim key, 256b=a
input key2,ginfo_winx,21mesbox a, ginfo_winx, 200, 4//button gosub "暗号化",*gobutton gosub "復号化",*go2
mesbox b, ginfo_winx, 200, 4gsel 0,1stop
*go
b=a
ascrypt_enc b, key2, word
objprm 3,breturn*go2
b=a
ascrypt_dec b, key2, word
objprm 3,breturn#endif///////サンプル3//////////////////////////////////////////////////////////////#if SAMPLE == 3font msgothic,14,16 : pos 5,5objmode 2 : objsize ginfo_winx-10,200a={" ascryptをお試しいただき有難う御座います。この暗号化モジュールには文字処理機能が付いており,ヌル文字(0x00)や改行コード(0x0a,0x0d)などの文字列操作でなにかとバグの原因となってしまう文字をバグが発生しないほかの文字と置き換えることが出来るようになっています。
 例えば,ヌル文字と改行文字を暗号化されたデータに入れたくない場合は下のようにします。
\ta = "test"\tkey = "我輩は猫である。"\tword = 0x00, 0x0a, 0x0d\tascrypt_enc a, key, word
 aが暗号化される元のデータが入った文字列型変数,keyは復号化で必要になる鍵が入った文字列方変数,wordが文字処理を行う文字が入った配列変数です。この文字処理配列変数に含まれている文字コードは暗号化データには含まれることがありません。また,配列変数の0番目の配列は0x00で予約されているため,使用することは出来ません。ユーザーは,1番目から文字コードを指定する必要があります。
 また,同スクリプトには3つのサンプルが含まれています。「#define SAMPLE *」にてサンプルを切り替えることができます。"}key = "我輩は猫である。"#if 1//全ての文字を処理するrepeat 256word(cnt) = cnt
loop#else//ヌル文字と改行文字とタブ文字を処理word = 0x00, 0x0d, 0x0a, '\n'#endifascrypt_enc a, key, word, '0xff'
mes "符号化:"mesbox a,,,3b=a
ascrypt_dec b, key, word
mes "復号化:"mesbox b,,,3#endif#undef SAMPLE

W-ZERO3で最大限の録画性能を発揮する設定

Poketの手を使ってデバイスの設定を行い,その上でW-ZERO3[es](WS011SH)の録画性能を調べてみました。

本体メモリを使用した場合

QVGA

  • Jitter : 167ms

QQVGA

  • Jitter : 98ms

SDストレージのディスクキャッシュを無効にした場合

QVGA

  • Jitter : 336ms

QQVGA

  • Jitter : 179ms
SDストレージのディスクキャッシュを1MBだけにした場合

QVGA

  • Jitter : 172ms

QQVGA

  • Jitter : 103ms

FATFS:16384, ReplStore:1024

QVGA

  • Jitter : 161ms
  • ライトキャッシュメモリ有効

FATFS:16384, ReplStore:16384

QVGA

  • Jitter : 282ms
  • ライトキャッシュメモリ有効
FATFS:4692, ReplStore:0

QVGA

  • Jitter : 154ms
  • ライトキャッシュメモリ有効

FATFS:16384, ReplStore:0

QVGA

  • Jitter : 103ms ←Great!!
  • ライトキャッシュメモリ有効

 これは,Jitterの時間が短ければ短いほど動画がかくかくしなくなります。これを見ると,いかに本体メモリに書き込みしたほうが速度が速いかということがわかります。

 しかし,ディスクキャッシュを無効にすると,かなり動画がかくかくしてしまうことには驚きました。W011SHは初期設定でディスクキャッシュが4MB以上になっていて,プログラム実行用メモリが足りませんと表示されてしまい録画できないので,ポケットの手2で設定を無効にしたいところですが,ギリギリのところまでに抑えたほうが無難なようです。

 また,FATFSが最大値になっている箇所がありますが,これは携帯のファームウェアが2.0b以上のものです。

“プログラム実行用メモリが不足しています”といわれたら

ファームウェアが2.0b以下の場合

 たくさんのソフトウェアを起動していたり,SDカードを入れていたりするとプログラム実行用メモリを消費してしまうようです。

 起動しているソフトウェアを減らせば録画できるようになりますが,SDカードを入れている場合に録画できなくなってしまう場合はPoketHand2(ポケットの手2)を使って,外部ストレージのディスクキャッシュを減らすことで録画できるようになります。

ファームウェアが2.0b以上の場合

 SHARPのサイトにW011SH用のアップデートファイルがあり、これによってアップデートを行うことで、空きメモリの必要上限が低く設定されるようになります。

 そのぶんディスクキャッシュにメモリが割り当てられるようになるので、動画がかくかくならないようにある程度割り当てると良い。

 いろいろと試したところ、残メモリが50MB以下になっても動画を撮影することができました。

タグ: W-ZERO3 W011SH ビデオ カメラ PoketHand 録画 Advanced/W-ZERO3[es] es

Advanced W-ZERO3[es]

Wiki記法はメモに便利

 よく見かけるwikiの記法には、“*”や“-”などといった記号を行の先頭に書くものが多く見られます。誰が最初に始めたのやら、この書式を考えた人は本当にすごいと思います。

 おおまかに一般的なWikiの記法を説明すると、 “*”は、大見出しという意味で、HTMLでは“<H1>”タグと同じような意味があります。

*大見出し

 大見出しは、このようにして使います。他にも、様々な記法があり、まとめると

*大見出し
**小見出し
***小小見出し
-箇条書き
--箇条書き2
---箇条書き3
+数字タイプの箇条書き
++数字タイプの箇条書き2
+++数字タイプの箇条書き3

など、いろいろなものがあります。先頭に各記号の数が多いほど、優位度が低くなります。

 

[[aa>http://aa.aa/]]
[[aaa]]

他にも、このように[[]]で囲むことによってリンクの役割を果たすものもあります。

 wikiを使っている人にとっては当たり前のように使っていることだと思いますが、これらの記法は、ちょっとしたメモの時にも意外と便利な場合があります。

 例えば携帯のメモ帳でメモをする場合を考えて見ます。携帯のメモ帳は、文字数は限られていたり、半角スペースを打つのにかなりの手間がかかったり、横スクロールバーがないため、右側で折り返すこともできません。これだと、一般的な文章の書き方に使われる段落をあらわすための字下げ(インデント)がうまく扱えなくなってしまいます。

 うまく改行してあわせたとしても、途中でその文章を変えたくなってしまったとしたら、いちいち改行を消さないといけなくなったりと手間が掛かってしまいます。

f:id:As_hsp:20090216014058g:image

 しかし、これをWikiの記法に変えてみると、このようになります。

f:id:As_hsp:20090216014057g:image

 ずいぶんとすっきりして、インデントによる無駄なサイズの消費も抑えることができました。もし、箇条書きに二重に箇条書きが必要になった場合も、“–”とするだけでいいので、手間が少なくてすみます。

ウィルコムストア

はてなカウンターのURLのテキストを書き換えるGreasemonkey

はてなカウンターのアクセス解析は、リンクがURLのまま表示されますが、それを好きな文字列に書き換えるスクリプト。

例:

<a href="http://hogehogehoge.hoge">http://hogehogehoge.hoge</a><a href="http://hogehogehoge.hoge">ほげほげどっとほげ</a>
//タグ(tdなど), 置き換えるURLまたはホスト名, 置き換え後の名前, フラグ//フラグ 0=デフォルト 1=ボールド 2=URLを指定(http://hogehoge.hoge/*) 3=URLを指定(http://hogehoge.hoge/hoge.html)function rep(_tag, _before, _after, _flag){if (_tag == "")return;if (_before == "")return;if (_after == "")return;var elm = document.getElementsByTagName(_tag);var taglen = elm.length;var as = "";var ae = "";var target = _before;if(_flag == 1){as="<span style='font-weight:bold;color:#00AA00;'>";
ae="</span>";}else if(_flag == 2){target = '<a href="' + _before + '';
as = '<a href="' + _before + '">';
ae = "</a>";}else if (_flag == 3){target = '<a href="' + _before + '">';
as = '<a href="' + _before + '">';
ae = "</a>";}for (var i = 0; i<taglen; i++){if (elm.item(i).innerHTML.indexOf(target,0) != -1){elm.item(i).innerHTML = as + _after + ae;}}}

タグ: Greasemonkey はてなカウンター innerHTML アクセス解析

ポケットの3スティック

 ポケットには携帯と財布を入れている人が大半だと思いますが、私は、常にそれに合わせて3つのスティックを携帯しています。

アルブラン コンシーラ

f:id:As_hsp:20090214223856j:image

 朝忙しいときににきびが出来てて隠すのに大変なときに便利。私は、顔に怪我をしてしまってそれを隠すためにもともとは買ったのですが、最近では傷もだいぶ治ってきて普通ににきび隠しにも使うようになってしまいました。 正直、これが二本目だったりします’笑(失くしたため)

 他にも安いコンシーラを試したりしたのですが、肌の色が合わなかったり、水っぽくて乾燥するとかさかさになって粉っぽくなってしまうものがほとんどのなか、このコンシーラは一度つければ夜までそのまま、べたつくわけでもなくムラがないので非常に気に入ってます。リピーターが多い商品だとおもいます。

Ora2 マウススプレー

 よくある口臭スプレーです。コンビニでたまに見かけたりするのですが飲むタイプのものと比べて、人気商品なのかなかなか売られてるところを見たことがありません。

 だから、ほんとにたまにしか買えないのですが、ちょっとしたときにすぐに使えるのでなかなか便利だったりします。

UNO ナチュラルリップ

[rakuten:kenkoex:10002045:detail]

 またこれもよくあるリップクリーム。正直何でもいいですが、季節限定ですね。これがあるだけでえらい違います。乾燥ってのは体にも悪いので、唇が乾燥しているとこの部屋は乾燥しているんだなーってのがわかります。

LimechatでRSSを取得し新しいエントリーのみを書き込むスクリプト

 Limechat2には、最近新しくスクリプト機能としてjavascriptが扱えるようになりました。そこで、RSSが取得できるんじゃないかと思い、Microsoft.XMLDOMを使用してRSSを読み込み、新しい記事のみを抽出しチャンネルに自動で書き込むスクリプトを書いてみました。

 既に他の誰かが同じようなスクリプトを作っているとはおもいますが、ぐぐってもでなかったので書いてみたってのが本音ですが、他力本願ですねw

 ちなみに、UTF-8で保存しないといけないようです。

//////////////////////////////////////////////////////////////var url=""; //RSSのURLvar channel=""; //RSSエントリーを書き込むチャンネルvar inttime=1800000; //RSSをチェックする間隔(1800000:30分)//////////////////////////////////////////////////////////////var elm_en_old;var max_old;function rssload(flag){var req = new ActiveXObject("Microsoft.XMLDOM");
req.async=false;do{req.load(url);}while(req.innerHTML == "")var root = req.documentElement;var elm_en = req.getElementsByTagName("title");var elm_link = req.getElementsByTagName("link");var hit;var max = elm_en.length;if (flag != 1) {for (var i=0; i<max; i++) {hit=0;for (var ii=0; ii<max_old; ii++) {if (elm_en.item(i).firstChild.nodeValue == elm_en_old.item(ii).firstChild.nodeValue) {hit=1;}}//全てのエントリーに当てはまらなければ(hit==0)、新しいエントリーとし、書き込むif (hit == 0) {send(channel, "" + elm_en.item(i).firstChild.nodeValue + " " + elm_link.item(i).firstChild.nodeValue);}}}max_old = max;
elm_en_old = elm_en;}var tid;function event::onConnect(){rssload(1);
tid=setInterval(rssload,inttime);}function event::onLoad(){rssload(1);
tid=setInterval(rssload,inttime);}function event::onUnload(){clearInterval(tid);}function event::onDisconnect(){clearInterval(tid);}

#追記(2009.2.15)

 スリープモード、休止モードを使用したり、サーバーの接続を切断した場合に再接続するときに比較用のフィードが保持されている変数を初期化するように修正。

#追記(2009.3.11)

 正常に取得できなかった場合処理を繰り返すように修正

 ページが更新しているかどうかを調べるためのコードを入れていないので、間隔を置いて受信することをお勧めします。

タグ limechat2 RSS スクリプト フィード Microsoft.XMLDOM

カテゴリー: IRC