NEC LifeTouch NOTE with SKK for Android IS01 ed. その2

NEC LifeTouch NOTE に、SHARP IS01 のハードウェアキーボード向けにカスタマイズされた SKK for Android をインストールし使ってみた感想を書きましたが、作者の ray_m さんにコメントを頂き、修正を施したとの事だったので、早速使ってみました。

修正がほどこされた点をかいつまんで紹介します。

  • Shift キー押下しっぱなしでの連続入力に対応。修正前のバージョンでは、「入れる」と入力する際、タイプでは「IReru」となりますが、I と R を Shift キーを押しっぱなしにして連続で入力する事が出来ませんでした。( Shift+i、Shift+r の間で、Shift キーを”離す”必要があった。) ray_m さんによると、IS01 のタイプ方法をベースに作成されていた為という事でそれを受けてすぐに修正して頂きました。LifeTouch NOTE は持ってらっしゃらないようなのに、迅速に修正して頂けるなんて頭が下がるばかりです。

IS01 の特殊キーは、同時押しではなく、キーを押した次のキーに作用するように出来ています。 これは QWERTY ハードウェアキーボードを搭載していても、サイズ自体が小さい為、同時押しがしづらい物理的な問題に対処するものだと考えられます。例えば、IS01 で大文字の ‘A’ を入力する場合、Shift キーを押した上で、( 押しっぱなしにしても、離してしまっても、Shift 押下状態が続くので、その直後に ) a キーを押す事によって入力する事が出来ます。自分の IS01 は電話専用機になってしまっているので、SKK を導入する必要はないですが、LifeTouch NOTE や Dynabook AZ のようなネットブックに匹敵するサイズの QWERTY キーボードを搭載している Android 端末上では、SKKer にとって、キラーアプリになるくらい外せないアプリになっています。

  • z キーでの記号入力に対応。カタカナ入力モードのトグルキーである q キーや、半角英数モードにする l キーは以前から利用出来ていましたが、日本語でよく利用する記号を 2 タイプで呼び出す z キー機能がありませんでした。これ自体はクリティカルに SKK の使い勝手を落とすわけではないのですが、新しいバージョンではサポートされるようになりました。これで、『』~・…‥←↓↑→ といった記号を 2 タイプで入力する事が出来ます。
  • 一時的に半角英数を入力する際、▽の表示に対応。ちょっと細かな話ですが、/ キーを押して一時的に半角英数文字をタイプする際に、最初の 1 文字を入力するまで、SKK による入力中である事を示す▽が出てきませんでした。最新版では、これもちゃんと出ている模様で、/ キーを押した状態で「えーと、スペルどうだっけ」と一瞬ディスプレイから目を離した時に、再度、/ キーを押してしまって「▽/」という入力状態にならなくなりました。
  • 通常の Android 端末にはまず付いていないであろう Delete キーは、LifeTouch NOTE 専用のテキストエディタである「ライフノート」では、IM がオンの状態でも使う事が出来ます。コピー C-c、ペースト C-v、カット C-x、アンドゥ C-z、全選択 C-a などのライフノート・ショートカットキーを使うにはは、IM をオフにする必要があります。

前回の記事は、SKK for Android をインストールしたその夜に使い勝手を調べながら書いたものですが、それから 1 ヶ月以上使ってみて、ますます満足しています。残すは変換候補の表示位置のみといったところでしょうか。

LifeTouch NOTE は、せっかく左にある Menu キー( IBM-PC キーボードで言う CapsLock の位置 )を Ctrl キーに変更する設定項目まで搭載してくれているのに、Android 自体の仕様が全体的に Ctrl キーをサポートしていないのが残念な限りです。自分に課題を出すとすれば、確定 C-j やキャンセル C-g を多用している SKKer としても、”C” になるキーを指定させてそれらをサポートしたいところです。

2011/09/23 追記

ray_m さんから新しいバージョン 1.4 のご連絡があり,早速試してみると,変換候補の表示位置がずれてしまう現象が解消されたようです.

また,上の記事には書いていませんでしたが x キーによる小文字(っ,ぁ,ぃ,ぅ …など)にも今回のバージョンから対応しているようで,使用感はほとんど Emacs や SKKIME と変わらなくなっています.

さらに SKK 使いでフルキーボードを搭載している Android 端末ユーザには,離せないアプリになっていると思います.

※ 2020/07/02 度重なるブログ移転・ブログシステムのアップデートにより崩れた記事を校正。

bsplinecurve コマンド引数( knot 値)を相互変換

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() は、もう少しスマートに出来るかも。

2020/07/02 追記

度重なるブログ移転・ブログシステムのアップデートにより崩れた記事を校正。ついでに 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 で IRC クライアント的な

