花粉症でお困りの方に

花粉症でお困りの方に、アレグラというおすすめの薬があります。今回はそれの紹介。

アレグラ錠60mg

用量
  • 1日2回、内服、朝・夕食後
  • 1回1錠
用法・効能・注意

アレルギーによるくしゃみ、鼻水、蕁麻疹、皮膚のかゆみなどをやわらげる作用があります。

水酸化アルミニウム、水酸化マグネシウムを含む制酸剤と一緒に用いると、この薬の効き目が弱くなりますので、同時に服用しないでください

使用した感覚

ここは私個人の見解です。詳しくは医師に聞いてください

  • 服用しても眠くならない(これ重要)
  • 服用後も体調が良い
  • 鼻水、くしゃみ、花粉症特有の症状が一切なくなる
  • 薬の効き目が切れ始めると、くしゃみが出始める
  • 効用は大体半日

とりあえず飲んでおけば、花粉の季節ではないときと体調は一緒!

入手方法
  • 病院でお医者さんに処方箋をもらう
  • 薬局で購入
留意事項

薬の正確な情報に関しては各自でしっかりと調べてください。自己責任ですよ、自己責任。


Perlのforeachについてメモ

The foreach statement

Programming Perl Chapter 1(p.34) には

Note that the loop variable refers to the element itself, rather than a copy of the element. Hence, modifying the loop variable also modifies the original array.

とある。

"the loop variable refers to the element itself"

http://d.hatena.ne.jp/perlcodesample/20091120/1246679588 の「コメントに対する回答」には

itouhiroさんのコメント

Perl5の「foreach」は、myをつけても、myをつけた新変数ではなく、配列内部の変数に直接アクセスしてしまうという変なクセがある。だからforeachに限ってmyは無意味。Perlの文法はこういう例外も覚えないとならない

 変数としてはまったく新しいものです。ですから意味はあります。foreachが少し変なのはその変数の内容に配列の要素のエイリアスが設定されるということです。スカラ値のコピーはPerlの処理の中でも遅い部類に入るためスカラ値のコピーをしたくないというのが理由でだと思います。「パフォーマンスを考慮した結果」の例外だと思います。

 でも実際にプログラムをしてみるとわかりますがそれほど困ることはないです。(値を書き換える場合についてはエイリアスがわたってくるということは意識しないといけませんが。)

と回答がある。ちょっとややこしいので、検証してみた結果が以下。勘違いしているとわけのわからないところで嵌りそう。

検証コード
use Data::Dumper;

my @hoge = 1 .. 10;
my @fuga = @hoge;
my @foo  = @hoge;

print "-" x 30 . "\n";
print Dumper \@hoge, \@fuga, \@foo;

foreach (@hoge) {
  $_ += 30;
}

foreach my $item (@fuga) {
  $item += 30;
}

foreach my $item (@foo) {
  my $bar = $item;
  $bar += 30;
}

print "-" x 30 . "\n";
print Dumper \@hoge, \@fuga, \@foo;
output
------------------------------
$VAR1 = [
          1,
          2,
          3,
          4,
          5,
          6,
          7,
          8,
          9,
          10
        ];
$VAR2 = [
          1,
          2,
          3,
          4,
          5,
          6,
          7,
          8,
          9,
          10
        ];
$VAR3 = [
          1,
          2,
          3,
          4,
          5,
          6,
          7,
          8,
          9,
          10
        ];
------------------------------
$VAR1 = [
          31,
          32,
          33,
          34,
          35,
          36,
          37,
          38,
          39,
          40
        ];
$VAR2 = [
          31,
          32,
          33,
          34,
          35,
          36,
          37,
          38,
          39,
          40
        ];
$VAR3 = [
          1,
          2,
          3,
          4,
          5,
          6,
          7,
          8,
          9,
          10
        ];

http://codepad.org/1XvvYiyx で実際の実行結果を確認できます。


Perlでメールを送信するときはEmail::Senderを使いましょうというお話

ことの経緯は http://togetter.com/li/6431 を。 Email::MIME->create() のところうまく書けば良いよ、というお話。

ところが今度は Email::Send 。Email::Send の POD には

