2010年 7月 5(月曜日)
blogシステムserendipityをchromeで編集できるようにするパッチChromeブラウザでserendiputyの管理者スィートを立ち上げた場合、警告(alert)が度々表示される不具合があります。"mozilla < 1.3 beta is not supported"というものです。これをfixするパッチを作りました。 serendipity-chrome.patch これは、Safari系ブラウザに共通なもののようです。このアラートは、Geckoエンジン(SafariはKHTMLのような?)の場合に、リリース日時を調べて、一定以上昔の場合に表示されています。通常はこれでOKなのですが、Safariの場合はちょっと動作が違っていて、初期リリース(1.0版)のリリース日時を返すとのこと。このため、必要以上に古い日時が返されて警告が表示されていました。 Safari系のブラウザ(Safari, Chrome)は新しく、時期的に"< mozilla 1.3"とかいうことはありませんので、単純に警告を抑制することにしました。実際には、AppleWebKitを使っているものに対して抑制します。調べていませんが、このモジュールが上記動作をしていると思われます。 もしかしたら、serendipityの最新リリースでは直っているかもしれません。(ソースコメントに、この部分の実装が不完全なことが注記されていますので)
2010年 7月 2(金曜日)
中小規模の会社ネットワーク その2こちらの続きです。 ゲートウェイ名前の通り、外(インタネット)とのやりとりはすべてこの機器によって中継されます。通信パケットフィルターによって、危険性のある通信を遮断し、内(イントラネット)を安全に保つことができます。常時起動であることと、外との通信が容易であることから、DNSやウェブサーバとメールサーバ、NTP等を稼動するのに最適ですし、パケットフィルタリングだけでは処理能力に余裕がありますので、各種のネットワークサービスを稼動することとします。勿論、サービスが重くなれば、他にサーバを立てて処理を分散することも可能です。 GatewayとNATゲートウェイでは通信を中継する際に、ポリシーに沿ってパケットフィルタリングを行います。要するにファイアウォール(防火壁、firewall)を構築します。代表的なポリシーは「何も通さない」と、「内からの通信は許し、外からの通信は遮断」です。いずれにしても、外(インタネット)からのアクセスはゲートウェイ内で処理し、内(イントラネット)には通さないことが原則になります。この場合、イントラネットはプライベートアドレス(192.168.0.0/16、もしくは、172.16.0.0/12)を使うことができます。 何も通さない基本的に、内(イントラネット)からも外(インタネット)からも通信を開始されることはありません。全てのパケットはゲートウェイ内で破棄されます。その代わり、proxyをゲートウェイ内で稼動し、アプリケーション層で中継することになります。proxyでは通常、内から外へのウェブアクセスとFTPを許可します。アプリケーションはproxy対応が必要となります。 内からの通信は許し、外からの通信は遮断NATです。内からの通信はゲートウェイのIPとポート番号を持つ通信として第3,4層(TCP/UDP/IP層)で外のサーバに転送(forward)されます。これは外のサーバからも、内のPCからも透過的ですので、通信プログラム(サーバ、アプリケーション共)はNATの存在を意識する必要はありません。 イントラネットからの自由なインタネットの利用を妨げたい特段の理由がなければ、スモールオフィスには適したポリシーです。特段の理由とは、例えば、「P2Pやメッセンジャーが帯域を圧迫するのを防ぐ」、「内からの機密データ流出を完全に阻止したい」、「社員がインタネットで遊んでしまわないようにする」などでしょう。 実装手段LinuxのNAT実装であるIPマスカレードを含むIPフィルタであるIPTablesを使います。設定の概要は以下の通りです。 $IPTABLES = "/sbin/iptables" $EXTDEV="ppp0" #-- インターネットに通じるPPPOE仮想NICデバイス $POEDEV="eth0" #-- インターネットに通じる物理NICデバイス $INTDEV="eth1" #-- イントラネットに接続されたNICデバイス $INTRANET="192.168.7.0/16"
まず、基本的なポリシーです。外には出られて、中には入れない。 $IPTABLES -P INPUT DROP $IPTABLES -P FORWARD DROP $IPTABLES -P OUTPUT ACCEPT
ローカルホストとイントラネットからのアクセスは受け入れる #--- allow access from lo, internal_net $IPTABLES -A INPUT -i lo -j ACCEPT $IPTABLES -A INPUT -i $INTDEV -j ACCEPT $IPTABLES -A FORWARD -i $INTDEV -j ACCEPT
インタネットからは、イントラネットから開始された通信中であるパケットのみ受け入れる。 $IPTABLES -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT $IPTABLES -A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT $IPTABLES -A FORWARD -i $EXTDEV -m state --state NEW,INVALID -j DROP $IPTABLES -A INPUT -p tcp ! --syn -m state --state NEW -j DROP ウェブサーバへのインタネットからのアクセス(http, https)だけを受け入れる。 $IPTABLES -A INPUT -p tcp -m state --state NEW,ESTABLISHED,RELATED --dport 80 -j ACCEPT $IPTABLES -A INPUT -i $EXTDEV -p tcp --dport 80 -j ACCEPT $IPTABLES -A OUTPUT -o $EXTDEV -p tcp --sport 80 -j ACCEPT $IPTABLES -A INPUT -p tcp -m state --state NEW,ESTABLISHED,RELATED --dport 443 -j ACCEPT $IPTABLES -A INPUT -i $EXTDEV -p tcp --dport 443 -j ACCEPT $IPTABLES -A OUTPUT -o $EXTDEV -p tcp --sport 443 -j ACCEPT NATの設定 echo 1 > /proc/sys/net/ipv4/ip_forward echo 1 > /proc/sys/net/ipv4/conf/all/rp_filter $IPTABLES -t nat -A POSTROUTING -o $EXTDEV -j MASQUERADE
2010年 6月 25(金曜日)
中小規模の会社ネットワーク その1小さな会社や、個人商店に最適なネットワーク構築です。これから、何回かに分けて解説をします。 情報システム(IS/IT)会社のネットワーク構築にはSI(社内/社外)が入り、少なくない予算と多くの機材、設備を要するという考え方が一般的です。このため、ここで紹介するものの極限的にシンプルさに驚かれるかもしれません。しかし、機能や性能は必要に応じて増やすことができますので、基本的な構成はシンプルにできます。よほどの大企業でもなければ、どこでも充分に使えるものと思います。実際、このような構成は私の発明ではなく、10年前までは(大企業でも)普通に使われていたものです。現在のIS/ITへの投資は、得られる効果に比して過剰品質なのではないでしょうか。 機能としては、社外に対しては、ウェブ、ファイル転送、リモートシェル(リモートログイン)を提供し、社内にはファイアウォールに守られたイントラネット、DNS、DHCP、ウィンドウズのドメインコントローラ、ファイルサーバと共有プリンタを提供します。ウィンドウズネットワークとしては、ワークグループの他に、ドメインログオンを提供することも可能です。 利点- 汎用の技術、機材を使っていますので、ソフトウェアの機能追加、ハードウェアの性能向上と価格下落の恩恵を享受できます。
- 安価です。ソフトウェアはフリーソフトですし、ハードウェアも、中古PCを使えば5千円以下の機材で構築できます。(実際、最新の機器は必ずしも必要ありません)
- ランニングコストが安い。機器が少なくて電気も食いませんので、特別なマシンルームなども不要です。
- スケーラビリティはありませんが、数十台〜数百台のネットワークには充分です。パーツも汎用のものなので、ファイル容量なども(通常の企業システムよりは)簡単に大きくすることができます。
構成構成は以下です。Linux PCをゲートウェイとし、その上で種々のサーバを稼働します。 ルーター/ブリッジハードウェアは通信会社から提供される機器を使います。回線は光Fletsか同等の回線を利用すれば良いです。もしかすると場所にも依るかもしれませんが、公称100Mbps、実効で上り下り共30Mbps程度は出るようです。なお、ウェブ等サーバとして提供する場合には、上り回線の帯域が必要になりますので、ADSLは使えません。 プロバイダ(ISP)は固定IPアドレスを取得できるところを選びます。最安値で500円/月程度からあります。固定IPにしないで運用することも不可能ではありませんが、特に疾しいサービスでなければ特にメリットがあるとは思われません。 ゲートウェイハードウェアは汎用PCです。イーサネットポートを増設して100base-Tを2口用意して、一方の口をルータ/ブリッジに、もう片方の口をイーサネットハブに接続します。 信頼性を考えるとサーバPCが良さそうですが、むしろ、省電力と静音を考慮して、メーカ製のスリムタイプが良いと思います。(サーバはファン音がうるさいです)。なお、常時起動が必要でサスペンド等を使うことはありませんので、BIOSで切っておきます。また、起動さえ可能であれば、ディスプレイやキーボードはなくても構いません。(リモートログインでメンテナンスできます) Linux OSを使用します。利用するサーバプログラムは、rp-pppoe (PPPOe)、IPTables (ファイアウォール、NAT)、Bind (DNS)、dhcpd (DHCP)、Apache (Web Serever)、Samba (ウィンドウズ共有)。 イーサネットハブポートが沢山付いたciscoとかの高価なものでなくても、家庭用のもので十分です。端末個数が多い場合は、カスケードして使います。 ワイヤレスLANアクセスポイント特別な設定は必要ありません。ただ、NAT機能が付いているようでしたらOFFにしておき、ブリッジとして使います。 「その2」に続きます。
2010年 6月 23(水曜日)
YahooAuctionSの機能追加ヤフオク向けGreaseMonkeyユーザスクリプトの機能を追加しました。こちらyahooauctions.user.jsです。 変更点は以下の通りです。 - ウォッチリスト画面の表示を「タイトルと画像」に設定するスイッチ(FORCE_TITLE_AND_PICTURE_ON_WATCHLISTをtrueにして下さい)の追加。
- 上記を設定するとウォッチリストが20個/画面になってしまうのを、50個/画面とする。
- ウォッチリストの削除画面から自動で戻る設定をしたときに、"終了したオークション"の削除画面から"開催中のオークション"に戻ってしまう不具合の修正。
なお、"設定する"と言っても、ユーザがボタンを押して、表示を明示的に変更した場合は、そちらが優先されます。 インストールFirefoxで、GreaseMonkeyのアドオンがインストールされていれば、単にクリックしていただくだけでインストールされます。詳しい設定方法は、こちら"ヤフオク用Greasemonkeyスクリプト II"をご覧下さい。 ※ FORCE_TITLE_AND_PICTURE_ON_WATCHLIST に不具合があったので、差し替えました。不具合は、設定しても最初の一回目は反映されないというものです。
2010年 6月 4(金曜日)
ヤフオク ユーザスクリプトの改良ヤフオク画面用ユーザスクリプトを改造しました。改造点は2点です。 - ソート方法が既に指定されていたら、そのまま表示します。
例えば、「価格が安い順」とユーザが設定したらそれに従い、残り時間で再ソートはしません。 - リスト表示形式が、「画像」(画像のみのマトリックス表示)のときにもブラックリストが効くようにしました。
ファイルはこちらyahooauctions.user.jsです。
2010年 5月 28(金曜日)
SKKの入れ替え嵌り易い漢字変換システムにSKKがあります。その名の通りシンプルな単語変換ですが、入力の手順が手書きと似ているところが気に入っています。元々はEmacsに特化したシステムだったこともあり、ユーザも多くはないながらも熱心な人が多いようで、廃れることもなかったので、利用し続けてきました。また、幸いなことに今ではLinux(iBus, SCIM, UIM, XIM), Windows、Macなど多くの環境で利用することができます。 やっと、受託していた開発を納品することができましたので、なんだか無駄なことがしたくなり、SKK関係の不満を解消しようと思い立ちました。 SKKIME on WindowsWindowsにはSKKIMEがあります。本当に素晴しい。これと、XKeymacsがあるおかげでWindows上でも快適に作業をすることができるようになりました。しかし、私が使っていたバージョンでは「IMEをオープンしたときに"かな"に戻す」の設定が効いていないことが、小さな不満でした。特にWindowsではステータスバーがウィンドウから離れた端っこのほうに出るので、いちいち確認していられないのです。 さて、サイトを見てみると新しい版が出ていますので、入れ替えてみました。設定が大幅に変わっているようで、Shift+Spaceを押しても動きません。どうやら、この辺のキーハンドルが自分でできるように変更されたようです。このため、XKeymacsで設定していた"toggle-ime"のキーマップを解除し、skkimeのプロパティ設定のキーマップの設定で、Shift-Spaceを追加して、toggle-imeを設定。これでできました。最新版では、上記の「"かな"に戻す」も動作しています。 この設定を見ていると、もっとカスタマイズできそうなので、以前から気になっていたのを変更することにします。 skkでは"\"(あるいは¥)で句点コード入力モードに入りますが、UNIXと違い、Windowsではディレクトリのセパレータとして"\"自体を入力することが多く、この仕様はちょっと困りものでした。要するに、"\"で"\"が入力されるようにします。同じくキーマップ設定で"\"の "skk-j-mode-map"を"self-insert-char"にして、別のキーに"skk-input-by-code-or-menu"を割当てます。IME起動と"Shift+Space"にしているために空いている"C-\"に設定しました。 SkkInput3 on Linuxこれで気を良くしたので、Linuxのほうも変更してみることにしました。ディストリビューションにはskkinput2が入っているため、こちらをバージョンアップしつつ使っていたのですが、何かの拍子に落ちてしまうこと(しばしばFirefoxと共に落ちる)や、漢字登録ダイアログが消去できなくなってしまうことがあり、解決策を捜していました。 バージョン3版を取ってきてコンパイルしてみると動きそうです。(以前は何故か動かなかった記憶が)。とりあえず、実行ファイルも同じskkinputになるので、同じように使うことができますが、共存は想定されていないようです。 こちらも、そのままでは動かないようです。Xリソースに書いてある設定は効いていないようで、emacs-lispの設定ファイルを作らなくてはなりません。で、".skkinput.el"を作ります。とりあえず、".skk"にリンクすれば良さそうです。(ln -s .skk .skkinput.el) こちらもしばらく使っていた限りでは、前述の問題は解決されています。落ちないようですし、登録ダイアログの動作も申し分ありません。なのですが、原因不明の不具合が発生しており、一時的にバージョン2に戻していて、そのまま乗り換えには至っていません。不具合はFirefox上で"Enter"が入力できなくなってしまうことがある、のと、Backspaceが誤動作(?)することです。skkinput以外の何かの設定が原因かもしれません。
2010年 5月 17(月曜日)
Mouse Wheelのゴム交換マウスは、ボールから光学になって可動部分が減り、大幅に故障が減りましたが、ホィール周りは段々と壊れてくるようで、ネットで沢山ググれます。私の場合は、特に、ホィールに付いている滑り止めのゴムが駄目になってしまうことが多いです。手に汗をかくせいかもしれませんが、ゴムが伸びてきて空回りをしたり、ホィールの外側の部品に当ってしまい回転が悪くなってしまいます。 自己融着テープ今迄、色々なものを貼ってだましだまし使ってみていたのですが、やっと良い修理方法が見つかりました。それは、自己融着テープをホィールに貼る方法です。 自己融着テープはブチルゴム製の両面テープ状のもので、時間が経つとテープ同士の接触面がくっついて一体化します。外面はゴム状です。主に屋外の防水対策に使われることが多いようです。例えばAmazonで検索すると、こんな感じの商品がありますし、HANDSやDIYの店に置いてあります。 修理方法修理方法は簡単で、マウスを分解してホィール部品を取り出し、伸びたゴムキャップを取り除いて、代わりにテープを巻きます。大体、テープを幅1cmくらいの短冊型に切って、それをホィールの幅になるまで伸ばしながら巻き付けていくのが良いようです。 注意点としては、巻き過ぎないように。意外と嵩が増えますので、多く巻くと、周りの部品と擦ってしまいます。一度貼ったテープは二度と層状には剥れないので、削るしかありませんが、デコボコになってしまいます。(下記、失敗の写真。滑り止めになって良い感じでもありますが。見栄えが気になる場合は、全部取り払ってやり直したほうが良いでしょう)
2010年 4月 11(日曜日)
VIA VT6102イーサネットコントローラの不具合解決VIA Technologies Inc.社のチップセットKT600(多分他のファミリにも)には、VT6102(6105とかも)イーサネットコントローラ(NIC)が付いています。このNICはRhine/Rhine IIと呼ばれていて、勿論Linuxでもサポートされているのですが動作上の不具合があり、今に至るもfixされていないようです。しかし、VIAが提供するドライバを使えば解決することが解りました。 不具合の内容不具合は、このデバイスをLinuxで使うとき、長時間コネクション繋ぎっぱなし、もしくは連続して大量のデータの通信をすると、"NETDEV WATCHDOG: eth0: transmit timed out"というwatchdogタイマによるリセットが入ってコネクションが切断されてしまう、というものです。リセット後は再度接続可能になるため、Webなど小まめに切断される通信では問題となりませんので、殆どのユーザは気付かずに使っているかもしれません。 しかし、サーバとして使うなどして、大きなファイル転送などを行うと途中で切れてしまうので、使い物になりません。また、Windowsではこのような不具合は報告されていないようですので、原因はハードウェアバグとしてもドライバソフトウェアでの回避は可能なはずです。 以前に一回調査してみたのですが原因が掴めていないようで、カーネルの残バグとして残っています。対症療法として、ACPIを切れば動くとか、APICを使わなければ動くとか書いてあるものもあり、やってみましたが直りませんでした。(Linuxカーネルでは、何か不具合あると、仕様が必ずしもオープンでないACPIやAPICに原因を求めようとする悪い癖があるような。度々grub.confに色々書き込んで試しています)。結局仕方なく、別途NICカードを差して対処していました。 VIAのドライバ今回、ひょんなことからVIAがLinux向けにドライバの提供を行っていると知り、もしやと思って捜してみたらRhine II向けもありました。ソース提供なのでコンパイルして"rhinefet"というモジュールをロードしてみます。今迄使ってみていますが、不具合は出ていないようです。作業で1GBx40個のファイルを転送しましたが大丈夫です。有難いことです。もしも、この不具合に悩まされているサーバ屋さんがいらっしゃいましたら、このドライバを試してみることをお勧めします。 それにしても、Linuxのサポートが全くなかったり、不具合以外のfirmwareやBIOSのupdateを行わないのは、今や日本メーカだけなのではないでしょうか。酷い場合には、アメリカサイトでは提供しているのに、日本サイトだけには置いていなかったりします。最近もF通のPC(Inetl 865チップセット)でPrescottが使えなくて残念な思いをしました。以前はサポートのことも考えて国内メーカ製の機器を選んでいましたが、今は韓国や台湾を始めとする海外メーカのものを選んでしまいます。 提供してもし不具合が出たらとか、コールセンタへの問い合わせが増えたら困るということなのでしょうけれど。そろそろこういった社内対応優先主義、あるいは事なかれ主義のようなものはやめていただきたいですね。「お客様第一」などと口では言いますが、全然そうなっていません。
2010年 4月 1(木曜日)
PS/2キーボードのUSB化今使っているキーボードのIFはPS/2です。キーボードは機械としてあまり壊れないのと、慣れがあるので、頻繁に換える気になりません。ATプラグが付いているものでさえ未だに現役です。しかし、これからはUSBに統一されていくことは間違いないようです。macや最近のノートPCにはPS/2は付いていませんし、ちょっと前に仕事で使ったデスクトップPCもUSBオンリーでした。私は普段英語キーボードなので、出先にもマイキーボードを持って行くことがあり、そのためにUSBで動くキーボードを用意したいと思っていました。 そんな中、最近、キーボードが一台壊れてしまい、代わりを検討していました。良さそうなHappy Hacking Keyboadも、USBのは少し割高で、PS/2のものであればかなり安く手に入ります。是非を判断するためにPS/2からUSBに変換するアダプターを調べてみましたら、かなり価格が下っていることが分りました。概ね1000円以下で購入できます。しかし、動作検証サイトを見てみると、動いたり動かなかったりするようです。 とりあえず、送料込みで300円の激安品を試してみました。SPEED社の"SPU-UPTS2"という型番の商品です。ネット上での評判は最悪のようです。しかし、結論から言うと、英語キーボードでは問題なく使えます。Windowsでも、macでもLinuxでも。 但し、この商品は日本語キーボードですと、"変換"キーが落ちるそうです。考えてみますと、こんな商品は、どこかが作ったIF変換のICが一個入っているだけみたいなものでしょうから、英語キーボードで動くのは当たり前で、動かなければ不良品の類でしょう。無変換などの離れたキーコードは世界共通部品ではハンドルされていないということなのでしょうね。
2010年 3月 31(水曜日)
watch_videos 形式のURL対応YouTubeにいつの間にか仕様が追加されています。URLに"watch_videos"が付くものがそれで、例えば、<<http://www.youtube.com/watch_videos?more_url=%2F&video_ids=BOjWxqFKA4g....>>の形式です。 YouTubeダウンローダとダウンロードスクリプトでこの対応をしました。このフォーマットのURLのページを開いてみた範囲では、"watch?v=xxx"のURLのページと見た目に違いはありません。このため動作上の違いは分りませんでしたが、いずれにせよ、動画が自動再生されますので、このビデオを取得することになります。 ところで、ソフトウェア的にもこのフォーマットには謎があります。このURLにアクセスすると、<<http://www.youtube.com/watch?v=BOjWxqFKA4g&...>>に転送(リダイレクト)されます。転送先は一見何の変哲もないいつものフォーマットのページのようなのですが、ここから取得した"fmt_url_map"を使うと、直接ダウンロードできないようなのです。取得できるビデオ識別子(watch?v=xxx)を使えばダウンロードできるのですが、実際、見比べてみますと、この2つの"fmt_url_map"は確かに違っているのですが、どう直すのが正解なのか今一不明です。 そこで、ビデオ識別子を使ってページを取得し、その中から"fmt_url_map"を取ることにしました。ビデオ識別子は、"video_ids"パラメタの最初のもののようです。しかし、このフォーマットのURLはサンプルが少ないため確証が持てなかったので、取得できなかった場合はリダイレクトページの中からビデオ識別子を捜すようにしました。 こんな感じです。 #--- YTPid from watch_videos type URL sub GetYtpidFromWatchVideos { my ($url) = @; my $ytid = ""; my $durl = urldecode($url); #--- like http://www.youtube.com/watch_videos?more_url=/ #--- &video_ids=BOjWxqFKA4g,yHeiXcg1M5c,Ki4dgped5d0,2D296Xi2FLY #--- &type=11&feature=featured&no_autoplay=1 if ($durl =~ m![?&]video_ids=([^&,;]+)!) { $ytid = "http://www.youtube.com/watch?v=${1}"; } else { $ytid = GetYtpidFromWatchVideosFromWeb($url); }
Dprint "GetYtpidFromWatchVideos($url)->($ytid)"; return $ytid; } sub GetYtpidFromWatchVideosFromWeb { my ($url) = @_; my $ytid = ""; my $opts = "-q -U \'$UAgent\'"; if ($url =~ m!(http://[^/]+/)!) { $opts .= " --referer=\"${1}\""; } my $cmd = "wget $Options -O - \'$url\'"; Dprint "COMMAND: $cmd"; my @pgcontents = `$cmd`; foreach (@pgcontents) { # Dprint "pgcontents: $_"; chomp(); if (m!<link rel=\"canonical\" href=\"([^\"]+)\">!) { $ytid = "http://www.youtube.com$1"; } elsif (m|\'VIDEO_ID\': \'([^\']+)\',|) { $ytid = "http://www.youtube.com/watch?v=${1}"; } } Dprint "GetYtpidFromWatchVideosFromWeb($url)->($ytid)"; return $ytid; }
これにて、取得に失敗していたビデオが所得できるようになったと思います。
2010年 3月 17(水曜日)
Linuxで使える世界時計
サーバのメンテナンスのために休止したり、データを入れ換えるのは、利用者になるべく不便を掛けないような時刻を選ぶようにしています。最近は海外からのアクセスが結構あるので、海外の時刻が何時なのか気になっていました。ヨーロッパとの時差は何となく実感としてあるのですが、アメリカは今何時なのだろう、と。 それで、良く証券会社の仕事場の映像に出ているような、壁に世界中の都市の時刻を表示する時計が一杯並んでいるようなものが欲しいなと思いました。
検索してみると、意外なことに、こういった世界時計は多くありません。なんだか平気で有料シェアウェアとかになっています。時差があるだけで簡単なものだと思うのですが。このため、時計を横に並べたようなものを自分で作ってみようかとemiclockのソースを取ってきたりしたのですが、残念ながらこれはGPLではないため改造して使うことはできないようです。 zdumpそうこうしている内に、zdumpというプログラムを見つけました。使い方は簡単で、 $ zdump Europe/Pais Europe/Paris Wed Mar 17 06:54:09 2010 CET
これで現在時刻の表示ができました。色々な場所を一度に表示したければ、 $ zdump Europe/London Australia/Sydney Asia/Tokyo Asia/Singapore Asia/Katmandu Europe/Paris \ Europe/Moscow America/New_York America/Los_Angeles Africa/Kinshasa Pacific/Honolulu Europe/London Wed Mar 17 05:55:57 2010 GMT Australia/Sydney Wed Mar 17 16:55:57 2010 EST Asia/Tokyo Wed Mar 17 14:55:57 2010 JST Asia/Singapore Wed Mar 17 13:55:57 2010 SGT Asia/Katmandu Wed Mar 17 11:40:57 2010 NPT Europe/Paris Wed Mar 17 06:55:57 2010 CET Europe/Moscow Wed Mar 17 08:55:57 2010 MSK America/New_York Wed Mar 17 01:55:57 2010 EDT America/Los_Angeles Tue Mar 16 22:55:57 2010 PDT Africa/Kinshasa Wed Mar 17 06:55:57 2010 WAT Pacific/Honolulu Tue Mar 16 19:55:57 2010 HST
というふうにできます。いつも一時に表示したければ、こんな感じで良いでしょう。 $ alias wclock='zdump Europe/London Australia/Sydney Asia/Tokyo Asia/Singapore Asia/Katmandu \ Europe/Paris Europe/Moscow America/New_York America/Los_Angeles \ Africa/Kinshasa Pacific/Honolulu'
worldclock.plさて、これで充分なのですが、ディストリビューションやバージョンによってはzdumpが動かないことがあるようです。何かのバージョン不整合があったのか、私のデスクトップマシンでは最初動きませんでした。いつも同じ時刻(グリニッジ標準時か東京時刻)を表示してしまいます。これは結局zoneinfoのインストールが上手くなかったようで、zoneinfoの少し新しいバージョンを入れたら動作するようになりました。元々はzoneinfo(/usr/share/zoneinfo)に.ics(中身はVCalendar)のファイルしかなかったのですが、追加したら拡張子が付かないバイナリファイル(TZif形式)が追加されてました。 それで、動かない間に、元々の.icsファイを読んでzdumpと同じ動作をするworldclock.pl(worldclock.pl.zip)を作成しました。こちらは少しおまけが付いていて、都市だけで、もしくは都市名に完全に一致しなくても、マッチするものを表示します。 $ worldclock.pl Par 03/17 Wed 03:19:47 2010 SRT America/Paramaribo 03/17 Wed 07:19:47 2010 CET Europe/Paris
こちらも、都市名(Aria/City)を複数指定して、上記のwclockのようにalias等を設定することができます。 #!/usr/bin/perl $Usage = "$0 [-h] [-verbose] [Aria/]city ...\n";
$ZoneinfoDir = "/usr/share/zoneinfo"; @WeekdayName = ("Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"); @MonthName = ("Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"); $Verbose = 0;
#--- interpret the command-line arguments while ($ARGV[0]) { # print STDERR "$ARGV[0]\n"; if ($ARGV[0] =~ /^-D.*/) { $Debug = 1; } elsif ($ARGV[0] =~ /^-v.*/) { $Verbose = 1; } elsif ($ARGV[0] =~ /^-.*/) { print STDERR "$Usage"; exit 0; } else { last; } shift(@ARGV); }
#--- checking to set the necessary variables. #--- DebugPrint function #$Debug = 1; sub Dprint { if (defined($Debug)) { printf STDERR "DBG @_"; } return 0; } Dprint "ARGS($#ARGV): @ARGV\n";
#--- Current time of Greenwich. $gm_time = time() - 9 * 60 * 60;
#--- Check zoneinfo dir if (!-d $ZoneinfoDir) { my @zdirs = `locate /zoneinfo/Asia/Tokyo.ics`; #-- Use the first one without reasons. if ($#zdirs < 0 || $zdirs[0] !~ m|^(.*)/[^/]+/[^/]+$/|) { printf STDERR "$0 zoneinfo directory is not found."; exit(-1); } $ZoneinfoDir = $1; Dprint "ZoneinfoDir ($ZoneinfoDir)\n"; }
#--- Create file list foreach my $arg (@ARGV) { my @matchs_complete = (); my @matchs_partial = (); my $sout = ""; if ($arg =~ m|/|) { #-- Asia/Katmandu if (-f "$ZoneinfoDir/$arg.ics") { push(@matchs_complete, "$ZoneinfoDir/$arg.ics"); } @matchs_partial = glob("$ZoneinfoDir/${arg}?*.ics"); } else { #-- Katmandu @matchs_complete = glob("$ZoneinfoDir/*/$arg.ics"); @matchs_partial = glob("$ZoneinfoDir/*/${arg}?*.ics"); } Dprint "Complete: (@matchs_complete)\n"; Dprint "Partial : (@matchs_partial)\n"; foreach my $zfile (@matchs_complete) { $sout = GetLocalTimeString($zfile); print "$sout\n"; } foreach my $zfile (@matchs_partial) { $sout = GetLocalTimeString($zfile); print "$sout\n"; } }
exit 0;
#--- sub GetLocalTimeString { my ($zf) = @_; my $srtn; open(IN, "<$zf") or return ""; my @czf = <IN>; close(IN); my ($tzsign, $tzhour, $tzmin, $tzname) = ("", "", ""); foreach (@czf) { if (m|TZOFFSETTO:([+-])([0-9]{2})([0-9]{2})|i) { ($tzsign, $tzhour, $tzmin) = ($1, $2, $3); } elsif (m|X-LIC-LOCATION:(.+)|i) { $tzlocation = $1; } elsif (m|TZNAME:([a-zA-Z]{3})|i) { $tzname = $1; } } Dprint "($tzsign, $tzhour, $tzmin, $tzname)\n"; if (length($tzhour) <= 0 || length($tzmin) <= 0 || length($tzsign) <= 0) { return ""; } my $lc_time; if ($tzsign eq "-") { $lc_time = $gm_time - ($tzhour * 60 + $tzmin) * 60; } else { $lc_time = $gm_time + ($tzhour * 60 + $tzmin) * 60; } Dprint "($gm_time, $lc_time)\n"; my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime($lc_time); if ($isdst) { #-- The aria supports summer time. ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime($lc_time + 60 * 60); $tzlocation .= " (ST)"; } $srtn = Fmt($mon + 1, 2) . "/" . Fmt($mday, 2) . " $WeekdayName[$wday] " . Fmt($hour, 2) . ":" . Fmt($min, 2) . ":" . Fmt($sec, 2) . " " . ($year + 1900) . " $tzname " . "$tzlocation";
return $srtn; }
#--- sub Fmt { my ($nbr, $kta) = @_; return sprintf("%0${kta}d", $nbr); }
因みにzoneinfoがあるディレクトリは/usr/share/zoneinfoだと思いますが、これがなかった場合、あるいはあってもVCalendar形式ファイルがなくTZifのバイナリファイルだけの場合には、システム中からlocateで捜します。evolutionの下にあったりするようです。
2010年 3月 16(火曜日)
Type-Map (var)の作成前回、ウェブページの国際化に関して書きました。結論としては、type-mapを使って、.varファイルを作成すれば良いということでした。このtype-mapファイル作成を手作業でやるのは面倒ですので、生成スクリプトmktypemap.pl.zipを作りました。 使い方は以下の通りです。 カレントディレクトリのhtmlファイルとjpgファイルに対してlvarファイルを作成します。 mktypemap.pl *.html カレントディレクトリのファイル全部を対象とし、既にvarファイルがあるときは上書きします。 mktypemap.pl -f .
ここでは、"foo.php"に対して国際化されたファイルが"foo.ja.php"もしくは"foo.php.ja"の形式に対応します。 中身は以下のようなものです。 基本的に各々のファイルに対して言語違いファイルを捜して、それらをまとめて".var"ファイルを作成します。 #!/usr/bin/perl $Usage = "$0 [-h] [-S[imulate]] [-force] [-quiet] [--] files_to_create_var\n";
$Simulate_Mode = 0; #-- all procedure is simulated without creating files. $Verbose = 1; #-- print out many messages. $ForceOverwrite = 0; #-- When not set, .var file isn't created if exist.
#--- interpret the command-line arguments while (defined($ARGV[0])) { # print STDERR "$ARGV[0]\n"; if ($ARGV[0] =~ /^-D.*/) { $Debug = 1; } elsif ($ARGV[0] =~ /^-q.*/) { $Verbose = 0; } elsif ($ARGV[0] =~ /^-f.*/) { $ForceOverwrite = 1; } elsif ($ARGV[0] =~ /^-S.*/) { $Simulate_Mode = 1; } elsif ($ARGV[0] =~ /^-.*/) { print STDERR "$Usage"; exit 0; } elsif ($ARGV[0] =~ /^--/) { shift(@ARGV); last; } else { last; } shift(@ARGV); }
#--- checking to set the necessary variables. #--- DebugPrint function #$Debug = 1; sub Dprint { if (defined($Debug)) { printf STDERR "DBG @_"; } return 0; } Dprint "ARGS($#ARGV): @ARGV\n";
#--- If there are no files in arguments, all files in the current directory should be checked. if ($#ARGV < 0 || $ARGV[0] eq ".") { @files = glob("*"); } else { @files = @ARGV; }
#--- Create file list %typemap_created = (); #--- type-map file created by the program. foreach my $fle (@files) { my ($bdy, $lng, $ext); if (!-f $fle || -d $fle || $fle =~ m|\.var$|i) { next; } elsif ($fle =~ m|~$|i) { next; } elsif ($fle =~ /\.(html|htm)$/i) { #--- at this moment, html is a dummy to transfer to php. next; } elsif ($fle =~ m|^(.*)\.([^.]{2})(\.[^.]+)$|i) { #--- like foo.de.html ($bdy, $lng, $ext) = ($1, $2, $3); Dprint "(FILE 1: ($fle)($bdy, $lng, $ext)\n"; } elsif ($fle =~ m|^(.*)(\.[^.]+)\.([^.]{2})$|i) { #--- like foo.html.de ($bdy, $lng, $ext) = ($1, $3, $2); Dprint "(FILE 2: ($fle)($bdy, $lng, $ext)\n"; } elsif ($fle =~ m|^(.*)\.([^.]{2})$|i) { #--- like foo.de ($bdy, $lng, $ext) = ($1, $2, ""); Dprint "(FILE 3: ($fle)($bdy, $lng, $ext)\n"; } elsif ($fle =~ m|^(.*)(\.[^.]+)$|i) { #--- like foo.html ($bdy, $lng, $ext) = ($1, "ja", $2); Dprint "(FILE 4: ($fle)($bdy, $lng, $ext)\n"; } else { next; }
if ($lng eq "js" || $ext eq ".js") { #-- should be a java script file. next; } if (!$ForceOverwrite && -f "$bdy.var") { next; } elsif (exists($typemap_created{"$bdy.var"})) { next; } my $str = CreateTypeMap($bdy, $ext); if (length($str) > 0) { my $fvar = "${bdy}.var"; if (!$Simulate_Mode) { open(FOUT, ">$fvar") or next; printf FOUT "$str"; close(FOUT); } $typemap_created{$fvar} = 1; } }
exit 0;
#--- Creating contents of type map file sub CreateTypeMap { my ($bdy, $ext) = @_; my @grpfiles = glob("${bdy}${ext} ${bdy}.*${ext} ${bdy}${ext}.??"); Dprint "CreateTypeMap: ($bdy, $ext)\n"; Dprint "@grpfiles\n"; my $s = ""; foreach (@grpfiles) { my ($b, $l, $e); Dprint "CreateTypeMap: ($_)\n"; if (!-f $ || -d $ || /\.var$/i) { next; } elsif (/~$/i) { next; } elsif (/\.(html|htm)$/i) { #--- at this moment, html is a dummy to transfer to php. next; } elsif (/^(.*)\.([^.]{2})(\.[^.]+)$/) { #--- like foo.de.php ($b, $l, $e) = ($1, $2, $3); } elsif (/^(.*)(\.[^.]+)\.([^.]{2})$/) { #--- like foo.php.de ($b, $l, $e) = ($1, $3, $2); } elsif (/^(.*)\.([^.]{2})$/i) { #--- like foo.de ($b, $l, $e) = ($1, $2, ""); } elsif (/^(.*)(\.[^.]+)$/) { #--- like foo.php ($b, $l, $e) = ($1, "ja", $2); } else { next; } if ($l eq "js" || $e eq ".js") { #-- should be a java script file. next; } Dprint "CreateTypeMap: ($b, $l, $e)\n"; my $hder = "URI: $_\nContent-Language: $l"; $cty = GetContenttype($e); if ($cty eq "text/html") { $chs = GetCharset($l); $ctyp = "Content-type: text/html; charset=$chs\n"; } else { $ctyp = "Content-type: $cty\n"; } if (length($s) > 0) { $s .= "\n"; } $s .= "$hder\n$ctyp"; } #if (length($s) > 0) { # $s = "URI: $bdy; vary=\"type,language\"\n\n" . $s; #} Dprint "$s\n"; return $s; }
#--- Get the charset sub GetCharset { my ($lg) = @_; my $c; if ($lg eq "ja") { $c = "UTF-8"; } else { $c = "ISO-8859-1"; } return $c; } #--- Get the content type sub GetContenttype { my ($e) = @_; my $c; if ($e =~ /(jpg|jpeg)$/i) { $c = "image/jpeg"; } elsif ($e =~ /gif$/i) { $c = "image/gif"; } elsif ($e =~ /png$/i) { $c = "image/png"; } elsif ($e =~ /(php|html|htm)$/i) { $c = "text/html"; } elsif ($e =~ /zip$/i) { $c = "application/zip"; } elsif ($e =~ /(tgz|tar)$/i) { $c = "application/x-tar"; } else { $c = "application/octet-stream"; } return $c; }
なお、このコードでは、"#--- at this moment, html is a dummy to transfer to
php."のところにあるように、".html"に対しては".var"ファイルを作成しません。これは私は".php"としてコンテンツを作成している
ためで、".html"は昔からあるコンテンツや外部からのリンクが切れないように転送ページを置いています。 このファイルは以下のようなものです。 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <html lang="ja"> <head> <title>301 Moved Permanently</title> <meta http-equiv="refresh" CONTENT="0;URL=index.var"> <meta name="robots" content="NOINDEX,NOFOLLOW"> </head> <body> このページは、<a href="index.var">http://www.nikep.net/</a>に移転しました。 自動転送されない場合は、このアイコン<a href="index.var"><img src="home3.png"></a>を 押して下さい。<br/> Requested page was transfered to <a href="index.var">http://www.nikep.net/</a>. If you can see this text, please click the following icon <a href="index.var"> <img src="home3.png" alt="nikep"></a>. </body> </html>
2010年 3月 11(木曜日)
Apacheの多言語化壁紙サービス(アプリ)を国際化して、海外のサイトで配布しています。意外にも、国内よりも海外のほうで使ってくださる人が多く、サイト自体のアクセスも海外からが増えてきました。そのため、最近は少しずつ英訳を進めています。しかし、ページが増えてくると、色々と課題が出てきて手作業が増えてきましたので、システマチックな方法で対応することにしました。 ページの英訳ページを英訳するには、以下の作業を行います。 - 内部テキストを英語に翻訳します。
- ページに記載されたハイパーリンクで、既に翻訳済みページがある場合は、そちらを差すようにします。埋め込みのイメージファイルに関しても同様にします。
- 当該ページにアクセスする際の(別ページ等にある)リンクを、英語言語リーダ向けには英語のページに変更します。
この内、テキストの翻訳は手で行うしかありませんが、2)や3)は手作業でやるのが手間になってきたのと同時にバグったりしてきました。このため、2)に関してはPHPで関数を書いて対応していたのですが、3)の対応を行うに際し、Web Server (Apache)の機能を調べてみました。 国際化の方法apacheの国際化の方法は2種類あります。いずれの方法も、閲覧者から指定された"Accept-Languages"を参照して、適切な言語のファイルを自動的に返す仕組です。 | 方式 | 設定 | やり方 | 課題 | MultiViews | httpd.confに"Options MultiViews"を設定する。(通常デフォルト) | foo.htmlに対して、foo.html.en, foo.html.jaを配置する。foo.htmlは置かない。 foo.htmlにアクセスすることにより、言語に合わせたfoo.html.xxが返される。 | 直感的で簡単。 処理が遅いらしい。 foo.htmlを置けないのは気持ちが悪い(置くと直接アクセスでこちらが開かれてしまう) | Type-Map | httpd.confに "AddHandler type-map var"を設定する。(通常デフォルト) DirectoryIndex index.var index.php index.html 等と書く。 | foo.varを作成してfoo.en.html, foo.ja.htmlなどを配置する。foo.htmlは置かない。 foo.varにアクセスすることで、ファイル内に設定された適切な言語に合わせたファイルが返される。 | こちらの方法のほうが新しい。 処理が速いとのこと。 別ファイルを置かなくてはならないのはちょっと嫌。(もしくは、foo.htmlをvarファイルにすることも可能) |
特に理由がなければ、Type-Mapの方法を使うのが良さそうです。 実際の設定foo.htmlに対して、foo.varのファイルを作成して、URLをfoo.varでアクセスさせることになります。ファイルは以下のようなものです。 URI: foo.en.php Content-type: text/html Content-language: en
URI: foo.ja.php Content-type: text/html;charset=utf-8 Content-language: ja
そして、国際化したページ全てのページに対して xxx.var を作成し、リンクを全て xxx.var を差すように変更します。 なお、例えばindexファイルであれば、DirectoryIndex に index.varを追加しないとならなりません。(これは、httpd.confの設定を変更します。なお、phpのバージョンに依っては、php.confの設定も変更/削除しないとならないかもしれません) これでOKなのですが、実際に想定されている使い方とは少し違うようです。apacheのmanualディレクトリでType-Mapが使われているのですが、ここではindex.htmlをvarファイルにしています。動作させるためには、SetHandlerが必要になります。 <Directory "/var/www/manual"> <Files *.html> SetHandler type-map </Files> </Directory>
このようにすると、外部からのURLを変更する必要がありませんので、透過的に設定することができて便利です。要するに、htmlファイルと思ってアクセスすると実体はtype-mapファイルで、その設定に従って適切なファイルが実際には返されることになります。 但し、この設定をしてしまうと、単なるhtmlファイルとして扱うこと(中身がtype-mapでないtext/htmlであればそのまま返すなどということ)はできなくなります。これはサブディレクトリにも伝播してしまいますので、取り扱いには注意が必要です。
2010年 3月 11(木曜日)
Happy Hacking Keyboardの設定
キーボードが壊れかけているのか押し難いキー出てきたので、中古のHappy Hacking Keyboard Lite (HHK Lite)を購入しました。一番安価なやつですが、それでもキータッチはかなりよく思います。(安物ばかり使ってきたせいもありますが)。このキーボードは昔のSUNのワークステーションと同じキー配列とのことで、backquote/asciitildaとBSの配置が少し変っています。またHHK Liteには独立の方向キーがないためにWindowsではちょっと使い難そうですので、UNIXがメインのマシンに付けることにしました。
若干のカスタマイズを施しました。OSはLinuxとWindowsXPです。 キーボードはディップスイッチの設定があり、若干のカスタマイズができます。私は使いませんが、日本語変換用のHenkan, Muhenkanのキーコードも出せるようです。さて、Fnキーの位置も特殊なので左下に設定したかったのですが、オリジナルのFnキーは動かすことができず、あきらめました。只でさえキーが少ないのに、これ以上減らすわけには行かないからです。 結局、DIPスイッチ、"1101"として、ここからはソフトウェア的にカスタマイズすることにします。スペースの横列は左から、Win_L, Alt_L, Space, Alt_R, Win_Rです。方法は、こちらに記載した方法を取ります。
個人的には右のキー(Alt_R, Win_R)は使わないので、足りないキーである Application (LinuxではMulti)キーと、BSにしてしまったために独立キーがなくなっているDeleteキーに割当てます。(Alt_R→Application、Win_L→Delete)。因みに 元々存在していないCaps_Lockは、ソフト的には設定することができないようです(?)ハードウェアでShift+TABでCaps_Lockトグルになります。
Linux/Xでは Xmodmapで設定します。
remove mod4 = Super_R
keycode 113 = Multi_key
keycode 116 = Delete
また、Windowsではレジストリをいじります。レジストリファイルはus_WinrDel_AltrApl.regです。これで快適になりました。
と思ったのですが、上で追加したDelete(元々の右Win/刻印は右Alt)はキーリピートが入らないようです。これはモディファイア系のキーはリピートしないというハード的な仕様なのでしょうね。仕方ないです。Xmodeを上記にしたらできました。
2010年 2月 13(土曜日)
朝日新聞サイト向け マーキー削除 II前回、ティッカー(marquee)を取り除いたのですが、今日から仕様が変更になったようです。以前は"TopBnr"というIDでしたが、"tickerAnchor"になったようです。そのため、ユーザスクリプトを修正しました。ここ(asahis.user.js)です。
|