基本

無駄がなくて綺麗なコード。やっぱり 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 スクリプトを配布しているサイトのものをそのまま設置したものや、自作コードによるものでしたが、どうみても危険です。本当にありがとうございました。

ここからはもちろん、自宅のサーバ上で試したものです。

  1. PHP ファイルのアップロードを許可している PHP アップローダを設置してみる。
  2. ブラウザより、先ほど拾ってきた PHP ターミナルスクリプトをアップロードする。
  3. サーバ上にアップロードされたターミナルスクリプトの URL を開いてみる。

うっわ、やっぱり実行されたΣ

試しに 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 とか。

新しいデバイスが欲しい

新しいデバイスが欲しくなってきた。要件は次のとおり。

前提

  • 本体が省スペースであり、軽いこと。 ・・・ ただしタイピング効率が落ちたり、特殊なキーボードは避けたいところ。
  • 任意の Linux が動作すること。 ・・・ Android などが最初から入っていても、専用機 ( 組み込み ) のような環境は NG。
  • 無線 LAN (WiFi) デバイスが搭載されていること。 ・・・ 最近のモバイル PC では、むしろ付いていない方が珍しいか。
  • 長時間、稼動すること。 ・・・ 公称 10 時間ほど欲しい。
  • お手頃価格であること。 ・・・ 出来れば 5 万円以下、3 万円以下ならなお嬉しい。

普段、使っているネットブックは以下のもの。

NEC LaVie Light BL300/TA6R (PC-BL300TA6R) スペック

2009 年に購入。Atom 1.6GHz / 1GB RAM と、Windows XP 搭載ネットブックの頭打ち性能。Ubuntu 11.04 を入れて使用中。

ディスプレイは 10 インチなので、次に欲しいものはもうちょっと小さい( 5 ~ 8 インチ程度 )のものがいい。

候補

以下、候補。

NEC LifeTouch NOTE NA75W/1AR (LT-NA75W1AR) スペック

公称稼動時間 9 時間、実機を触ったがキーピッチもいい具合。 公式の Android マーケットにも対応しているので、Connect Bot などで自宅サーバを弄ったり、IRC や Twitter でつぶやきながらネット巡回したりする分には困らない。ただ、一般的な Linux ディストリを導入するには、Dynabook AZ 同様、いくつかの作業が必要みたい。自宅では NFS サーバのデータを扱う事が多いから、一般的なディストリを入れるのに苦労はしたくないなあ、というのが正直な気持ち。また日本語入力は ATOK ではなく SKK 環境が慣れている点でも、一般的なディストリにしておきたい理由の一つ。

【Android】NEC LifeTouch NOTE Part 5【Tegra】 – 2ちゃんねるキャッシュ

Fujitsu FMV-BIBLO LOOX U/G90 (FMVLUG90R) スペック

ちょっとばかり値が張るが LifeTouch NOTE よりもひと回り小さく、かつタイピング効率が落ちないであろうベストなサイズ。公称バッテリー持続時間が 4 時間という点が致命傷だが、Windows 7 も動作する贅沢なハードウェア構成 (Atom な AT 互換機) なので、任意のディストリを入れる事も簡単そう。OS は要らないから、8000 円ほど安くならないかなあ。

SHARP NetWalker PC-Z1-R スペック

発売前から、かれこれ 2 年くらい気になり続けていたハード。同社のスマートフォン IS01 よりもひと回り大きく、ジャンルとしては PDA に分類されてそう。最初から Ubuntu が入っているのは楽ちん。公称バッテリー持続時間も 10 時間と良好。しかし QWERTY キーボード付き Android の IS01 も持っている自分としては、サイズ面 ( つまり、タイピング効率 ) でちょっと中途半端なものになり兼ねない。もうちょっと大きかったら、価格も納得していたところなので残念。

まとめ

ディスプレイサイズを 10 インチにまで制限を緩めてみると、長時間稼動かつ低価格な Acer などのメーカーのネットブックもあるが、今と同じサイズのものを購入するのも何だかなぁ。結局、LifeTouch NOTE か NetWalker のどちらかになりそうな予感だけれども、今から購入する事を考えれば、スペック的にもやはり LifeTouch NOTE か。しかし、前者は Android というのも気が退けるところではある。

IS01 を不用意に 01.00.13 にアップデートしてしまって、root が使えなくなり、テザリングも出来なくなった直後だから、尚の事。

本当は Android でも SHARP でもなく、どうしようもない日本の電話会社の傲慢と、それを忘れてアプデなんかした自分の責任って事は分かっているけれども。

※ 2020/07/02 度重なるブログ移転・ブログシステムのアップデートにより崩れた記事を校正。