Windows上でperlを使って日本語ファイル名を操作する(メモ

slashdot.jpの「Perlはゾンビだ」に、日本語Windows環境において、perlを使って日本語ファイル名を操作する時の注意点がまとめられていたので、引用&備忘録化。

過去にperlスクリプトを作る際、ファイル内に書かれた日本語の操作に関することはWindows/Linuxで動作が共通化できたものの、「日本語ファイル名の取り扱い」について、Windows上での動作がいまいち分からず、面倒になり、NASに該当ファイル群を置き、Linuxで処理する、ということをしたことがある。

その時に受けた感じからすると、以下の解説は非常に納得がいくモノだった。

Anonymous Coward の書き込み (#2628619) 」より

コマンドラインからの引数取得とかファイル操作とかのたびに
@ARGV = map { decode(‘cp932’, $_) } @ARGV; とか
open my $fh, ”, encode(‘cp932’, $filename) or die $!; とか
@files = map { decode(‘cp932’, $_) } readdir($d); とか
if (-f encode(‘cp932’, $filename)) とか
mkdir encode(‘cp932’, $filename); とかソース全体にわたって書かなければならないこと。

これが面倒だと思わない奴はWindows上でPerlを本気で使ったことがないとしか思えない。少なくとも小飼弾はMac使っているようだし。つーか面倒だと思わないならそもそもどうして開祖が「怠惰はプログラマの美徳」とか言ってる言語なんか使ってるの?

56億7千万歩ほど譲ってこれは面倒ではないということにしても、Windows以外の環境への移植性がまったくない。Windows上でシステムロケールを変えただけで動作がおかしくなる。当然どんな環境で動くかわからないモジュール内では使えない。
まあいちおうこれには対処の方法があって、
use Encode::Locale;
@ARGV = map { decode(locale, $_) } @ARGV; とか
open my $fh, ”, encode(locale_fs, $filename) or die $!; とか
@files = map { decode(locale_fs, $_) } readdir($d); とか
if (-f encode(locale_fs, $filename)) とか
mkdir encode(locale_fs, $filename); とかさらに呪文を積み増しすればいいらしい。
MacやLinuxでこんなことわざわざしてる奴いないと思うけど。つーか忘れてもたいてい問題なく動くからWindows以外の環境で正しく書くのが超困難。だから結局Windowsに移植する奴が貧乏クジを引かされる。Windows上ですら、localeとlocal_fsが違う環境があるというバグを知らずに踏んでも気づかない。

しかし実はEncode::Locale;使ってもまだ不十分で、システムロケール(日本語版ならシフトJIS)で表せない文字を含んだファイル名が扱えない。いちおうWin32::Unicode::Fileというモジュールがあるようだが、ファイル読み書きをモジュール内で独自に行なっているので信じられないほど遅くて捨てた。Win32::Longnameというモジュールがちょっとはマシなようだが、どちらにしてもまたも移植性がなくなる。

自分で書くコードは上記の面倒じゃないことにした書き換えを「するだけで」済むとしても、File::compareのような超基本的モジュールすらいまだに非対応。

Perlでこのへんが改善される見込みはまったくなさそうなので、自分はPythonの勉強を始めた。

そして、(#2630401) より

> ・PerlをUTF-8ベース(CP65001)でPerlを動かす
> ことだと思います。

Console CPはファイル名で使われるコードページにはまったく影響を与えない。Encode::Localeでもlocale_fsとconsole_inとconsole_outが別々に定義されている(そう、APIレベルではコンソール入力と出力さえ異なる可能性がある)。Perlの仕様をまともにするためにあなたのような知ったかぶりバカをマサカリで殴って回るよりコストがかからないに違いないからPythonの勉強を始めたの。

> 普通のコマンドプロンプト(SJIS)ベースでは不可能。

Windowsにはコンソール入出力にもワイド文字APIがあり、それを使えば可能(リダイレクトやパイプが絡むとこっちの都合だけでエンコーディングを決められないけどそれはCygwinでも同じだし)。もちろん今あるPerlでは不可能だがそれは実装の手抜きにすぎない。そもそもCygwinはどうやってUTF-8文字を受け付けるコンソールを実現してると思ってるの?

> ・UTF-8 な cygwin の環境を構築し、その上で Perl を使う

Cygwinはパスの扱いが特殊すぎて、結局普通のアプリとパス名をやりとりする際にパスの変換/逆変換が必要なので、面倒だとか移植性ゼロだとかいう問題は何も解決しない。Perlがmsvcrt使うのやめて、UTF-8←→UTF-16LE変換を行ってワイド文字API呼び出して、Encode::LocaleはあたかもロケールがUTF-8であるかのようにふるまってくれるのが一番いいのだが、それを実現するために投入するコストを考えるとすでにまともな処理している言語の乗り換えにコストを振り向けたほうがどう考えても省エネ。

> ・@ARGVやファイル名を、スクリプト本体内のデータ処理と混ぜない

それを面倒と思わないなら以下略

MySQLとpostgresqlでのレプリケーション動作検証時使用perlスクリプト

MySQLのレプリケーション機能を使うとどのような動きをするのかを確認中。

テストデータのインサートと確認を行うためのスクリプトを作成した。

標準で用意されているデータベース「test」内にテーブル「testtable」を作成して、そこにデータを投入することにした。

# mysql -u root
mysql> use test;
mysql> create table testtable (
	id int(20) not null auto_increment,
	name char(100) default '' not null,
	text char(255) default '',
	primary key (id)
);
mysql> grant all on test.* to テストユーザ名@ホスト名 identified by 'パスワード';
mysql>

スクリプトはperl。
perl-DBD-MySQLパッケージをインストールしておくこと。

#!/usr/bin/perl

use DBI;

my $mysqluser="MySQL内のユーザ名";
my $mysqlpassword="パスワード";
my $masterserver="マスタサーバ名";
my $slaveserver="スレーブサーバ名";
my $dbname="test";
my $tablename="testtable";
$max=5;

sub getselect{
	my($server,$user,$password,$dbname,$tablename)=@_;
	my $db=DBI->connect("DBI:mysql:$dbname:$server",$user,$password);
	my $sth=$db->prepare("select id,name,text from $tablename order by id desc");
	$sth->execute;
	print "\tname\ttext\n";
	my $count=$max;
	for(my $i=0; $i<$sth->rows; $i++){
		my @tmp=$sth->fetchrow_array;
		if($count>0){
			print $tmp[0] ."\t". $tmp[1] ."\t". $tmp[2] ."\n";
			$count--;
		}
	}
	$sth->finish;
	$db->disconnect;
}

sub insertvalue{
	my($server,$user,$password,$dbname,$tablename)=@_;
	my $db=DBI->connect("DBI:mysql:$dbname:$server",$user,$password);
	my $str1=substr("00".rand(100),-3);
	my $str2=localtime();
	my $sth=$db->prepare("insert into $tablename values (NULL,'name$str1','$str2')");
	$sth->execute;
	$sth->finish;
	$db->disconnect;
}

if($ARGV[0] =~ /ins/){
	print "=== insert ===\n";
	insertvalue($masterserver,$mysqluser,$mysqlpassword,$dbname,$tablename);
}

print "=== master:$masterserver ===\n";
getselect($masterserver,$mysqluser,$mysqlpassword,$dbname,$tablename);

print "=== slave:$slaveserver ===\n";
getselect($slaveserver,$mysqluser,$mysqlpassword,$dbname,$tablename);

使い方
情報確認のみ「mysqltest.pl」
データ追加と情報確認「mysqltest.pl ins」

オプションとして「ins」(insert)を指定すると、データを追加する、というもの。

実行すると以下の様な形となる。

# mysqltest.pl ins
=== insert ===
=== マスタサーバ ===
name    text
248     name284 Fri Jun 20 11:42:01 2014
247     name563 Fri Jun 20 11:35:01 2014
246     name934 Fri Jun 20 11:28:01 2014
245     name769 Fri Jun 20 11:21:01 2014
244     name227 Fri Jun 20 11:14:01 2014
=== スレーブサーバ ===
name    text
248     name284 Fri Jun 20 11:42:01 2014
247     name563 Fri Jun 20 11:35:01 2014
246     name934 Fri Jun 20 11:28:01 2014
245     name769 Fri Jun 20 11:21:01 2014
244     name227 Fri Jun 20 11:14:01 2014
#

「単純増加する数字 name+ランダム数字 日付」という出力内容のうち、最新の5件のみ表示する、というものになっている。

マスタサーバの出力内容と、スレーブサーバの出力内容を比べる、というもの。


2021/05/19

postgresql環境でのバックアップ試験のためにこのスクリプトを流用しようとしたところ、作り直しが必要なポイントがあった。

まずはテーブル作成時の違い

create table testtable (
	id int(20) not null auto_increment,
	name char(100) default '' not null,
	text char(255) default '',
	primary key (id) 
);

これをそのまま実行すると下記エラーになる

ERROR:  syntax error at or near "("
LINE 2: id int(20) not null auto_increment,

int型auto_increment属性というのはMySQL特有で、postgresqlではserial型で置き換える。
「int(20) auto_increment」→「serial」に変更すると、以下のようになる。

create table testtable (
	id serial not null,
	name char(100) default '' not null,
	text char(255) default '',
	primary key (id) 
);

また、perlモジュールは DBD:mysqlではなくDBD:Pgに変更になり、データベースとホスト指定手法が変わった。

パッケージとしては perl-DBD-Pg をインストールする。

#!/usr/bin/perl

use DBI;

my $mysqluser="postgresql内のユーザ名";
my $mysqlpassword="パスワード";
my $masterserver="マスタサーバ名";
my $slaveserver="スレーブサーバ名";
my $dbname="test";
my $tablename="testtable";
$max=5;

sub getselect{
        my($server,$user,$password,$dbname,$tablename)=@_;
        my $db=DBI->connect("DBI:Pg:dbname=$dbname;host=$server",$user,$password);
        my $sth=$db->prepare("select id,name,text from $tablename order by id desc");
        $sth->execute;
        print "\tname\ttext\n";
        my $count=$max;
        for(my $i=0; $i<$sth->rows; $i++){
                my @tmp=$sth->fetchrow_array;
                if($count>0){
                        print $tmp[0] ."\t". $tmp[1] ."\t". $tmp[2] ."\n";
                        $count--;
                }
        }
        $sth->finish;
        $db->disconnect;
}

sub insertvalue{
        my($server,$user,$password,$dbname,$tablename)=@_;
        my $db=DBI->connect("DBI:Pg:dbname=$dbname;host=$server",$user,$password);
        my $str1=substr("00".rand(100),-3);
        my $str2=localtime();
        my $sth=$db->prepare("insert into $tablename (name, text) values ('name$str1','$str2')");
        $sth->execute;
        $sth->finish;
        $db->disconnect;
}

if($ARGV[0] =~ /ins/){
        print "=== insert ===\n";
        insertvalue($masterserver,$mysqluser,$mysqlpassword,$dbname,$tablename);
}

print "=== postgresql:$masterserver ===\n";
getselect($masterserver,$mysqluser,$mysqlpassword,$dbname,$tablename);

print "=== slave:$slaveserver ===\n";
getselect($slaveserver,$mysqluser,$mysqlpassword,$dbname,$tablename);

IIJmioクーポンスイッチAPIを使って使用量グラフ作成

IIJmioクーポンスイッチAPI」というものが公開された。

AndroidアプリからこのAPIを使う、というのが想定されている使われ方だと思うんですが、違う使い方をしてみた。
というのは、「データ利用量照会」という機能を見つけ、これを利用すれば1年分のデータ使用量グラフが作れる、と思ったからです。

幸い、常時起動のサーバがあるので、そいつに仕込めばいいか、と、やってみました。

まずは、完成品をご覧ください。
test

現在SIMを4枚もっているので、こんなグラフになっています。
メインで使ってるのがSIM2、SIM4はSMS対応のものでテストに使用。
SIM3はうちの奥さんに渡しているもの、SIM1は実家においてあるルータ、という感じです。

さて、このグラフ作るまでに行ったことですが、まず最初はアクセストークン取得です。
いろいろ悩んだんですが、適当な手法をとっています。

まず、redirect_uriとして適当なCGIを作りました。

#!/usr/bin/perl
print "Content-Type: text/plain; charset=UTF-8\n\n";
print "test\n";

えぇ、適当過ぎますね。

そして、普通のHTMLを作ります。

<html>
<head>
<title>iijmio</title>
</head>
<body>

<a href="https://api.iijmio.jp/mobile/d/v1/authorization/?response_type=token&client_id=<DeveloperID>&state=test&redirect_uri=http%3A%2F%2F~.osakana.net%2Ftest.cgi">go to IIJMIO</a>

</body>
</html>

redirect_uriには、先ほど作成した適当なCGIのアドレスを記載します。

ブラウザで作成したhtmlにアクセスし、IIJmioの認証を行い、正常に通ると、redirect_uriに指定したURLに対して、戻ってきます。
ブラウザのURL欄に表示された文字列から「access_token=~」という記述を見つけ、アクセストークンを取得します。
ちなみに、このアクセストークン、7776000秒有効です。つまり90日間です。
IIJmio側に30日分のデータが保管されているので120日以内に1回手動で更新すればいいか、と考え、テキトーな実装になっています。

次に、利用量取得のperlスクリプト作成。

#!/usr/bin/perl
use strict;
use warnings;
use LWP;
use URI::Escape;
use JSON;
use Time::Local;

my $lwpua = LWP::UserAgent->new;

my $url="https://api.iijmio.jp/mobile/d/v1/log/packet/";

my $developerid="<DeveloperID>";
my $usertoken  ="<アクセストークン>";

my $lwpreq = HTTP::Request->new(GET => "$url");
$lwpreq->header("X-IIJmio-Developer" => "$developerid");
$lwpreq->header("X-IIJmio-Authorization" => "$usertoken");
my $lwpres= $lwpua->request($lwpreq);
my $data = decode_json($lwpres->content);

for(my $i=0;$i<@{$data->{packetLogInfo}};$i++){
        #print $i . ":" . $data->{packetLogInfo}->[$i]->{hddServiceCode} ."\n";
        my $hddServiceCode=$data->{packetLogInfo}->[$i]->{hddServiceCode};

        for(my $j=0;$j<@{$data->{packetLogInfo}->[$i]->{hdoInfo}};$j++){
                #print $i . "-" . $j . ":" . $data->{packetLogInfo}->[$i]->{hdoInfo}->[$j]->{hdoServiceCode} . "\n";
                my $hdoServiceCode=$data->{packetLogInfo}->[$i]->{hdoInfo}->[$j]->{hdoServiceCode};
                if(! -f "$hdoServiceCode.rrd"){
                      print "rrdtool create $hdoServiceCode.rrd --start 1384786740 --step 86400 DS:withCoupon:GAUGE:86400:0:U DS:withoutCoupon:GAUGE:86400:0:U RRA:LAST:0.5:1:100000 \n";
                      system("rrdtool create $hdoServiceCode.rrd --start 1384786740 --step 86400 DS:withCoupon:GAUGE:86400:0:U DS:withoutCoupon:GAUGE:86400:0:U RRA:LAST:0.5:1:100000");

                }

                for(my $k=0;$k<@{$data->{packetLogInfo}->[$i]->{hdoInfo}->[$j]->{packetLog}};$k++){
                      #print "   " . $data->{packetLogInfo}->[$i]->{hdoInfo}->[$j]->{packetLog}->[$k]->{date} ;
                      #print ":" . $data->{packetLogInfo}->[$i]->{hdoInfo}->[$j]->{packetLog}->[$k]->{withCoupon} ;
                      #print ":" . $data->{packetLogInfo}->[$i]->{hdoInfo}->[$j]->{packetLog}->[$k]->{withoutCoupon} ;
                      #print "\n";
                      my $d=$data->{packetLogInfo}->[$i]->{hdoInfo}->[$j]->{packetLog}->[$k]->{date};
                      my $year = substr($d,0,4);
                      my $mon  = substr($d,4,2) - 1;
                      my $mday = substr($d,6,2);
                      my $unixtime = timelocal(0,59,23,$mday,$mon,$year);
                      my $withCoupon=$data->{packetLogInfo}->[$i]->{hdoInfo}->[$j]->{packetLog}->[$k]->{withCoupon};
                      my $withoutCoupon=$data->{packetLogInfo}->[$i]->{hdoInfo}->[$j]->{packetLog}->[$k]->{withoutCoupon};
                      print "rrdtool update $hdoServiceCode.rrd $unixtime:$withCoupon:$withoutCoupon \n";
                      system("rrdtool update $hdoServiceCode.rrd $unixtime:$withCoupon:$withoutCoupon");
                }
        }
}

これを「get.pl」というファイル名で保存します。
実行すると、「hdo810xxxxx.rrd」というような感じのファイルがSIMカード分作成されます。
なお、手抜きをしているので、2回目以降は、同じ値を入力しようとし、「ERROR: hdo8371xxxx.rrd: illegal attempt to update using time 1387378740 when last update time is 1387378740 (minimum one second step)」みたいなエラーがでてしまいますが、仕様です。
また、rrdtoolは一度登録した情報の更新ができない構造をしているので、日付が変わる直前に実行することを推奨します。

で・・・グラフ作成は以下の様な感じで、情報取得と連続で行わせています。
現在SIMが4枚あるので、4枚分を集計しています。
クーポン使用の有無は区別せず合算としています。

#!/bin/bash
cd /home/~/mio
./get.pl
rrdtool graph iijmio-use.png --imgformat=PNG --end now --start end-1months \
--vertical-label "MB" \
--title="IIJmioの使用量" \
DEF:SIM1C=hdo8038xxxx.rrd:withCoupon:LAST \
DEF:SIM1N=hdo8038xxxx.rrd:withoutCoupon:LAST \
DEF:SIM2C=hdo8100xxxx.rrd:withCoupon:LAST \
DEF:SIM2N=hdo8100xxxx.rrd:withoutCoupon:LAST \
DEF:SIM3C=hdo8100xxxx.rrd:withCoupon:LAST \
DEF:SIM3N=hdo8100xxxx.rrd:withoutCoupon:LAST \
DEF:SIM4C=hdo8371xxxx.rrd:withCoupon:LAST \
DEF:SIM4N=hdo8371xxxx.rrd:withoutCoupon:LAST \
CDEF:SIM1=SIM1C,SIM1N,+ \
CDEF:SIM2=SIM2C,SIM2N,+ \
CDEF:SIM3=SIM3C,SIM3N,+ \
CDEF:SIM4=SIM4C,SIM4N,+ \
LINE1:SIM1#0000FF:"SIM1" \
LINE2:SIM2#00FFFF:"SIM2" \
LINE3:SIM3#00FF00:"SIM3" \
LINE4:SIM4#F00F00:"SIM4"

で、これをサーバのcrontabに突っ込んで、23:58に実行する設定しました。
さて、これでちゃんと更新し続けてくれるといいのですが・・・


APIが公開されて速攻作成&記事公開したところ、IIJmioの人に発見された模様。


2013/12/24追記

しばらく運用してみた結果、見にくかったので、グラフ作成については、以下の様に変更した。

rrdtool graph iijmio-use.png --imgformat=PNG \
--height=300 \
--lower-limit=0 \
--end now --start end-1months \
--vertical-label "MB" \
--title="IIJmioの使用量" \
DEF:SIM1C=hdo8038xxxx.rrd:withCoupon:LAST \
DEF:SIM1N=hdo8038xxxx.rrd:withoutCoupon:LAST \
DEF:SIM2C=hdo8100xxxx.rrd:withCoupon:LAST \
DEF:SIM2N=hdo8100xxxx.rrd:withoutCoupon:LAST \
DEF:SIM3C=hdo8100xxxx.rrd:withCoupon:LAST \
DEF:SIM3N=hdo8100xxxx.rrd:withoutCoupon:LAST \
DEF:SIM4C=hdo8371xxxx.rrd:withCoupon:LAST \
DEF:SIM4N=hdo8371xxxx.rrd:withoutCoupon:LAST \
CDEF:SIM1=SIM1C,SIM1N,+ \
CDEF:SIM2=SIM2C,SIM2N,+ \
CDEF:SIM3=SIM3C,SIM3N,+ \
CDEF:SIM4=SIM4C,SIM4N,+ \
LINE2:SIM1#0000FF:"SIM1" \
LINE2:SIM2#00FFFF:"SIM2" \
LINE2:SIM3#00FF00:"SIM3" \
LINE2:SIM4#F00F00:"SIM4"

iijmio2

「LINE数字:~」の数字部分の意味を取り違えていたという・・・太さの意味だったか・・・


2014/12/19追記

作ってから約1年が経過しました。
最近はこんなグラフにしています。(横軸のめもりを日付にした)

rrdtool graph iijmio-use.png --imgformat=PNG \
--height=300 \
--lower-limit=0 \
--end now --start end-2months \
--vertical-label "MB" \
--x-grid DAY:1:WEEK:1:WEEK:1:0:%m/%d \
--title="IIJmioの使用量" \
DEF:SIM1C=hdo8038xxxx.rrd:withCoupon:LAST \
DEF:SIM1N=hdo8038xxxx.rrd:withoutCoupon:LAST \
DEF:SIM2C=hdo8100xxxx.rrd:withCoupon:LAST \
DEF:SIM2N=hdo8100xxxx.rrd:withoutCoupon:LAST \
DEF:SIM3C=hdo8100xxxx.rrd:withCoupon:LAST \
DEF:SIM3N=hdo8100xxxx.rrd:withoutCoupon:LAST \
DEF:SIM4C=hdo8371xxxx.rrd:withCoupon:LAST \
DEF:SIM4N=hdo8371xxxx.rrd:withoutCoupon:LAST \
CDEF:SIM1=SIM1C,SIM1N,+ \
CDEF:SIM2=SIM2C,SIM2N,+ \
CDEF:SIM3=SIM3C,SIM3N,+ \
CDEF:SIM4=SIM4C,SIM4N,+ \
LINE2:SIM1#0000FF:"SIM1" \
LINE2:SIM2#00FFFF:"SIM2" \
LINE2:SIM3#00FF00:"SIM3" \
LINE2:SIM4#F00F00:"SIM4"

mio-20141219

そして、1年分

rrdtool graph iijmio-use-year.png --imgformat=PNG \
--height=300 \
--width=600 \
--lower-limit=0 \
--end now --start end-14months \
--vertical-label "MB" \
--x-grid WEEK:1:MONTH:1:MONTH:1:0:%m/%d \
--title="IIJmioの1年分使用量" \
DEF:SIM1C=hdo8038xxxx.rrd:withCoupon:LAST \
DEF:SIM1N=hdo8038xxxx.rrd:withoutCoupon:LAST \
DEF:SIM2C=hdo8100xxxx.rrd:withCoupon:LAST \
DEF:SIM2N=hdo8100xxxx.rrd:withoutCoupon:LAST \
DEF:SIM3C=hdo8100xxxx.rrd:withCoupon:LAST \
DEF:SIM3N=hdo8100xxxx.rrd:withoutCoupon:LAST \
DEF:SIM4C=hdo8371xxxx.rrd:withCoupon:LAST \
DEF:SIM4N=hdo8371xxxx.rrd:withoutCoupon:LAST \
CDEF:SIM1=SIM1C,SIM1N,+ \
CDEF:SIM2=SIM2C,SIM2N,+ \
CDEF:SIM3=SIM3C,SIM3N,+ \
CDEF:SIM4=SIM4C,SIM4N,+ \
LINE2:SIM1#0000FF:"SIM1" \
LINE2:SIM2#00FFFF:"SIM2" \
LINE2:SIM3#00FF00:"SIM3" \
LINE2:SIM4#F00F00:"SIM4"

test-year-20141219

おまけ:上記のグラフの利用率変動の解説。

SIM1はミニマムスタートプラン、SIM2/3/4はファミリーシェアプランで、SIM3はmicroSIM、SIM4はnanoSIM/SMS付。

・2013/12頃
 メイン機CP-D02:SIM2
 偽iPhone5s(Thunderbird i5s):SIM4
 奥さんのP-01D:SIM3
 奥さん実家の緊急用ルータ:SIM1
・2014/01頃
 ほとんど使用されていないSIM1の容量がもったいないので入れ替え
 メイン機CP-D02:SIM2→SIM1
 奥さん実家の緊急用ルータ:SIM1→SIM2
 偽iPhone5s(Thunderbird i5s):SIM4
 奥さんのP-01D:SIM3
・2014/02頃の変更点
 Thunderbid i5sの液晶を割ったので余ったSMS付SIM4をメイン機へ 
 メイン機CP-D02:SIM1→SIM4
 奥さん実家の緊急用ルータ:SIM2
 奥さんのP-01D:SIM3
・2014/03頃の変更点
 Covia CP-F03aが来たのでがんばって使用開始。
 それに伴い余剰になったCovia CP-D02を奥さんのに充当
 メイン機CP-F03a:SIM4 & SIM1
 奥さん実家の緊急用ルータ:SIM2
 奥さんのCP-D02:SIM3
・2014/06頃の変更点
 JIAYU F1購入。使い勝手が良かったので、メイン機に変更。
 メイン機JIAYU F1:SIM4
 予備機CP-F03a:SIM1
 奥さん実家の緊急用ルータ:SIM2
 奥さんのCP-D02:SIM3

・2014/11頃の変更点
 GMOBBのWiMAXを使い始めたのでメイン機SIM4の使用量低下

・2014/12頃の変更点
 自宅のフレッツが微妙に不安定なことが多いので、奥さんCP-D02のWiFiをオフにしてみた。

Zwatchの天気情報の日本語化とYahoo Weather RSS Feedの日本語表記

ZWatchの天気情報は、アメリカのYahooが提供する「Yahoo Weather RSS Feed」を使用して取得しています。
日本の都市もいくつか登録されています。
パソコンから確認するにはhttp://weather.yahoo.com/にアクセスすると良いでしょう。

ただ、英語表記の天気だとどうにもわかりにくいです。
それなりに日本語にしてみました。

10年ぐらい前にやったMiranda ICQのYahoo Weather pluginの翻訳例が流用できないかなぁ、と期待したんですが、確認してみると、当時と表記が全然違う模様。
ニュアンスはコレでいいんだろうか?とか悩む点がいろいろありますが、訳してみました。

zwatch010

手法は/system/app/IndroidWeather.apkをapktoolでばらしてres/value-jaを作成して、再構成、というもの。

できあがったものはこちら→「v2.2のIndroidWeather.apkを元にした改造版
 (v2.3のIndroidWeather.apkを元にした改造版)

インストール手法
1. MoreLocale2を入手
 上記URLでapkファイルが配布されています
2. MoreLocale2をZwatchにインストール
 手法は問いません
3. Zwatch上でMoreLocale2を起動し、「ja_JP」に設定
zwatch002
zwatch004
 コレにより時計盤の曜日表示が日本語になります(英語のままの時計盤もあります)
4. IndroidWeather-mod.apkをZwatchの/sdcard/に転送
5. Zwatchにadb接続し、rootユーザになる
6. Zwatchの/systemをread/write可能に設定
7. /system/app/IndroidWeather.apkを置き換える
 「cp」は無いので「busybox cp」を使う
8. /system/app/IndroidWeather.apkのパーミッションを755にする
9. 再起動(必須
10. 「天気」の設定画面から「都市の選択」し「Japan」→各都道府県を選択
zwatch005
zwatch006
zwatch007
zwatch008
zwatch009

再起動しないと、時計内の天気表示がうまくいかないようです。
上記の手順で分からない人は対象にしていません。

ちなみに、天気の翻訳は以下の様に対応付けてます。
「Yahoo Weather RSS Feed」の日本語翻訳例が見当たらなかったので掲載しときます。

0	tornado                 暴風
1	tropical storm          熱帯系風雨
2	hurricane               台風
3	severe thunderstorms    酷い雷雨
4	thunderstorms           雷雨
5	mixed rain and snow     雨/雪
6	mixed rain and sleet    雨/みぞれ
7	mixed snow and sleet    みぞれ/雪
8	freezing drizzle        氷混じりの霧雨
9	drizzle                 霧雨
10	freezing rain           凍るぐらいに寒い
11	showers                 にわか雨
12	showers                 にわか雨
13	snow flurries           しゅう雪
14	light snow showers      にわか雪
15	blowing snow            地吹雪
16	snow                    雪
17	hail                    雹(ひょう)
18	sleet                   みぞれ
19	dust                    砂塵
20	foggy                   霧
21	haze                    薄霧
22	smoky                   黒霧
23	blustery                快晴
24	windy                   快晴
25	cold                    寒い
26	cloudy                  曇り
27	mostly cloudy (night)   おおむね曇り(夜)
28	mostly cloudy (day)     おおむね曇り(昼)
29	partly cloudy (night)   所により曇り(夜)
30	partly cloudy (day)     所により曇り(昼)
31	clear (night)           雲が無い(夜)
32	sunny                   雲が無い(昼)
33	fair (night)            晴れ(夜)
34	fair (day)              晴れ(昼)
35	mixed rain and hail     雨/雹(ひょう)
36	hot                     暑い
37	isolated thunderstorms  所により雷
38	scattered thunderstorms 散発的な雷
39	scattered thunderstorms 散発的な雷
40	scattered showers       散発的な雨
41	heavy snow              大雪
42	scattered snow showers  散発的な にわか雪
43	heavy snow              大雪
44	partly cloudy           所により曇り
45	thundershowers          雷雨
46	snow showers            にわか雪
47	isolated thundershowers 所により雷雨

WebminのapsupsdモジュールをRHEL/CentOS6対応にしてみた

RHEL/CentOS 6.4にて、Webminを使って管理をおこなおうとしている。

サーバはapcupsdを使って停電対策をとることにした。
apcupsdの中には、WebでUPSの状態を確認できるようにcgiが添付されている。
これをWebminに組み込めないか確認した。

公式サイトでは「http://download.webmin.com/download/modules/apcupsd-0.81-2.wbm.gz」にそれっぽいものがある。

とりあえず、これを使ってみたところ、以下の問題点があった。

・cgiのパスが、apcupsd-0.81-2.wbm.gzの標準設定では/etc/apcupsd/
・WebminでUPSステータスを見ると、ヘッダが見える形で表示されてしまう。

これをとりあえず解消したものを作成した。

http://blog.osakana.net/sw/apcupsd/apcupsd-mod4.wbm.gz