WAIT! ACHTUNG!

Email::Send is going away... well, not really going away, but it's being officially marked "out of favor." It has API design problems that make it hard to usefully extend and rather than try to deprecate features and slowly ease in a new interface, we've released Email::Sender which fixes these problems and others. As of today, 2008-12-19, Email::Sender is young, but it's fairly well-tested. Please consider using it instead for any new work.

とある。よって Email::Sender を使うのがよろしいみたい。

経緯に関しては http://gihyo.jp/dev/serial/01/modern-perl/0020 が詳しい。

サンプルコード

sendmail の -f オプションを明示して指定できるようにしているが、普通に使う分には $contents->{from} と $contents->{envelope_sender} は同一で良い(らしい)。エラーメール収集アドレスを別にしたい人は別にするとよい(らしい)。

モバイルでも文字化けせずに送信可。(Docomoのみ確認済み、他キャリアの動作報告あればお願いします) 詳しい方はツッコミお願いします。

#!/usr/bin/perl

use strict;
use warnings;
use utf8;
use Encode;
use Email::MIME::Creator;
use Email::Sender::Simple qw/sendmail/;

my $contents = {
    from    => 'from@example.com',
    to      => 'to@example.com',
    subject => '電子メール',
    body    => 'サンプル',
    envelope_sender => 'envelope_sender@example.com',
};

my $mail = Email::MIME->create(
    header => [
        From    => $contents->{from},
        To      => $contents->{to},
        Subject => encode('MIME-Header-ISO_2022_JP', $contents->{subject}),
    ],
    attributes => { 
        content_type => 'text/plain',
        charset  => 'ISO-2022-JP',
        encoding => '7bit',
    },
    body_str => $contents->{body},
);

sendmail($mail, {from => $contents->{envelope_sender}});

exit;
__END__

PerlでTwitterのOAuthを使うサンプル

TwitterのOAuthClientを下記URLから設定

http://twitter.com/oauth_clients

consumer_keyとconsumer_secretを取得する。

おおまかな流れ

  • index.html からリンクで sample.pl にアクセスし、Twitter の OAuth 許可用のページへリダイレクト
  • OAuth 許可用のページで許否を設定後、sample.pl で設定した callback_url (ここ重要)へリダイレクトされる(この場合はcallback.pl)
  • callback.pl で oauth_token と oauth_verifier を取得し update を試みる
  • 成功であればツイート先へ、失敗であれば Twitter トップページにリダイレクト

コード例

sample.pl
#!/usr/bin/perl

use strict;
use warnings;
use utf8;
use lib '/home/foo/local/lib/perl5';
use OAuth::Lite::Consumer;
use URI;
use CGI;
use CGI::Carp qw/fatalsToBrowser/;

my $q = CGI->new();

my $consumer = OAuth::Lite::Consumer->new(
    consumer_key       => 'YOUR_CONSUMER_KEY',
    consumer_secret    => 'YOUR_CONSUMER_SECRET',
    callback_url       => 'http://example.com/callback.pl', 
    site               => 'http://twitter.com/',
    request_token_path => 'http://twitter.com/oauth/request_token',
    access_token_path  => 'http://twitter.com/oauth/access_token',
    authorize_path     => 'http://twitter.com/oauth/authorize',
);

my $request_token = $consumer->get_request_token();

my $uri = URI->new($consumer->{authorize_path});

$uri->query(
    $consumer->gen_auth_query("GET", 'http://twitter.com', $request_token)
);

print $q->redirect($uri->as_string);

exit;
callback.pl
#!/usr/bin/perl

use strict;
use warnings;
use utf8;
use lib '/home/foo/local/lib/perl5';
use OAuth::Lite::Consumer;
use Encode;
use CGI;
use CGI::Carp qw/fatalsToBrowser/;
use URI;

my $q = CGI->new();

*OAuth::Lite::Util::encode_param = sub {
    my $param = shift;
    URI::Escape::uri_escape_utf8($param, '^\w.~-');
};

