Perlの最近のブログ記事

この年末に、某システムのデータの圧縮方式を LZH から ZIP に変更した。
ユーザーが複数の CSV ファイルをひとつのアーカイブにまとめアップロードしたものを、サーバ(CentOS)上で自動で展開(解凍)し諸々の処理をするシステムだ。

初版公開が 2005年(俺が独立した翌年に作ったシステムだ(笑))なので、当時の Windows のファイル圧縮方式としては LHA(LZH方式)が主流だった。いや、もう、ZIP形式が LZH形式を駆逐してしまう未来は見えていた頃だが、このシステムを使うユーザーの職場ではまだ LZH形式が主流だったのだ。

しかし、あれから 18年。ついにユーザーより「もう、ZIP形式に変更したい~!」という声が出てきた。そのため、解凍コマンドを lha から unzip に変更した際の苦労話は「unzip の日本語ファイル名問題、なんとか解決」というエントリーにもちょっと書いているので、興味がある人は御一読下さいませ(笑)

件のエントリーでは「展開後の日本語ファイル名を EUC-JP で出力する」苦労話をまとめているが、その後、展開したファイルを正しく読み込めないという不具合が発生した。
ログなどを見て、どうもダブルバイト文字を正しく読めていないようだということはわかった。古い Perl のプログラムなので EUC-JP で書かれており、読み込むファイルの中身も EUC-JP である前提で処理をしているようだ。

ユーザーがアップロードするファイルは、Windows で作られているので文字コードは Shift_JIS である。しかし、プログラム内で Shift_JIS を EUC-JP に変換している箇所が無い。なのに、なんで今まではファイルの中身がちゃんと読めてたの???(どこで文字コードが EUC-JP に変換されてるの???) 

まあ、このエントリーのタイトルに思いっきり「落ち」を書いてるけど、lha コマンドでファイルを解凍するときに同時に EUC 変換していたのだ。lha コマンドにはそういうオプションがある。

lhaコマンドの引数には「オプション」と「コマンド」というのがあり、-e と書けば「圧縮ファイルを展開する」というコマンドを設定したことになる。
そのコマンドの前に e と書けば「テキストファイルの文字コードを EUC と相互変換する」というオプションが設定されたことになり、ファイル展開時に自動的にテキストファイルの文字コードが EUC に変換されるのだ。

具体的には、

/usr/local/bin/lha e -e -i -w=./temp hogehoge.lzh

のようなコマンドを投げていた。「e -e」という部分がそうだ。

