wodimコマンドが手軽ということを聞いたので、インストールして焼いてみました。
続きを読む →社内ツールとして、複数の DXF ファイル内にある文字列を一括で変換するスクリプトを組みました。スクリプトとは言っても、ファイルを列挙して一括置換させるだけのシンプルなものでした。
続きを読む →財団法人 流通システム開発センターで公開されている JAN コードの仕様に基き、与えられた文字列が正しい JAN コードであるか否かを返すシェルスクリプト関数です。
続きを読む →以前、ブログでも取りあげたbsdgamesパッケージにあるmorseコマンドを利用して、ビープ音(PCスピーカー)でモールス信号を再生するスクリプトを書いてみました。 ビープ音の再生には、自由に周波数と再生時間を指定する事が出来るbeepコマンドを利用しました。
#!/usr/bin/env bash
f=1800 # 周波数
#正確な再生単位
b=60 # 単位長さ
t=$(($b*1)) # 短点長さ
w=$(($b*3)) # 長点長さ
s=$(($b*1)) # 無音長さ
n=$(($b*3)) # 次の文字との無音長さ
#こっちの方が聞き易い気がする
#b=50 # 単位長さ
#t=$(($b*2)) # 短点長さ
#w=$(($b*6)) # 長点長さ
#s=$(($b*1)) # 無音長さ
#n=$(($b*3)) # 次の文字との無音長さ
morse $@ | while read line
do
echo $line
opt=$(echo '$line' | sed \
-e 's/dit/ -n -f $f -l $t -n -f 1 -l $s/g' \
-e 's/daw/ -n -f $f -l $w -n -f 1 -l $s/g' \
-e 's/^ *-n *//')
if [ "$opt" ]; then
beep $opt -n -f 1 -l $n
else
beep -f 1 -l $n
fi
done
$(()) での計算を行っている為、bash依存です。適宜、exprなどに置き換えれば他のシェルでも使えるはずです。 無音部分は、周波数1Hzの音を再生する事によって実現しています。 実行すると、以下のように表示され、ビープ音でモールスが再生されます。
$ sh bmorse hello
dit dit dit dit
dit
dit daw dit dit
dit daw dit dit
daw daw daw
dit dit dit daw dit daw
ビープ音に加えて、赤外線送信デバイスをチカチカ光らせて遊んでみたいです。
※ 2020/07/02 度重なるブログ移転・ブログシステムのアップデートにより崩れた記事を校正。
NEC LifeTouch NOTE に、SHARP IS01 のハードウェアキーボード向けにカスタマイズされた SKK for Android をインストールし使ってみた感想を書きましたが、作者の ray_m さんにコメントを頂き、修正を施したとの事だったので、早速使ってみました。
修正がほどこされた点をかいつまんで紹介します。
IS01 の特殊キーは、同時押しではなく、キーを押した次のキーに作用するように出来ています。 これは QWERTY ハードウェアキーボードを搭載していても、サイズ自体が小さい為、同時押しがしづらい物理的な問題に対処するものだと考えられます。例えば、IS01 で大文字の ‘A’ を入力する場合、Shift キーを押した上で、( 押しっぱなしにしても、離してしまっても、Shift 押下状態が続くので、その直後に ) a キーを押す事によって入力する事が出来ます。自分の IS01 は電話専用機になってしまっているので、SKK を導入する必要はないですが、LifeTouch NOTE や Dynabook AZ のようなネットブックに匹敵するサイズの QWERTY キーボードを搭載している Android 端末上では、SKKer にとって、キラーアプリになるくらい外せないアプリになっています。
前回の記事は、SKK for Android をインストールしたその夜に使い勝手を調べながら書いたものですが、それから 1 ヶ月以上使ってみて、ますます満足しています。残すは変換候補の表示位置のみといったところでしょうか。
LifeTouch NOTE は、せっかく左にある Menu キー( IBM-PC キーボードで言う CapsLock の位置 )を Ctrl キーに変更する設定項目まで搭載してくれているのに、Android 自体の仕様が全体的に Ctrl キーをサポートしていないのが残念な限りです。自分に課題を出すとすれば、確定 C-j やキャンセル C-g を多用している SKKer としても、”C” になるキーを指定させてそれらをサポートしたいところです。
ray_m さんから新しいバージョン 1.4 のご連絡があり,早速試してみると,変換候補の表示位置がずれてしまう現象が解消されたようです.
また,上の記事には書いていませんでしたが x キーによる小文字(っ,ぁ,ぃ,ぅ …など)にも今回のバージョンから対応しているようで,使用感はほとんど Emacs や SKKIME と変わらなくなっています.
さらに SKK 使いでフルキーボードを搭載している Android 端末ユーザには,離せないアプリになっていると思います.
※ 2020/07/02 度重なるブログ移転・ブログシステムのアップデートにより崩れた記事を校正。
NURBS 曲線の knot 値( Bスプライン基底関数を決定する為の値 )は、一般的に下記のように ( 階数 + 制御点数 ) 個の単調増加する配列として表されます。
T = [ 0 0 0 0 1 2 3 3 3 3 ]
一方、OpenCASCADE Draw Test Harness の bsplinecurve コマンドにて上に示す knot 値を持つ NURBS 曲線を生成するには、下記のように指定する必要があります。
0 4 1 1 2 1 3 4
太字部分は knot 値自体を示すのではなく、”直前にある knot 値をくりかえす回数” を示します。Draw Test Harness の公式リファレンスでは誤った記載で引数の解説がなされていた為、少し迷いました。仮に、前者を Plain knots array、後者を Compressed knots array と呼ぶと、下記のような相互変換を行う Perl スクリプトが組めます。
#!/usr/bin/env perl
# Plain knots array to Compressed knots array
# for Draw Test Harness of OpenCASCADE
sub pKnot2cKnot {
my @pKnot = @_;
my @cKnot = ( );
my $bfr = -1, $nb = 0, $i = 0;
foreach $val ( @pKnot ) {
if ( $val != $bfr ) {
$cKnot[$i++] = $nb if ( $i > 0 );
$cKnot[$i++] = $bfr = $val;
$nb = 1;
}
else {
$nb++;
}
}
$cKnot[$i] = $nb;
return @cKnot;
}
# Compressed knots array to Plain knots array
sub cKnot2pKnot {
while ( length( $val = shift( @_ ) ) ) {
$buf .= ( "$val " x ( shift( @_ ) ) );
}
return split( " ", $buf );
}
このような仕組みを使って、ある三次元 CAD 形式のファイルから Draw Test Harness 経由で、BRep モデルを作成する事が出来ました。ひょっとしたら pKnot2cKnot() は、もう少しスマートに出来るかも。
度重なるブログ移転・ブログシステムのアップデートにより崩れた記事を校正。ついでに Ruby で書き直してみました。
#!/usr/bin/ruby
def pknot2cknot(str)
ar = []
c = 1
x = nil
str.split(' ').each_cons(2) do |n, m|
if n != m
ar << [n, c]
c = 1
else
x = n
c += 1
end
end
(ar << [x, c]).join(' ')
end
def cknot2pknot(str)
Hash[*str.split(' ')].map{|n, m|"#{n} "*m.to_i}.join.strip
end
p pknot2cknot("0 0 0 0 1 2 3 3 3 3") # => "0 4 1 1 2 1 3 4"
p cknot2pknot("0 4 1 1 2 1 3 4") # => "0 0 0 0 1 2 3 3 3 3"
劇的に小さくなると思いきや、そんなことなかったのが残念。
Array#partition でも Array#group_by でもなく、配列から隣合う要素を比較し、区切りを見つけて多次元配列を返すメソッド…ないかなぁ。
無駄がなくて綺麗なコード。やっぱり Python って素敵。
#!/usr/bin/env python # -*- coding: utf-8 -*- import socket, string # ソケット作成、接続、ログイン irc = socket.socket( socket.AF_INET, socket.SOCK_STREAM ) irc.connect( ( 'irc.example.com', 6667 ) ) irc.send( ''' USER arianne * * arianne NICK arianne JOIN #hogefuga ''' ) while True: # recv() で、受信するまでブロッキング buf = unicode( irc.recv( 1024 ).strip(), 'utf-8' ) # コマンドプロンプトの場合は、'cp932' を指定 print buf.encode( 'utf-8' ) # IRC サーバから PING が来たら PONG を自動応答する if string.split( buf )[0] == "PING": irc.send( "PONG " + string.split( buf )[1] + "\n" ) # 文字列に反応してみたり if buf.find( u"こんにちは" ) > -1: irc.send( u"PRIVMSG #hogefuga :こんにちわぁ\n".encode( 'utf-8' ) )
車輪の再発明だと思いつつ、自分の使い易い形のクラスにしてみた。サーバー応答対応やエラーと例外処理が未実装だけれど「スレッド化した受信監視→外部から指定されたイベントハンドラ実行」は、これで・・・いけるはず・・・。もうちょっとスマートに書けるようになったらいいな。
#!/usr/bin/env python # -*- coding: utf-8 -*- import socket, string, threading import logging class ircc ( object ): """The IRC Client Class""" def __init__( self, hostname, port, server_encoding='utf-8', terminal_encoding='utf-8' ): # ソケット作成 self.server = socket.socket( socket.AF_INET, socket.SOCK_STREAM ) self.server.connect( ( hostname, port ) ) self.server_encoding = server_encoding self.terminal_encoding = terminal_encoding script_encoding = 'utf-8' logging.basicConfig( level=logging.DEBUG, format='%(asctime)s %(levelname)s %(message)s' ) def __str__( self ): return 'ircc' def send( self, message ): # 渡された文字列をサーバに送信するだけ message = unicode( message, self.script_encoding ) logging.debug( ">>> " + message.encode( self.terminal_encoding ) ) self.server.send( message.encode( self.server_encoding ) + "\n") def recv( self, receive_size = 1024 ): # サーバから文字列を受信するまで待機 buf = unicode( self.server.recv( receive_size ).strip(), self.server_encoding ) for line in string.split( buf, '\n' ): logging.debug( "<<< " + line.encode( self.terminal_encoding ) ) return buf # こういう細々とした IRC コマンドは、はたして個別に実装する必要があるのかニャー def quit( self, message = '' ): self.send( 'QUIT :' + message ) def nick( self, nickname ): self.send( 'NICK ' + nickname ) def join( self, channel ): self.send( 'JOIN ' + channel ) def privmsg( self, to, message ): self.send( 'PRIVMSG ' + to + ' ' + ' :' + message ) # ログイン・フェイズはエラー処理が重要になってくるので、メソッド化しておく。 def login( self, loginname, nickname, description, wait_for_motd = True ): self.send( 'USER %s * * :%s' % ( loginname, description ) ) self.nick( nickname ) #if self.recv().find( '433' ): # self.quit() # return 1 while wait_for_motd: if self.recv().find( ' 376 ' ): break # イベントハンドラ、send()、recv() それぞれのアドレスを渡してスレッド化 def set_event( self, event_handler ): _irc_recv_thread( event_handler, self.send, self.recv ) class _irc_recv_thread( threading.Thread ): """ メッセージイベントを検知し、外部から定義された イベントハンドラを呼ぶスレッドオブジェクト """ def __init__( self, event_handler, send_handler, receive_handler ): self.__event = event_handler self.__send = send_handler self.__receive = receive_handler self.__msg = '' threading.Thread.__init__( self ) self.setDaemon( True ) self.start() def run( self ): while True: # メインループ self.__msg = self.__receive() if len( self.__msg ) > 0: for line in string.split( self.__msg, '\n' ): if string.split( line )[0] == 'PING': self.__send( 'PONG ' + string.split( line )[1] ) self.__event( line ) else: break
使うのは、以下のようなイメージで。
#!/usr/bin/env python # -*- coding: utf-8 -*- import ircc # イベントハンドラ def check_message( msg ): if msg.find( u"こん" ) > -1: irc.privmsg( '#hogefuga', 'こん' ) irc = ircc.ircc( 'irc.example.com', 6667, 'utf-8' ) irc.login( 'arianne', 'arianne', 'Arianne the BOT', False ) irc.join( '#hogefuga' ) # イベントハンドラを登録 irc.set_event( check_message ) while True: pass # 何か他の事でもやる
んー、クラス化するメリットが少ないかも。日々使ってないとすぐ忘れるタチなので、wxPython/PyGame なんかと一緒に IRC プロトコルを使った通信将棋やチェスでも書きたいなぁ。
※ 2020/07/02 度重なるブログ移転・ブログシステムのアップデートにより崩れた記事を校正。Python なのにインデントがすべて吹き飛んでいるので間違いがあるかも…。
Google 検索で、「intitle:”index of” mp3 Description」といったキーワードで検索してみると、著作権法に保護されているはずの音楽ファイルが大量に、かつダウンロード可能な状態でヒットします。サーバ管理者/サイト運営者のデータ置き場が誤って公開状態になっていただけでは、Google の BOT は検索結果データベースに登録する事は出来ないはずなので、少なくともどこかパブリックな場所からリンクを貼られ、そこから自由にダウンロード出来るようになった結果ではないかな、と思いました。
Youtube やニコニコ動画といった動画サイトで、著作者以外がコンテンツをアップロードして共有する事は珍しくなくなりましたが、同時に手軽に著作物を公開してしまおうという敷居も低くなった気がします。Warez などのように、コンテンツがそのままの状態では使用できないように、何重にも工夫( ファイル分割やパスワード付与、URL の隠蔽… etc. )していた頃に比べて、必死さが見受けられないというか、悪い事をしている意識が見受けられないというか。まあ、それに関しては「ユーザのモラルが下がってるというか、エンドユーザが増える事による危機感の低下かなー」程度の感想しか持っていません。自分もそんなに危機感をビシバシ持ってるタイプではありませんが、root として最低限の事はしているつもりです。
* * *
MP3 以外にもいろいろなものが”おおっぴら”に落ちているので、Google 検索を眺めていったところ、ある PHP スクリプトファイルを見つけました。その PHP ファイルにアクセスすると、スクリプトが実行され、カレントディレクトリのファイル一覧に加えて、基本的なファイル操作用のコマンドボタンがいくつか、さらに exec コマンドをブラウザ経由でサーバに実行させるインタフェイスが付いていました。
その PHP スクリプトは誰が作ったものか分かりませんが、スクリプト経由で確認した PHP スクリプトファイルがあるディレクトリのパーミッションは 777。どうやら、誰かが仕込んだもののようでした。
ブラウザ経由からサーバに任意コマンドを実行させて結果を表示させるのは、別段、珍しい技術でもなく、むしろそれが出来なければ動的ページを吐けないものです。自分も何年か前に、Perl でコマンドを発行/表示する事が可能なウェブターミナルを書いて、昔の携帯電話のウェブブラウザでも簡単にサーバ管理が出来るようなスクリプトを設置していました。もちろん Basic 認証の下*1にですが。
* * *
「誰かが仕込んだとすれば、どうやって仕込むかなー」と考えた時、PHP アップローダが手軽な事に気付きました。あまりスクリプトに馴染みがないエンドユーザの増加、携帯やスマートフォンなどのアクセス手段の増加、安くて高品質かつ初心者でも手軽に使えるレンタルウェブサービスの増加、簡単に設置できる PHP スクリプトの配布サイトの登場、などなどが相俟って、PHP ファイルをアップロード許可している PHP アップローダが、Google 検索しただけでいくつか見つかりました。PHP スクリプトを配布しているサイトのものをそのまま設置したものや、自作コードによるものでしたが、どうみても危険です。本当にありがとうございました。
ここからはもちろん、自宅のサーバ上で試したものです。
うっわ、やっぱり実行されたΣ
試しに id コマンドを実行してみると、httpd 権限でスクリプトが動作している事を示す結果が表示されました。ほとんどのファイルは、read 権限だけで書き換える事は出来ませんが、閲覧は出来てしまいます。さらに、ファイラ機能やコマンドを用いてルートディレクトリ(/)にアクセスしてみましたが、もちろん、全てのユーザが rx できるパーミッションなので、ファイルシステムとしてアクセス禁止されていないところは、例え .htaccess だろうが .cgi ファイル*2だろうが、全ての内容を見る事が出来てしまいました。他人の個人ホームページでこのスクリプトを実行すると、
などなど、「URL さえ非公開にしていれば第三者の目にはつかない」と思っているユーザのファイルを危険に晒す事になります。
今回は自分ん家のサーバでしたが、suEXEC (user CGI 権限)をサポートしているレンタルサーバなどで実行したら、第三者がユーザディレクトリ以下のファイルを全部消してしまう事も可能になります。
また個人レベルで維持が可能なレンタルウェブサービスは、有料・無料に関わらず、数十人から数百人単位で一つのホストを共用して使用しているハズです。このようなサービスの利用者の一人が、PHP ファイルをアップロード可能な PHP アップローダを設置*3していると、その利用者だけではなく、同じホスト上の他の利用者のディレクトリまで参照可能となってしまいます。
さくらインターネットのレンタルサーバなどでは、同じホストの利用者間のプライベートはしっかりと確保されており、suEXEC は有効( PHP は user 権限で動作)、全ての一般ユーザは users というグループに所属され、各々のホームディレクトリ以下のパーミッションは g-rwx となっている為、利用者一人の誤ちで他の人の”どこからもリンクされていないファイル”が閲覧されたり、CGI や PHP の書き込みディレクトリにファイルを追加される恐れはありません*4。
ただし、レンタルサーバでもセキュリティ意識が低い*5ところも数多くある為、何気なくホームページを運用している方は、一度、パーミッションを見直してみてはいかがでしょうか。もちろんこの後、自分もパーミッションを見直しました。
プライベートな ML やチャットなどでよく見かけますが、「URL は非公開、どこにもリンクしていないから大丈夫!」といって、安易に、第三者に見られたくないファイルをアップロードするのもいかがなものかと思いました。
*1:もっとちゃんとセキュアな環境にしたいなら、Basic 認証だけでは平文の username/password を渡す事となるので、SSL などを組み合わせなければなりません。お金かかるけど。
*2:正攻法?でアクセスすると、CGI の実行結果しか見る事が出来ませんが、この方法だとソースコードがそのまま読めてしまうワケです。あなたが設置している掲示板の CGI ファイルには、平文でパスワードなどが書いてありませんか?
*3:CGI の場合は、外部からアップロードされたファイルに対して -x しておけば、まず実行される事はありません。これは PHP の CGI モードも同じだと思います。
*4:もちろん、自分でホームディレクトリのパーミッションを変更したらアウトですが…
*5:/etc/shadow~ 644 とか。