my $consumer = OAuth::Lite::Consumer->new(
    consumer_key       => 'YOUR_CONSUMER_KEY',
    consumer_secret    => 'YOUR_CONSUMER_SECRET',
    site               => 'http://twitter.com/',
    request_token_path => 'http://twitter.com/oauth/request_token',
    access_token_path  => 'http://twitter.com/oauth/access_token',
    authorize_path     => 'http://twitter.com/oauth/authorize',
);

my $param_oauth_token    = $q->param('oauth_token');
my $param_oauth_verifier = $q->param('oauth_verifier');

my $access_token = $consumer->get_access_token(
    token    => $param_oauth_token,
    verifier => $param_oauth_verifier,
);

my $res = $consumer->request(
    method => 'POST',
    url    => q{http://twitter.com/statuses/update.xml},
    token  => $access_token,
    params => {
        status => scalar localtime,
        token => $access_token,
    },
);

if ($res->is_success) {
    use XML::Simple;
    my $status = XMLin($res->decoded_content);
    print $q->redirect(
        "http://twitter.com/"
        . $status->{user}->{screen_name}
        . '/status/'
        . $status->{id}
    );
} else {
    print $q->redirect('http://twitter.com');
}

exit;

SSHの切断を防ぐ設定

一定時間経過後にコネクションが切断される場合は ~/.ssh/config に下記の設定を追記すれば切断されなくなる

ServerAliveInterval 120

MP3にID3v2を書き込む

MP3::Tag

MP3のID3を操作するMP3::Tagというモジュールを使う。

http://search.cpan.org/~ilyaz/MP3-Tag-1.12/lib/MP3/Tag.pm

ID3そのものについてはWikipediaのID3タグあたりを参照。

使い方

最小限の実用的な使い方の例

use MP3::Tag;
use LWP::UserAgent;
my $ua = LWP::UserAgent->new();

# 画像データを取ってくる
my $pic = $ua->get("http://tn-skr3.smilevideo.jp/smile?i=8708446")->{_content};

my $mp3 = MP3::Tag->new('tmp.mp3');

# まずはタグを取得する
$mp3->get_tags();

MP3::Tag->config("write_v24" => 1); # ID3v2.4 での書き込みを有効にする 

my $id3v2;

# ID3v2が存在するかを確認する
if (exists $mp3->{ID3v2}) {
    $id3v2 = $mp3->{ID3v2}; # 存在すれば$id3v2に代入
} else {
    $id3v2 = $mp3->new_tag("ID3v2"); # 存在しなければID3v2をつくってやる
}

# TIT2 : Title/songname/content description 
# TALB : Album/Movie/Show title 
# APIC : Attached picture Keys: MIME type, Picture Type, Description, _Data

# add_frameでタグを追加
$id3v2->add_frame("TIT2", "曲名");
$id3v2->add_frame("TALB", "アルバム名");
$id3v2->add_frame("APIC", "image/jpeg", "Cover (front)", "Description", $pic);

# タグを書き込む
$id3v2->write_tag;

ID3v2.4 での書き込みについては write_v24 の項目より。

write_v24

If FALSE (default), writing of ID3v2.4 is prohibited (it is not fully supported; allow on your own risk).

操作できるタグ一覧

http://search.cpan.org/~ilyaz/MP3-Tag-1.12/lib/MP3/Tag/ID3v2-Data.pod#List_of_Complex_Frames

フレーム名が省略されているのでいちいちマニュアルを参照して書く必要がある。


ニコニコ動画のマイリストをMP3に変換してiTunesで便利に使えるmylist2mp3.pl書いた

ソース

http://github.com/punytan/mylist2mp3

保存できる範囲

自分のマイリストであれば次のものが保存できます。

  • sm\d+
  • nm\d+
  • コミュニティ限定の動画(数字のみの動画)

MP3ID3v2タグに、

  • 曲名に動画のタイトル
  • アルバム名にマイリスト名
  • アートワークに動画のサムネイル

が入ります。

使い方

  • Windowsの場合はFFmpegをからDLして、パスの通った場所に展開する
  • そのほかの場合はaptなどからffmpegをインストール
  • mylist2mp3.zip を展開
  • コマンドラインから次のように実行
perl mylist2mp3.pl
  • tmp/mylist_idに一時ファイル、mp3/mylist_idに変換されたものが入ります

Perlで(UTF-8)文字列を扱う基礎中の基礎

お約束

#!/usr/bin/perl
use strict;
use warnings;
use utf8;
use Encode;

日本語を扱う可能性があるプログラムのすべて(つまり、文字列処理をするプログラムの全て)に書いておくと幸せになれるらしいです。

Perl内部のUTF-8とUTF-8

文字列がUTF-8ならUTF-8じゃないか?と思いがちですが、Perlには内部で扱う"flagged UTF-8"と"flaggedではないUTF-8" (文字列ではない) の二種類があることを覚えておきましょう。

文字列を扱う時は、Perl内部で扱うflagged UTF-8へdecodeで変換し、Perlの外部に出力する時にはencodeしてやる必要があります。例えば、ターミナルから入力されるひらがなをカタカナに変換する場合は、次のようになります。

use strict;
use warnings;
use utf8;
use Encode;

my $hoge = <>;
my $decoded_hoge = decode_utf8($hoge);
$decoded_hoge =~ tr/ぁ-ん/ァ-ン/;
print encode_utf8($decoded_hoge);

これでたいていの処理は問題なくできるはずです。

参考


AnyEventとblockingについてのメモ

sleep (あるいは LWP::UserAgent などのそのほかのブロックする処理) をすると、たとえコールバック内でも nonblocking では処理されない。

$http_request_cb で sleep しているこの例は blocking で、 sleep を消せば nonblocking になる。ブロックさせたくない場合は timer を使う。

#!/usr/bin/perl 

use strict;
use warnings;
use utf8;
use Encode;

use AnyEvent;
use AnyEvent::HTTP;
use AnyEvent::Socket;
use AnyEvent::Handle;

use Data::Dumper;
use XML::Simple;

my $server = get_alertinfo();

my $http_request_cb; $http_request_cb = sub { 
    my ($body, $hdr) =@_;
    my $xml = XMLin(decode_utf8 $body); 
    print Dumper $xml->{request_id};
    sleep 5;
};

my $socket_read_cb; $socket_read_cb = sub {
    my ($handle, $chat_tag) = @_;
    $chat_tag = XMLin(decode_utf8 $chat_tag);

    if (defined $chat_tag->{content}) {
        my ($lv_num, $co_num, $user_id) = split/,/, $chat_tag->{content};
        if (defined $lv_num && defined $co_num && defined $user_id) {
            print Dumper $lv_num;
            my $url = 'http://live.nicovideo.jp/api/getstreaminfo/lv';
            http_request(
                GET     => "$url$lv_num",
                timeout => 3,
                $http_request_cb
            );
        }
    }
    $handle->push_read(line => "\0", $socket_read_cb);
};

my $connection_cb; $connection_cb = sub {
    my ($fh) = @_ or die $!;

    my $thread_tag_attr = {
        thread   => $server->{thread},
        res_from => '-1',
        version  => '20061206',
    };

    my $thread_tag = XMLout($thread_tag_attr, RootName => 'thread') . "\0";

    my $handle; $handle = new AnyEvent::Handle(
        fh       => $fh,
        on_error => sub {
            warn "Error $_[2]\n";
            $_[0]->destroy;
        },
        on_eof   => sub {
            $handle->destroy;
            warn "Done\n";
        }
    );       
    $handle->push_write($thread_tag);
    $handle->push_read(line => "\0", $socket_read_cb);
};

my $cv = AE::cv;

my $connection = tcp_connect(
    $server->{addr}, $server->{port}, $connection_cb,
);

$cv->recv;

sub get_alertinfo {
    my $url = 'http://live.nicovideo.jp/api/getalertinfo';

    use LWP::UserAgent;
    my $ua = LWP::UserAgent->new();
    my $res = $ua->get($url);
    
    die $res->status_line unless $res->is_success;

    my $xml = XMLin($res->decoded_content);

    die "Fatal: Server status $xml->{status}" if $xml->{status} ne 'ok';

    return $xml->{ms};
}

さくらのレンタルサーバでroot権限無しにCPANを使えるようにする

注:最近は cpanm でうまくやる方法があるのでそちらを探した方が得策

_

local::lib使わなくてもMyConfig.pmの設定を変えるだけで大丈夫

SSHでログインして次のディレクトリを作成する
$HOME/local/lib/perl5
$HOME/local/lib/perl5/site_perl
cpanを起動

自動的に設定することでかなり楽ができる。手動設定でもCPANのFTPミラー以外はデフォルトでOK。

~.cshrc にPERL5LIBを追記する
setenv PERL5LIB $HOME/local/lib/perl5:$HOME/local/lib/perl5/site_perl
~.cpan/CPAN/MyConfig.pm を書き換える

ユーザがhogeの場合。

$CPAN::Config = {
  'applypatch' => q[],
  'auto_commit' => q[0],
  'build_cache' => q[100],
  'build_dir' => q[/home/hoge/.cpan/build],
  'build_dir_reuse' => q[0],
  'build_requires_install_policy' => q[ask/yes],
  'bzip2' => q[/usr/bin/bzip2],
  'cache_metadata' => q[1],
  'check_sigs' => q[0],
  'colorize_output' => q[0],
  'commandnumber_in_prompt' => q[1],
  'connect_to_internet_ok' => q[1],
  'cpan_home' => q[/home/hoge/.cpan],
  'curl' => q[/usr/local/bin/curl],
  'ftp' => q[/usr/bin/ftp],
  'ftp_passive' => q[1],
  'ftp_proxy' => q[],
  'getcwd' => q[cwd],
  'gpg' => q[/usr/local/bin/gpg],
  'gzip' => q[/usr/bin/gzip],
  'halt_on_failure' => q[0],
  'histfile' => q[/home/hoge/.cpan/histfile],
  'histsize' => q[100],
  'http_proxy' => q[],
  'inactivity_timeout' => q[0],
  'index_expire' => q[1],
  'inhibit_startup_message' => q[0],
  'keep_source_where' => q[/home/hoge/.cpan/sources],
  'load_module_verbosity' => q[v],
  'lynx' => q[/usr/local/bin/lynx],
  'make' => q[/usr/bin/make],
  'make_arg' => q[],
  'make_install_arg' => q[],
  'make_install_make_command' => q[],
  'makepl_arg' => q[INSTALLDIRS=site INSTALL_BASE=/home/hoge/local LIB=/home/hoge/local/lib/perl5],
  'mbuild_arg' => q[],
  'mbuild_install_arg' => q[],
  'mbuild_install_build_command' => q[./Build],
  'mbuildpl_arg' => q[./Build --install_base /home/hoge/local],
  'ncftp' => q[],
  'ncftpget' => q[],
  'no_proxy' => q[],
  'pager' => q[more],
  'patch' => q[/usr/bin/patch],
  'perl5lib_verbosity' => q[v],
  'prefer_installer' => q[MB],
  'prefs_dir' => q[/home/hoge/.cpan/prefs],
  'prerequisites_policy' => q[ask],
  'scan_cache' => q[atstart],
  'shell' => q[/bin/csh],
  'show_unparsable_versions' => q[0],
  'show_upload_date' => q[0],
  'show_zero_versions' => q[0],
  'tar' => q[/usr/bin/tar],
  'tar_verbosity' => q[v],
  'term_is_latin' => q[1],
  'term_ornaments' => q[1],
  'test_report' => q[0],
  'trust_test_report_history' => q[0],
  'unzip' => q[/usr/local/bin/unzip],
  'urllist' => [q[ftp://ftp.riken.jp/lang/CPAN/]],
  'use_sqlite' => q[0],
  'wget' => q[/usr/local/bin/wget],
  'yaml_load_code' => q[0],
  'yaml_module' => q[YAML],
};
1;
__END__
cpanを起動
  • o confで設定を確認
  • 設定がOKそうなら、install Mooseあたりで確認
  • cpanを終了し、Mooseがインストールされたかを確認する
perl -MMoose -e 'print $Moose::VERSION, $/'

バージョンが出力されればインストールは成功。


« 11 »