いやあ、ハマったわ・・・。まさか lha コマンドが EUC 変換までしているとは思いもしなかった・・・(^^;;;
俺が書いたプログラムだけど 18年も前のものなので記憶が・・・

結局、unzip による ZIP ファイルの解凍のあとに、ファイルの中身を EUC 変換する処理を追加して解決した。

昔の UNIX 及び UNIX ライクな OS の主流の文字コードは Shift_JIS ではなく、まだ Unicode も正式に実装されておらず、EUC-JP の一人勝ち状態だった。だから lha にも EUC 変換オプションなんかが実装されているんだろうなあ(笑)
随分前に作った Linux(CentOS)上で動くプログラム。
LZH ファイルを解凍し、そのファイルをほげほげするのだが、さすがにもう Windows 上で LZH ファイルを作るのもきつくなってきた・・・ということで ZIP ファイル対応を依頼されたのだが(例えば、7-Zip なんかでも LZH 形式には対応してないからな(^^;)・・・ハマった(^^;

yum で入れた unzip は -O オプション(アーカイブ内のファイル名のエンコードが指定できる)が使える(以前のバージョンではパッチを当てないと駄目だった)ので、例えば unzip -Ocp932 -l exsample.zip で、exsample.zip の中の「かわいい中年男性一覧.csv」みたいなファイル名は取ってこれるんだけど、これをディスク上に解凍するとファイル名が化けまくる・・・

ちなみに、プログラムは EUC-JP で書かれている。なにせ、もう、18年前に初版公開したプログラムだからな(笑)。

これ、lha コマンドは EUC-JP でファイル名を出力するパッチが当たっていたので問題なかったんだけど、unzip は「サーバの locale のエンコードでファイル名が作られる」ため、実行サーバの locale である UTF-8 のファイル名となる。

他のプログラムにも影響あるから、なんとか EUC-JP でファイル名を設定してほしいなあ。

しかし、unzip にそのようなオプションはない。結局、unzip を実行する前に、locale を EUC-JP にする形でなんとかなった。

(例)
export LC_CTYPE=ja_JP.eucJP; /usr/bin/unzip -OCP932 -d /tmp exsample.zip

このプログラムは実行後シェルを閉じるので、LC_CTYPE の設定を投げっぱなしだが、同一シェル内で他のコマンドなど実行するのなら、

export LC_CTYPE=ja_JP.UTF-8

で locale を元の UTF-8 に戻すこと。

急に、CGI から送信していたメールが、Gmail に届かなくなった。

maillog を確認すると、

550-5.7.26 This mail is unauthenticated, which poses a security risk to the
550-5.7.26 sender and Gmail users, and has been blocked. The sender must
550-5.7.26 authenticate with at least one of SPF or DKIM. For this message,
550-5.7.26 DKIM checks did not pass and SPF check for [www.exsample.co.jp] did
550-5.7.26 not pass with ip: [210.XXX.XXX.XXX]. The sender should visit
550-5.7.26  https://support.google.com/mail/answer/81126#authentication for
550 5.7.26 instructions on setting up authentication.

ああ、定番の 550 エラー・・・

www.exsample.co.jp ドメインの SPF レコードに、送信元サーバの IP 210.XXX.XXX.XXX が登録されていないので、怪しいからメールは受け取らんよ・・・という Gmail のエラー。

最近、セキュリティ対策でサーバ構成が変わって、www.exsample.co.jp が別のサーバの CNAME になったので(お客さんのサーバなので、俺の権限ではどうしようもない)、www.exsample.co.jp の TXT レコードが書けんのよね。なので、その中に SPF レコードも書けず・・・

ちなみに、example.co.jp の SPF レコードは存在する。

# nslookup -q=TXT exsample.co.jp

と引いてみると、

exsample.co.jp   text = "v=spf1 ip4:202.XXX.XXX.XXX ip4:163.XXX.XXX.XXX ip4:210.XXX.XXX.XXX include:spf.securemx.jp ~all"

と返ってくる。
エンベロープ From を admin@www.exsample.co.jp から admin@exsample.co.jp に変えてやればいいというわけだ。

CGI の中では、

    $mail_data = <<EOM;
From: admin@exsample.co.jp
To: hogehoge@gmail.com
Subject: TEST MAIL
MIME-Version: 1.0
Content-type: text/plain; charset=ISO-2022-JP
Content-Transfer-Encoding: 7bit
X-Mailer: CGI-Script

test death.

EOM

    if (!open (MAIL,"| sendmail -t")) {
        print "Error : Mail Send\n";
    }

    print MAIL $mail_data;
    close(MAIL);

のように sendmail でメール送信をしている。

ここで、sendmail の引数に -f を追加してやれば、エンベロープ From を書き換えることができる。

具体的には、↓こう。

    if (!open (MAIL,"| sendmail -t -f admin@exsample.co.jp")) {
        print "Error : Mail Send\n";
    }

これで、エンベロープ From には admin@exsample.co.jp がセットされ、Gmail は example.co.jp の SPF レコードを参照し、万事解決である(笑)
以前 Perl で組んだシステム上からツイートをする必要が出てきたので、久しぶりにテスト用のボットを作ってみるか・・・と思って、Perl の Twitter API v2 対応のモジュールを探してみたけど・・・

無い・・・

@perl_api の過去ツイートで、2021/04/23 に「Twitter APIv2のサポートは進行中です。早期アクセスのために、GitHubのapi-v2ブランチから今すぐ使用できます。ディスカッションに参加して、Twitter::API(またはNet::Twitter/Lite)を使用するアプリのスムーズな移行を確実にしてください。」というのはあるが、試しに Twitter 関係の Perl モジュールをインストールして、Net/Twitter/API.pm の中を見てみたけど、v1.1に関する記述しかないみたい・・・

未だ GitHub に対応進行中ソースが存在するだけなのか?

Twitter 公式の「Developer Platform」ページを確認すると、「Community tools and libraries for v2」の一覧の中には、C#.NET、Go、Java、JavaScript (Node.JS) / TypeScript、Kotlin、PHP、PowerShell、Python、R、Ruby しかない・・・(v1.1にはちゃんと Perl もあるのに)

だいたい、Kotlin(コトリン)とか、何?(ああ、Android アプリ開発でメジャーな言語なのか(^^;)

仕方ない。Perl の既存アプリの中で編集だけして、その中から呼び出されるツイート投稿プログラムは Python で書こう。

まだ v1.1の API も使えるみたいだけど、いつ使えなくなるかわからんからなあ・・・
ちょっと仕事の関係で Perl の GD::SecurityImage モジュールをインストールしなくちゃいけなくなって、どうするんだっけ?とググったら、12年前の自分の記事がヒットした。


とか読むと、なんかインストールに七転八倒してるな(笑)

勝手のよくわからないレンタルサーバというのもあったんだろうけど、なんかソースから make しようとしてるし。

今回は、試しに全部 yum で入れてみたら一発でうまくいった。

# yum -y install gd
# yum -y install gd-devel
# yum -y install perl-GD
# yum -y install perl-GD-SecurityImage

perl-GD は入れずに、いきなり perl-GD-SecurityImage のインストールすればいいと思うけど、perl-GD 入れたら SecurityImage も入るのかと思ってたのよね。perl-GD-SecurityImage でインストールが必要であった。

ああ、便利な世の中や。

でも、国内インターネットサービス黎明期に、せっせとソースを make してはサーバを構築していた身からすると、なんか yum でポンっと入れちゃうのって罪悪感を覚えるというか、人間、こんなに怠慢でいいのか?とか思っちゃうのよね(笑)

そういう気持ちわかる人、けっこういると思うけど(笑)
今回の LINE API テストにつかった Perl ソース(PSGI 対応)の bot.psgi を載せておく。
API リファレンスに載っているソース例を元に作成した。
前回のエントリーを書いてから、メッセージの出力を追加してるけど)

use strict;
use warnings;
use utf8;
use LINE::Bot::API;
use LINE::Bot::API::Builder::SendMessage;
use Plack::Request;

my $channel_secret = '84xxxxxxxxxxxxxxxxxxxxxxxxxxxxec';
my $channel_access_token = '8sXxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxcDnyilFU=';

my $bot = LINE::Bot::API->new(
channel_secret       => $channel_secret,
channel_access_token => $channel_access_token,
);

sub {
my $req = Plack::Request->new(shift);

unless ($bot->validate_signature($req->content,
$req->header('X-Line-Signature'))) {
return [200, [], ['bad request']];
}

my $events = $bot->parse_events_from_json(
$req->content);
foreach my $event (@{ $events }) {
if ($event->is_user_event && $event->is_message_event
&& $event->is_text_message) {

my $messages = LINE::Bot::API::Builder::SendMessage->new;
$messages->add_text( text => $event->text );
$messages->add_text( text => 'って言ったのね?');
my $res = $bot->reply_message($event->reply_token,
$messages->build);
}
}

return [200, [], ["OK"]];
};

これで、

20200512_line1.jpg

こんな感じに、ユーザが入力した文字を復唱したあとで、「って言ったのね?」と問いかけるウザい形に(笑)。

ポイントは、use utf8 と宣言して、プログラム内に記述される文字列リテラルがすべて「flagged utf8」(utf8 フラグ有効)になるようにすること。
LINE Messaging API に送る文字列は utf8 フラグ有効にしたものでないと駄目。use utf8 してないと、LINE 画面で文字化けする。

まあ、use Encode 宣言して、ひとつひとつ Encode::decode('utf8', 'って言ったのね?') という具合にしても(多分)一緒だけど。いちいちするのは面倒なので、use utf8 した方がいいだろう。

さて、LINE がらみの提案をしたいお客さんのサーバでは PSGI サーバが使えないので、CGI 版に直してみるかな。

<追記>
ちょっとソースを転記したとき、コピーミスがあったので修正した(2020/05/13 12:00)
いやあ、やっと LINE Messaging API を使った「オウム返し bot」がちゃんと動いた。

試しに Perl でテストプログラムを作ってみようと昨夜手をつけたんだけど、これがなかなかうまく行かなくて(^^;

公式 API リファレンスに載ってるスクリプト例が PSGI(Perl Web Server Gateway Interface)前提になってるんで、CGI 形式になおしてもよかったんだけど、まあ、せっかくなんで PSGI 使ってみようかなっと。その分よけいに時間がかかってしまった(^^;

やることは、

    1. CPAN から Perl モジュールを簡単にインストールするための cpanm のインストール
    2. Plack インストールの前準備(openssl-devel、expat-devel などを yum で入れておく)
    3. Plack(PSGI サーバソフトウェア)のインストール(cpanm で、Task::Plack、XMLRPC::Transport::HTTP::Plack をインストール)
    4. LINE API 関係のモジュールをインストール(cpanm で、LINE::Bot::API をインストール)
    5. Apache に PSGI サーバへのリバースプロキシ設定を追加(https://www.hoge.jp/line_api/ にアクセスがあったら、http://localhost:5000/ に転送・・・みたいな)
    6. API を使うチャンネルを LINE Developersコンソールで作成
    7. チャンネルの設定(基本設定、Webhook やチャネルアクセストークンなど Messaging API の設定)
    8. プログラム作成(GitHub 上の「LINE::Bot::API - SDK of the LINE Messaging API for Perl」にサンプルプログラムあり)
    9. Apache Web サーバ起動
    10. PSGI サーバ起動(例:plackup --max-workers 30 --port 5000 -a bot.psgi&)
    11. LINE でこのチャンネルと友達になる
    12. トーク画面で話しかけて、同じ言葉をチャンネル側が返してくるか確認

って感じ。けっこう色々あるっしょ?

20200511_line1.jpg
これがなかなか大変。Task::Plack のインストールはかなりの数のモジュールがインストールされるので時間がかかるし、「チャンネルの設定」って一行でさらっと書いているけど、アイコンとかチャンネル名とかの基本情報は LINE Official Account Manager で設定するし、Webhook やチャネルアクセストークンの発行などは LINE Developers で行う。どっちで何を設定できるのかよくわからんし、飛んだ先のページからの戻りリンクが無かったり、なんか手間取った。

結局、うまく行かなかったのも、チャネルアクセストークンの発行が正しく行われてなかったからのようだ。ずっとうまく行かなくて悩んでいたのだが、トークンを再発行してプログラムに設定したら、あっけなく上手く行った。

PSGI も初めてだったので、その仕組から調べたので時間がかかった。素直に PSGI のソースを CGI に書き直した方が早かっただろう(笑)
ググっても、ngrok を利用する記事が多くて、最初は PSGI のこともよくわからなかったので、何が何やら(^^;・・・

まあ、そのうち、ルータの内側の PSGI サーバへ外部から直接アクセスするために ngrok というトンネリングサービスを使っていることや、つまりは PSGI サーバは Java の Tomacat みたいなアプリケーションサーバ(のようなもの)なのか・・・とかそういうことがわかってきたので、「うちのテストサーバはグローバルIPアドレス空間にいるので ngrok なんか使わずに、Apache で Reverse Proxy 設定してやればいいだけじゃん」と。そこまで考えが至るにもけっこう時間がかかった(^^;

疲れた(^^;

具体的な設定やプログラムについては追々書いていこう(笑)
もう10年近く前に作ったシステムの移行をしているのだけど、その中に UDP パケットでデータを受け取っているプログラムがある。firewall の設定をしたり、ちょっとだけ新サーバに合わせてそのプログラムの受信部分を修正したので、疎通確認だけでもしときたいなっと。Perl で簡単なプログラムでも作ろうと思ったんだけど、念の為にググってみると、ちゃんとそういうプログラムが公開されているね。


もう、そこに載ってるソースそのまま(スコープがグローバルしかないので、変数宣言の my だけ外すという繊細さを見せてるが(笑)>俺)にコピー。

#!/usr/bin/perl

use Socket;

$ipstr = $ARGV[0];
$port = $ARGV[1];
$msg = $ARGV[2];

$ipaddr = inet_aton($ipstr);
$sockaddr = pack_sockaddr_in($port, $ipaddr);
socket(SOCKET, PF_INET, SOCK_DGRAM, 0);
send(SOCKET,$msg , 0, $sockaddr);

無事、テスト終了。

最近 Perl もあまり触ってないので、これだけのコード書くにも色々調べないと駄目だったと思うので、大変助かりました。ありがとうございます>ProjectLiliO
もう 8年前に作った Perl で書いたシステムを CentOS 9 サーバに移行する。

DBD/DBI を始め、色々と Perl モジュールをインストールしないといけないのだが、まあ、ほとんど yum で入れられるので大した手間ではない。

んが、日本語のコード変換に使用している、

Jcode;
MIME::Words

にはいつも苦労させられる。標準の yum リポジトリに含まれていないからだ。
(Jcode なんか、中で Encode 呼んでるだけなんだから入れなくてもいいやろみたいな素人意見は却下。use Jcode している全ソースを修正する暇も金もない。けっこう巨大なシステムなのである。個人が趣味で作っているシステムとは規模が違うのだよ)

CPAN からなら入れられるが依存関係を潰しながら入れるの大変なので、いつもは yum に RepoForge(旧RPMForge)リポジトリを追加してインストールする。んが、なんと 2016年で RepoForge リポジトリの提供は終わったそうな・・・
「え?この間、サーバ移行したときに使ったけど?」と思ったが、その作業をしたのは 2015年だった(^^;

というわけで、EPEL(Extra Package for Enterprise Linux)リポジトリを使って今回は入れてみる。EPEL は Fedora コミュニティの有志によって作成されたものだ。ありがたや、ありがたや。

・EPELリポジトリの追加

# yum -y install epel-release

・Jcode のインストール

# yum --enablerepo=epel -y install perl-Jcode

・MIME-Words のインストール

EPELリポジトリにも perl-MIME-Words のようなパッケージはない。でも、そう言えば CPAN でインストールするときは install MIME::Words ってやってたけど、MIME-tools-5.XXX.tar.gz とかが読み込まれていたな・・・と。

# yum --enablerepo=epel -y install perl-MIME-tools

ちゃんとインストールされたか確認してみる。

インストール前は use しようとすると、

# perl
use MIME::Words qw (:all);
Can't locate MIME/Words.pm in @INC (@INC contains: /usr/local/lib64/perl5 /usr/local/share/perl5 /usr/lib64/perl5/vendor_perl /usr/share/perl5/vendor_perl /usr/lib64/perl5 /usr/share/perl5 .) at - line 1.
BEGIN failed--compilation aborted at - line 1.

のように「そんなモジュールは見つからない」と怒られていたが、

# perl
use Jcode;

# perl
use MIME::Words qw (:all);

どちらもエラーは出なくなった。ええがな、ええがな。

ちなみに、そのまま EPEL リポジトリを有効にしていると、標準リポジトリと競合して問題が発生することがあるので、また必要なときまで無効にしておく。

・EPELリポジトリの無効化

以前は直接設定ファイルを触っていたけど、便利なコマンドがあったのね。

# yum-config-manager --disable epel

もし yum-config-manager が入っていなかったら、yum -y install yum-utils で入れる。
リストリファレンス(参照配列)やハッシュリファレンス(参照連想配列)は Perl の鬼門だ。

リファレンス(参照)の考え方を学ぼうとした時、言語が Perl だったら多分理解する前にギブアップすると思う(笑)

Perl は変数の前にシジルと呼ばれる記号を付けて、その変数の種類(という言い方が正しいのかどうなのか)を指定する。これは Perl アンチにとっては「Perl の駄目なところ」だし、Perl 信者にとっては「Perl の良いところ」だ。
まあ、俺は好きだけどね。このお陰で、予約語と変数名がぶつかることがないので。

ちなみに、$ が付いているのがスカラー変数(文字や数値などの一つの値がセットされる変数)、@ が配列(リスト)、% が連想配列(ハッシュ)である。

しかし、これがまた Perl 初心者の人がソースを読む時の障害にもなるんだよねえ。特にリファレンスを使おうとすると、$、@、% などのシジルに加えて、リファレンスの \$、\@、\% や、デリファレンスする時の $$、@$、%$ のようなシジルも出てきてもうわやくちゃ(笑)
シジルだけで、それが配列なのか配列リファレンスなのか理解せえや!の世界だ。
リファレンスとデリファレンスの、どっちが $@ だったか \@ だったかもしばらく使ってないと忘れちゃうしね。

リファレンスの勉強がしたければ C言語とかで学ぶことをオススメします(笑)

で、いつも多重リファレンスの時の書き方アレコレを忘れてしまうので、このブログにメモっとく。

$oya ... 一番大きな配列リファレンス。つまり親。
$ko1 他 ... $oya の要素のひとつとなる配列リファレンス。つまり子。
$mago11 他 ... $ko の要素のひとつとなる連想配列リファレンス。つまり孫。

普通の配列とはリファレンスの宣言は以下のように異なる。

my @array = (); # リスト
my %hash = (); # ハッシュ
my $array = []; # リストリファレンス
my $hash = {}; # ハッシュリファレンス

各リファレンスへの値のセットと抽出の仕方を Perl のコードにしてみる。

    my $oya       = [];   # リストリファレンスの宣言

    my $ko1       = [];   # リストリファレンスの宣言
    my $mago11    = {};   # ハッシュリファレンスの宣言
    my $mago12    = {};   # ハッシュリファレンスの宣言

    my $ko2       = [];   # リストリファレンスの宣言
    my $mago21    = {};   # ハッシュリファレンスの宣言

    $mago11->{'01'} = 'abc';   # ハッシュリファレンス mago11 に値をセット
    $mago11->{'02'} = 'def';   #  〃
    $mago11->{'03'} = 'ghi';   #  〃

    $mago12->{'01'} = 'jkl';   # ハッシュリファレンス mago12 に値をセット
    $mago12->{'02'} = 'mno';   #  〃

    push @$ko1, $mago11;       # 子リストリファレンスに孫ハッシュリファレンスを push
    push @$ko1, $mago12;       #  〃

    $mago21->{'01'} = 'pqr';   # ハッシュリファレンス mago21 に値をセット
    $mago21->{'02'} = 'stu';   #  〃
    $mago21->{'03'} = 'vwx';   #  〃

    push @$ko2, $mago21;       # 子リストリファレンスに孫ハッシュリファレンスを push

    push @$oya, $ko1;          # 親リストリファレンスに子リストリファレンスを push
    push @$oya, $ko2;          #  〃

    # 親リストリファレンスから子リストリファレンスの抽出
    # リファレンスの要素数を確認するには、デリファレンスしてスカラー値を取得
    for ($i = 0; $i < scalar(@$oya); $i++) {

        # 一時リストリファレンスに子リストリファレンスをセット
        my $array    = [];
        $array       = $oya->[$i];

        # 子のリストリファレンスから孫ハッシュリファレンスを抽出
        # リファレンスの要素数を確認するには、デリファレンスしてスカラー値を取得
        for ($j = 0; $j < scalar(@$array); $j++) {

            # 一時ハッシュリファレンスに孫ハッシュリファレンスをセット
            my $hash    = {};
            $hash       = $array->[$j];

            # keys でハッシュキーを抜き出すには、デリファレンスする
            foreach $key(keys %$hash) {

                print "キー=" . $key . " 値=" . $hash->{$key} . "\n";

            }

        }

    }

ちなみに、上記コードではリファレンスしか使っていないが、通常の配列(リスト)に連想配列(ハッシュ)をセットするには、セットするハッシュをリファレンス化する。

    my @ko1       = ();   # リストの宣言
    my %mago11    = ();   # ハッシュの宣言
    my %mago12    = ();   # ハッシュの宣言

    $mago11{'01'} = 'abc';   # ハッシュ mago11 に値をセット
    $mago11{'02'} = 'def';   #  〃
    $mago11{'03'} = 'ghi';   #  〃

    $mago12{'01'} = 'jkl';   # ハッシュ mago12 に値をセット
    $mago12{'02'} = 'mno';   #  〃

    push @ko1, \%mago11;     # ハッシュリファレンスとしてセット
    push @ko1, \%mago12;     # ハッシュリファレンスとしてセット

    foreach $ko(@ko1) {      # リストからハッシュリファレンスを1件読み出し

        # keys でハッシュキーを抜き出すには、デリファレンスする
    foreach $key (keys %$ko) { 

            print "キー=" . $key . " 値=" . $ko->{$key} . "\n";

    }

    }

こんな感じ。

俺的には最初から最後までリファレンスで処理するのが好み。リファレンスにしたりデリファレンスしたりしてるとわけわかんなくなる(^^;

このアーカイブについて

このページには、過去に書かれたブログ記事のうちPerlカテゴリに属しているものが含まれています。

前のカテゴリはAIR/Flexです。

次のカテゴリはPHPです。

最近のコンテンツはインデックスページで見られます。過去に書かれたものはアーカイブのページで見られます。

月別 アーカイブ

電気ウナギ的○○ mobile ver.

携帯版「電気ウナギ的○○」はこちら