How to growl IRC messages over ssh
My environment
I'm using weechat on remote server's screen.
The big problem is I can't perceive chatting on IRC without "polling" terminal by myself. Because I have no way to get alert over screen and ssh.
I was thinking to solve this problem and just found the solution.
The flow is:
Preparation
- Enable weechat's logging function and find the log files.
- Confirm that the following command works well (rewrite the path to logs)
tail -f $HOME/.weechat/logs/*/*/*.weechatlog
- Install `growlnotify`
Setup scripts
Shell script that connecting to the server (irc_growl.sh)
You may have to rewrite ssh options and path to the log. Be careful with `'` (single quotation mark) to guaranteeing the home dir path is interpolated with remote's.
ssh example.com tail -n 1 -f '$HOME/.weechat/logs/*/*/*.weechatlog' | perl irc_growl.pl &
Perl script that processes received lines (irc_growl.pl)
You can rewrite system()'s args as you want. `man growlnotify` will help you.
while (<STDIN>) { chomp; next unless $_; next if /^==>/; # ignore tail's output my $attr = parse($_); if ($attr->{type} =~ /(:?NOTICE|PRIVMSG)/) { system("growlnotify", "-m", $attr->{content}, "-t", $attr->{user}, "--appIcon", "LimeChat"); } } sub parse { my ($line) = @_; my ($time, $cmd, @contents) = split /\t/, $line; my $content = join "\t", @contents; my $user; if (not $cmd) { # critical error $cmd = 'ERROR'; } elsif ($cmd eq '-->') { # join $cmd = 'JOIN'; } elsif ($cmd eq '<--') { # part $cmd = 'PART'; } elsif ($cmd eq '--') { # messages from server $cmd = 'SERVER'; } elsif ($cmd eq '*') { # notice $user = $cmd; $cmd = 'NOTICE'; } else { # privmsg $user = $cmd; $cmd = 'PRIVMSG'; } return +{ type => $cmd, time => $time, content => $content, user => $user, }; }
Run!
./irc_growl.sh
100 fav されたので MacBook Air 11インチ を買ったら spell がなくてxt/podspell.t がコケた
Mac に戻ってくるのはもう6~7年ぶりなのか、当時は Intel Mac なんて無くて PowerPC でした。全体的な UI は昔からさほど変わった感じはしないですね。
さっそく環境を整えていたら github から持ってきたモジュールのテストがコケる。
こんな感じのテストを使っていたんですが、 spell は OSX には無いらしく、今まで Linux でしか作業してなかったのでだいぶ嵌りました。
podspell.t
use Test::More; eval q{ use Test::Spelling }; plan skip_all => "Test::Spelling is not installed." if $@; add_stopwords(map { split /[\s\:\-]/ } <DATA>); $ENV{LANG} = 'C'; all_pod_files_spelling_ok('lib'); __DATA__
spell がないと怒られます。
sh: spell: command not found
はてどうしたものかと CPAN モジュールを漁って見ると、各々思い思いの方法で podspell.t を書いているようでした。
そこで参考にしたのは、いろいろな環境の開発者がいて xt/ が多く走っていそうな Plack のテストを参考にしてみました。aspell が存在する場合には aspell を使い、ない場合には spell を使う方法が良さそうです。
Plack-0.9973/xt/podspell.t
use Test::More; eval q{ use Test::Spelling }; plan skip_all => "Test::Spelling is not installed." if $@; add_stopwords(map { split /[\s\:\-]+/ } <DATA>); $ENV{LANG} = 'C'; set_spell_cmd("aspell -l en list") if `which aspell`; all_pod_files_spelling_ok('lib'); __DATA__
GmailでOCNのSMTPを指定すると Remote server does not support TLS code(500) とエラーが出る件
ヘルプフォーラムから2chまで探してようやく解決したので2011年1月14日現在のメモ
2010年9月1日以前にOCN会員登録証が届いたお客さま smtp.vcの後にメールアドレスの@の右側
OCN設定サポート | NTT Com お客さまサポート の表記通りに従っても、smtp.vc*.ocn.ne.jp はTLS対応してないようなので延々と下のエラーメッセージが表示される。
Remote server does not support TLS code(500)
Imager で Twitter アイコンを低品質 jpeg で返す
Twitter のアイコンには主に gif / jpeg / png が使われており、 png を表示できないガラケーがある。
Cache::Memcached::Fast でキャッシュしつつ、 Imager では一時ファイルを作らず。思っていたよりも楽にかけた
use LWP::UserAgent; use Imager; use Cache::Memcached::Fast; use Plack::Request; use Plack::Builder; my $memd = Cache::Memcached::Fast->new({ ... }); builder { mount '/tw_thumbnail' => sub { my $env = shift; my $req = Plack::Request->new($env); if ($req->param("url") =~ m{^(http://a\d\.twimg\.com/.+)}) { my $url = $1; if (my $result = $memd->get($url)) { return [200, ['Content-Type' => 'image/jpeg'], [$result]]; } else { my $img = LWP::UserAgent->new->get($url)->decoded_content; my $image = Imager->new; $image->read(data => $img) or return [500, [], [$image->errstr]]; $image->write(data => \my $out, jpegquality => 30, type => 'jpeg') or return [500, [], [$image->errstr]]; $memd->set($url, $out, 1 * 60 * 60 * 24); return [200, ['Content-Type' => 'image/jpeg'], [$out]]; } } else { return [404, [], ['Not Found']]; } }; };
practical というプラグマ書いた
GitHub - punytan/practical: practical pragma
use practical;
は
use strict; use warnings; use utf8; use feature qw(switch say state);
と同じ。
ほとんどの人はこの4行は書いているはず(?)
類似のプラグマ
common::sense
- strict 'refs' はオフ
- warnings のオプション覚えきれないよ!
- 下のコードで "Wide character in print at" がでない
perl -Mcommon::sense -e 'print "いろは\n";'
Modern::Perl
- use utf8 がない
- 将来、モジュールが追加される可能性がある
Tatsumaki ライクな micro WAF "Lanky" を作ってみた
Twiggy を使う場合は Tatsumaki があって簡単に書けるけれども Starman / Starlet 使うときにも似たようにかけたらいいなぁ、ということで似たように書けるものを作ってみました。
モデルは実装してないので(どの ORM を使うかは TIMTOWTDI でどれ採用すべきか迷ったので)正確には WAF ではないと思うのだけれど、とりあえず Tatsumaki と似たことはできるようにしたつもりです。なにか意見いただけると嬉しいです
https://github.com/punytan/Lanky
Tatsumaki のように全部ひとつのファイルに突っ込むことも出来るし、別々のファイルに分割して書けるようにもしてあります。
t/02_app をみてもらえるとすぐわかると思うんですが、下記のように書けるようになっております。
ひとつのファイルで書く場合
errordoc, htdocs, template ディレクトリを準備して、
$ tree . |-- errordoc | `-- 404 |-- htdocs | |-- favicon.ico | |-- foo.htlm | `-- static | `-- index.html |-- template | `-- foo.xt `-- united.t
united.t
こんな風に書いたり、
use strict; package RootHandler; use parent 'Lanky::Handler'; use Data::Dumper; sub get { my ($self) = @_; my $body = $self->render('foo.xt', {foo => 'testing'}); my $res = $self->request->new_response(200); $res->content_type('text/html'); $res->body($body); $res->finalize; } 1; package LoginHandler; use parent 'Lanky::Handler'; use Data::Dumper; sub get { my ($self) = @_; my $body = $self->render('foo.xt', {foo => 'testing'}); my $res = $self->request->new_response(200); $res->content_type('text/html'); $res->body($body); $res->finalize; } 1; package main; use Test::More; use Plack::Test; use HTTP::Request::Common; use File::Spec; use File::Basename; use Lanky; use Plack::Builder; my $basedir = File::Basename::dirname(__FILE__); my $lanky = Lanky->new( application => [ '/' => 'RootHandler', '/login' => 'LoginHandler', ], template => [ path => ["$basedir/template"], cache => 1, cache_dir => File::Spec->tmpdir, ], errordoc_path => "$basedir/errordoc", render_encoding => 'utf8', ); my $app = builder { enable "Plack::Middleware::Static", path => sub { s{^/(?:(favicon\.ico)|static/)}{$1||''}e }, root => "$basedir/htdocs/"; $lanky->to_app; }; test_psgi $app, sub { my $cb = shift; my $res = $cb->(GET "/"); is $res->content, "testingいろはにほへと\n"; $res = $cb->(GET "/login"); is $res->content, "testingいろはにほへと\n"; $res = $cb->(GET "/xxx"); is $res->content, "みつからないよ!\n"; is $res->code, 404; }; done_testing;
別々のファイルに書く場合
lib ディレクトリを作って @INC に ./lib を突っ込んで、
$ tree . |-- errordoc | `-- 404 |-- htdocs | |-- favicon.ico | |-- foo.htlm | `-- static | `-- index.html |-- lib | `-- MyApp | `-- C | |-- Login.pm | `-- Root.pm |-- template | `-- foo.xt `-- divided.t
divided.t
こんな風に書いて、 MyApp::C::Root で上と同じように use parent 'Lanky::Handler'; してやれば、 $self から諸々呼べるようになっています
use strict; use Test::More; use Plack::Test; use HTTP::Request::Common; use File::Spec; use File::Basename; use lib File::Basename::dirname(__FILE__) . "/lib"; use Lanky; use Plack::Builder; my $basedir = File::Basename::dirname(__FILE__); my $lanky = Lanky->new( application => [ '/' => 'MyApp::C::Root', '/login' => 'MyApp::C::Login', ], template => [ path => ["$basedir/template"], cache => 1, cache_dir => File::Spec->tmpdir, ], errordoc_path => "$basedir/errordoc", render_encoding => 'utf8', ); my $app = builder { enable "Plack::Middleware::Static", path => sub { s{^/(?:(favicon\.ico)|static/)}{$1||''}e }, root => "$basedir/htdocs/"; $lanky->to_app; }; test_psgi $app, sub { my $cb = shift; my $res = $cb->(GET "/"); is $res->content, "testingいろはにほへと\n"; $res = $cb->(GET "/login"); is $res->content, "testingいろはにほへと\n"; $res = $cb->(GET "/xxx"); is $res->content, "みつからないよ!\n"; is $res->code, 404; }; done_testing;