2009年10月29日

このBlogのStyleSheet「ブラウザ、Telnet、Cygwin用」を追加

<pre>タグのスタイルシートで以下の見栄を追加した。今後、それぞれ、ブラウザ表示、Telnet、cygwin操作の説明で利用する予定だ。説明書きでは適宜グラフィカルな表示を加えることで判り易く出来るが、逐次画面コピーを取っていたのでは大変だし、来訪者にとってもイメージ内に見える文字はコピペ出来ない。また、イメージはサーバ上のHDD容量を圧迫するので出来れば共通の見栄えを使い回して節約した方が良い。良かったら、参考にして下さい。
 尚、このスタイルシートは<pre>タグで使っても、外枠幅の制限があれば、行の折返しで、頁レイアウトを壊すことを最小限に減らせます。

    このBlogの追加スタイルシート


<style type="text/css">

<中略>

pre.cmd {margin-right: 50px; width:100%; font-size:10px; line-height:12px; background-color:#F0F0F0; border-style:ridge; background-image: url(http://pythonlife.up.seesaa.net/image/commandprompt_small.png); background-repeat: no-repeat; background-position: left top; padding-top:14px; white-space: pre-wrap; white-space: -moz-pre-wrap; white-space: -pre-wrap; white-space: -o-pre-wrap; word-wrap: break-word; }
pre.mem2 {margin-right: 50px; width:100%; font-size:11px; line-height:12px; background-color:#F0F0F0; border-style:ridge; background-image: url(http://pythonlife.up.seesaa.net/image/mem_s2.png); background-repeat: no-repeat; background-position: left top; padding-top:1px; white-space: pre-wrap; white-space: -moz-pre-wrap; white-space: -pre-wrap; white-space: -o-pre-wrap; word-wrap: break-word; }

<!-- 2009-10-28追加分 -->
.brws {margin-right: 50px; width:100%; font-size:11px; line-height:11px; background-color:#F0F0F0; border-style:ridge; background-image: url(http://pythonlife.up.seesaa.net/image/Brws_bg_s.png); background-repeat: no-repeat; background-position: left top; padding-left:8px; padding-top:3px; white-space: pre-wrap; white-space: -moz-pre-wrap; white-space: -pre-wrap; white-space: -o-pre-wrap; word-wrap: break-word; font-family:serif;}
.cygwin {margin-right: 50px; width:100%; font-size:11px; line-height:11px; background-color:#F0F0F0; border-style:ridge; background-image: url(http://pythonlife.up.seesaa.net/image/Cygwin_bg_s.png); background-repeat: no-repeat; background-position: left top; padding-left:1px; padding-top:3px; white-space: pre-wrap; white-space: -moz-pre-wrap; white-space: -pre-wrap; white-space: -o-pre-wrap; word-wrap: break-word; font-family:serif;}
.telnet {margin-right: 50px; width:100%; font-size:11px; line-height:11px; background-color:#F0F0F0; border-style:ridge; background-image: url(http://pythonlife.up.seesaa.net/image/Telnet_bg_s.png); background-repeat: no-repeat; background-position: left top; padding-left:1px; padding-top:3px; white-space: pre-wrap; white-space: -moz-pre-wrap; white-space: -pre-wrap; white-space: -o-pre-wrap; word-wrap: break-word; font-family:serif;}

<中略>

</style>


    403 Forbidden - Mozilla Firefox


http://127.0.0.1/cgi-bin2/html4blog2.cgi

Forbidden


You don't have permission to access /cgi-bin2/html4blog2.cgi
on this server.


     127.0.0.1


$ ls

     127.0.0.1

$ ls
タグ:Webデザイン
posted by Mire at 01:45 | Comment(0) | TrackBack(0) | Webデザイン | このブログの読者になる | 更新情報をチェックする

2009年10月28日

【ApacheのCGI設定】あれ? 〜.cgiが使えないぞ

 ちょい使いには、Pythonの3行サーバでも充分だが、常時汎用で利用するなら、Apacheでしょう。
 ということで、Apache2.2で、CGI実行をさせるべく設定と思いhttpd.confを変更し再起動したが、上手く行かない。はい、はまりました。

はまりポイント1: VistaでのProgram Files内のファイル編集は「管理者として実行」せよ

 前もはまったものに、またはまりました。Vistaでは、普通に起動したエディタで編集して保存してもRoaming内にその編集が書かれるだけで、ファイル本体にその編集が反映されることはない。システム設計としてセキュリティ書込み拒否なら判るが受け入れた振りで済ませる辺りが何とも思想が理解出来ないが、MS仕様なので文句言っても仕方ないのだろう。
 皆様もお気をつけあれ。

はまりポイント2: 「#AddHandler cgi-script .cgi」のコメントアウトでは駄目だってよ

 これって、「<IfModule mime_module>」内の設定だからなのかな? Apache1.3系辺りではこれで良かった様な気がするのだが、どうも、個別Directoryに設定する必要が有る様だ。これは、Options の ExecCGIも同様に必要な様で結局以下の設定をすることで、ようやく〜.cgiの実行が可能になった。


  httpd.conf


<Directory "C:/Program Files/Apache Software Foundation/Apache2.2/cgi-bin">
AllowOverride None
#Options None
Options ExecCGI
AddHandler cgi-script .cgi
Order allow,deny
Allow from all
</Directory>

<Directory "D:/cgi-bin">
AllowOverride None
#Options None
Options ExecCGI
AddHandler cgi-script .cgi
Order allow,deny
Allow from all
</Directory>


 こちらの明示的に個別設定しないと動的コンテンツの実行が出来ないというのは、セキュリティ思想的に理解出来るので素直に受け入れることにする。続きを読む
タグ:httpd.conf CGI
posted by Mire at 05:47 | Comment(0) | TrackBack(0) | セキュリティ | このブログの読者になる | 更新情報をチェックする

2009年10月27日

【PC遠隔操作】RealVNCのLAN内利用

 永年愛用していたIiyamaのCRTディスプレィが逝ってしまった。垂直方向の偏向が時々乱れるなか、だましだまし使っていたが、全く反応しなくなったので、あきらめはつく。だか、手元不如意に付、今はディスプレィ購入は厳しい。まあ、1.5万円も出せば、安物の1440クラスのディスプレィは手に入るが、買うならやはり1920×1200以上でしょう。

 そう言うことで取敢えずのVNC利用で当座を凌ぐことにする。VNCのセキュリティはIP制約とパスワード程度で、VNCサーバ側PCの全制御を許すことになる為、この様な目的での業務利用は絶対に奨めないが、そこは、ご愛敬として、ご覧頂きたい(汗)。

 従って、VNCサーバ側設定は絞れるなら出来る限り絞った方がよい。ここでの掲載内容は最低限の設定として考えて下さい。

RealVNCのインストール

 VNCには色々と派生があるが、RealVNCには、日本語化されたものがあるのでそれをDLしインストールさせて頂いた。
RealVNC Free Edition Ver.4.1.2 日本語版(2006.05.29)
 本家を覗くと2009-10-27現時点での最新版は4.1.3だが、サーバ側に変更はないので、セキュリティ的には変わらないと判断。将来も引き続き使う場合には英語版の利用も検討することになる。

サーバ起動

 リモート側のPCでVNCサーバを起動しないと、手元PCのVNC Viewerでのリモート側PC操作は出来ない。標準的な起動方法としては手動とサービス起動の2つだ。セキュリティ的には出来れば手動が望ましいが、今回はディスプレィ無しのPCの操作なのでサービス起動とした。
 これで、WindowsがUpdateで勝手に再起動してもVNCサーバが起動しているので、ログインからの操作が可能になる。(DELL等サーバではHARD対応でシステムは電源OFFからでも制御可能だが自宅では、それは不要だ。)

サーバ設定1: 接続IP制限

接続を許可するIP範囲を個別に設定。当方では、無線LAN側のプライベートアドレス空間が別なので2つとも登録 右図の様に「ローカルマシンからのアクセスのみ受け入れる」のチェックを外し、追加ボタンで、IPアドレスの範囲を設定する。設定方法は、例えば、192.168.0.xのCクラス全部を指定する場合は192.168.0.0/255.255.255.0とネットマスクをCクラスにして指定、
192.168.1.20のみなら192.168.1.20/255.255.255.255かな。ここで、外部のグローバルIPを指定し、ルータとファイヤーウォールに穴を通すと、お外からの接続が可能になってしまうので注意して欲しい。
 尚、接続テスト成功後には、右図上部にある接続ポートも既定の5900,5800ではないものに入れ替えた方がより安全かと思う。

サーバ設定2: VNCパスワード認証

VNCパスワード認証を選択し、環境設定ボタンで、パスワードを2度打ち設定 まあ、別にセキュリティ確保が可能なら良いが、手動認証ではパスワードの設定くらいしかないので、ここでもそれで行く。VNCパスワード認証を選択し、環境設定ボタンで、パスワードを2度打ちし設定した。また、一般にはお勧めしないが、その下の「ローカルユーザが接続を受け入れか問い合わせる」と「ユーザログオン中のみ問い合わせる」のチェックを外すことで、リモート側に誰もいなくても接続可能で、且つ、ログオフ状態でもVNC接続を可能にした。

 以上の設定で、VNC Viewerから、リモートPCのIPを指定し、所定のパスワードを入れることで、リモートPCの画面が表示出来る様になる筈だ。リモートPC側でVNCサーバをサービス起動し、「ローカルユーザ問合せ」と「ユーザログイン中のみ問合せる」のチェックを外していると、電源ONさえしていれば遠隔操作が出来る。ログイン画面から操作も出来ないとすれば、双方のPCのポート番号に対するPCファイヤーウォール設定をチェックすれば多分解決出来るが、切り分けとして、自身のPCのVNCに接続(localhostを指定)して試るのも一つの方法だろう。リモートPCでもipconfigやifconfig、手元PCからはping等でIPアドレスの誤りがないことも要チェックだ。ルータによるDHCPでの運用の場合、リース期間は結構短めなので、一度接続を切ると同じIPで有り続ける保証はないのだ。ISC-DHCPDを立ち上げて、MAC固定割り当てで集中管理すると良いがLinuxPCがない今は仕方がない。

 PCのソフトファイアウォールには、ウィルス対策ソフトに付いてくるもの、Windowsファイアウォール等があるので、もし、それが原因と疑われる場合には、ログの確認または、一時的に解除して影響をチェックすれば大丈夫だろう。

 尚、当方の環境では以上の設定で接続出来たので障害対応は完了したが、フリーのVNCじゃ嫌な方は有償のPC Anywhereを以下から買って下さい。そうして頂ければ私は助かります。^^;;
タグ:VNC
posted by Mire at 15:34 | Comment(0) | TrackBack(0) | システム管理 | このブログの読者になる | 更新情報をチェックする

2009年10月22日

【無線LAN感度】後書き 〜 放物線の描き方と楕円

平行波前提での到達距離が等しくなる反射面を作図 前稿では、無線LAN子機様に最適な反射板を作成しようとの思いから、平行波で波長ずれが起きない反射面を求める為に、到達距離が一致する反射面を円弧と線分の交点を結ぶ方法でCAD上で作図し、それが2次曲線(放物線)となることが判って嬉しがっていた訳だが、この作図法を判り易くしてくれた頁が見つかったので紹介して置く。
 平行波なので、波長をずらさない為に距離を一定にする為に紐を、波の進行方向を正確に決める為に三角定規を使う方法だ。

2次曲線の作図方法(山崎直和さん)
 この中に判り易いjava動画のリンクも付いているのでご覧頂きたい。Good Job!!

近接発信源と平行波との反射面の差 この作図方法は、実のところ楕円の作図方法の一方の頂点が無限の場合(だから平行で等距離)に過ぎない。楕円が画鋲2つに紐で作図出来ることは大抵の人はご存知と思うが、無線LANの様な比較的短距離の電波の反射板の場合には、頂点間の距離が無限とするより、本当のところ十数m〜数十mとして作図した方が正確と言えば正確ではないかと思う。無論、頂点間距離を10mとして波長が数cmの楕円の一方の頂点側の面で作図しもそれを元に反射板を作成しても、放物線のものと差が出るかどうかは加工精度上疑問ではある。

 また、前稿でもリンクした「放物線」では、放物線の面の反射角が平行光線を頂点に集めることの数学的な証明をしているが、楕円も同様に各頂点間でも、双方の光の放射が他方に集まることは、後述の最短距離到達の考え方が成り立つ。
 同時に、当方のアプローチで言わせてもらうと、光、電波には波長があるので、到達距離が異なる伝達をしようとしたものは波長がズレて打ち消しあってしまい頂点にあっては反射面全体がら一応に同一波長にそろったもののみが強め合うので結論として、楕円も放物線の反射角と同様に頂点に正しい反射角のつながりとなる。

 従って居ないと思うけど(笑)、1m程度の距離での通信不良で反射板を作るときには楕円で作って試してください。その場合楕円は長手幅は1m+周波数の波長の1/2となります。続きを読む
タグ:無線LAN fon
posted by Mire at 00:27 | Comment(0) | TrackBack(0) | 無線LAN | このブログの読者になる | 更新情報をチェックする

2009年10月19日

【無線LAN感度】Fonの電波強度大幅UPに成功(答えは干渉低減と放物線)

 以前、「La Fontenna買ってドキッ!! ひょっとして違法?」で、触れていたが、La Fonera + に 外付けアンテナを付けたにも関わらず、木造戸建て2階設置での1階使用では、満足の得られる感度にすることが出来なかった。
 そこで、今度は自宅近くのPCショップで何気に立ち寄って眺めているとUSB接続タイプの無線子機が目にとまった。通常、USB接続タイプの無線子機もPCに直接差して使うのだろうが、これ、USB延長ケーブルを使えばPCの置き場所に関係なく、電波感度の高い所にアンテナを設置することが可能であることに気付いてしまった。で、物色すると金欠の自分にも買える程度で、且つ、しっかりアンテナだぞと張り子の虎かもしれないアンテナ付の無線LAN子機「BUFFALO Air Station NFINITI HighPower 11n/g/b USB用 無線子機 WLI-UC-GNHP」が目にとまった。

 すると、んっ〜、これを電波感度の良い場所に置いて反射版何ぞを置いたら効果があるかも! との想いが膨らみ、結局2980円で衝動買い。はい、226円の損でした。そのご反射板用の材料探しに100円SHOPに行き、台所の油汚れ除け用のアルミ箔板、アルミテープ、金属ザル何ぞを買い集めテストをすることになった。

 さて、この無線子機、先ずはCDを入れてから、その画面指示に従い、USBに刺したり抜いたりといった良くあるインストールパターンで導入し最後にリブートで出来る。早速、繋ごうとして、がっくり、我がノートPC内蔵分より感度が悪い安定しない。やっぱアンテナは張り子の虎かよと言うより多分ノートPC側の設計頑張っているのだろう。そう思うことにして、気を取り直して、反射板を色々と試してみた。

 抜群に効果があったのは金属ザル300円払った価値はある様だったが、持ち歩く訳にもいかないので、アルミ箔版を単純に立ててみると僅かに反応するので、凹面化して試みるが、感度は安定しない。まだ、ノートPC内蔵分の方がましである。そこで、ザルを2階に持って上がりfonの外付けアンテナにかぶせて見たが、取り立てて効果がある様でもなかった。で、駄目元で、fonera+本体も当方の1階PC位置に一番近い位置に移動して、ザルをかぶせて試た。するとあれ不思議、一気に電波感度がアップすると共に安定したのだ。
無線LAN感度安定 (inSSIDerで測定)
 あくまで憶測の域は出ないが、fonera+ は素のままでも、内蔵の埋め込みアンテナと、お尻にの短いアンテナが両方生きており、共に電波の送受信を行なっている。今回の場合、お針のアンテナは外部アンテナに置きかわさているが、fonera+本体内のアンテナは生きていた訳で、恐らく無造作に置いていた関係で、電波干渉で感度が不安定に減衰していたのであろう。それが並行に置かれれば、その正面と背面は平行波に近いものとなりうまくいったものと思う。

 また、同時に、無線子機側の反射板の曲げ具合もちょうど良かったようだ。理想の曲率を理論上で求めよう思い、久しぶりにCADを起動して、30,45,60,90度と判り易い物を先ずはプロット、それを眺めると規則性が見えて来たので、焦点を中心とする円弧を等間隔に描きそれに接する水平線を引いて、平行波の到達距離が等しくなるものを発見した。同時に、このプロットした点を滑らかに結ぶとそれは、その最短距離の入射角と一致する様でびっくりだった。また、この曲線、式で表すと、2y=x2-1と一致するのだ。これが解ってもっとびっくり、そう、いわゆる放物線だ。元々、想定していた相似形が放物線だったので、それと一致しているのではないかとは思っていたが、その通りで良かったと思うのと同時に、放物線の相似形がコンパスと直線定規で書けることを発見し、とても満足だった。

 因みに、この辺をグクってみると「放物線」として説明している頁か見つかったので興味がある方はご覧下さい。自分にはとてもここ迄の説明は出来ないので、代わりに反射板の絵とその同尺のPDFを付けて置くので、必要なら活用して欲しい。
反射板 for WirelesLan2.4GHz

 尚、現在の電場強度はさらに改善し-53dB〜-55dBとなっており、活用に問題はない。そして、その曲率は少しずつ修正して形作った訳だが、この放物線図と殆ど一致していたので、当方にとってはわざわざ、作図したことでの修正はなく改善はなかった。以下が最終結果だ。無線LAN安定化 最終結果
 これで取敢えず、自宅での無線LAN利用では問題はなくなった。また、今後、ノートPCを持出す際には、この放物線図とアルミ箔板、そしてUSB延長ケーブル、そして無線LAN子機「BUFFALO Air Station NFINITI HighPower 11n/g/b USB用 無線子機 WLI-UC-GNHPを一緒に持っていくことになる。流石に反射板を人前にさらすのは勇気がいるが、変に電波干渉のなければ無銭LANが楽しめる筈である。目出度し目出度し。
続きを読む
タグ:無線LAN fon
posted by Mire at 15:04 | Comment(0) | TrackBack(0) | 無線LAN | このブログの読者になる | 更新情報をチェックする

2009年10月18日

【PythonでCGI】CGIでの例外Error処理 〜 Web版BlogでHTMLタグ表示

 本日のお題は、CGIプログラムでのError処理である。前稿と同じソースの再掲載での説明では芸がないので、フローは前稿のそのままで、処理だけをHTMLタグの入ったソースコードをブログら掲載する時に必要な「< ⇒ &lt;」等を行なうもので行なわせて頂く。この機能自体は以前、コンソールプログラムとして紹介しているもので珍しくもないので先ずは簡単にその変換部分だけを説明させて頂く。前稿との差は、
  前稿の「SPAM投稿切刻み」処理部分


ss=p=''
for s in html_text: #unicodeはMultiBite文字も文字単位処理
if s=='\n' or s=='\r' or p=='\n' or p=='\r' or ss=='': #改行符号と頭の文字の
ss=ss+s #前後には空白文字を加えず
else: #そうでないなら
ss=ss+' '+s #空白文字を加える
p=s #直前の文字を代入
html_text=ss #html_textを置換え
が、
  今回の「HTMLタグ表示」処理部分


ss = html_text.replace(u'&',u'&amp;').replace(u'<',u'&lt;')\
.replace(u'>',u'&gt;').replace(u'&',u'&amp;') #最後の&の変換がミソ!!
html_text = ss
に変わった程度の差に過ぎない。また、以前の同機能のコンソールプログラムとの差は「.replace(u'&',u'&amp;')」が、HTML内に記述し表示させる為に追加になっていることにご注意頂きたい。蛇足ながら、Stringオブジェクトのメソッドとして定義されている「'<処理文字列>'.replace('<検索文字>','<置換文字>')」を使うと、元文書に対し、特定のキーワードを強調や色付表示させたい時に重宝する。そんなツールはテキスト欄へのキーワード入力を求め、
「'<本文>'.replace('.replace(u'&',u'&amp;')','<b>.replace(u'&',u'&amp;')&;lt;/b>')」の様に処理すれば、「.replace(u'&',u'&amp;')」が全て太字表示に置換出来る。普通なら正規表現で考えることが簡単に達成出来る訳だ。

 さて、これより本論のCGIでのError処理の説明に移る。Web版の「BlogでHTMLタグ表示」のソースコードは次の通り。
  /Web/cgi-bin/html4blog.py


#!c:/Python26/python
# -*- coding: UTF8 -*-
# ※ Windows の場合1行目はdummyです

u"""
#####################################################################
# HTML CODE_TEXT for BLOG 0.0.0 (C) Mire 2009-10-15 #
#####################################################################
 blogを持っていると
怒り^^;;を込めて、SPAM迷惑投稿を切り刻みます。コピペで上書きすれば、
内容はそのままでも目的のURL linkは全てはずれレンダリングも消えます。
USEGE:
1.SPAM迷惑投稿をテキスト欄に貼付けボタンをクリックして下さい。
2.別窓または別タブで1文字毎の半角スペース区切りテキストが表示。
3.このスペース区切テキストのCopy&PaseteでSPAM迷惑投稿を置換え
"""

__author__ = "Mire in Japan"
__version__ = '0.0.0'
__copyright__ = 'Copyright (c) 2009 Mire'
__license__ = 'GPL'
__url__ = 'http://pythonlife.seesaa.net/'

debug = 0 #debugレベル


########################################
## 当Tool専用関数の定義contents()のみ ##
########################################

def contents(debug=1):
u"""
コンテンツ「入出力フォーム」を表示します
"""
try:
from mire.htm import display_err, cgi_params #, tag_encode

print u'<table width="590px" style="background-color:#F0F0F0;"><tr>'
print u'<td><font size="-1"><b>HTMLのタグをそのまま表示するものに変換します。</b>\
</font></td></tr><tr><td align="center">',
prms=cgi_params() #> mire.htm.cgi_params(): CGI引数情報の辞書を返します


if debug > 1: #debugレベル2: CGI引数の名前と値を表示します。
print '<table><tr><td align="right"><pre align="left" style="text-align:center;\
pre-wrap; white-space: -moz-pre-wrap; white-space: -pre-wrap;\
white-space: -o-pre-wrap; word-wrap: break-word; ">'
for p in prms:
print '%s: %s' % (p,prms[p])
print '</pre></td></tr></table>'

if 'html_text' in prms: #cgi引数が存在したら、
html_text=unicode(prms['html_text']) # CGIの引数の値はunicode化しないと駄目の様だ
ss = html_text.replace(u'&',u'&amp;').replace(u'<',u'&lt;')\
.replace(u'>',u'&gt;').replace(u'&',u'&amp;') #最後の&の変換がミソ!!
html_text=ss #html_textを置換え

else: #引数がないなら
html_text='' #0長文字列

#コンテンツ本体: table,form textarea,inputタグで入出力画面を表示
print u'<table><form method="post" target="_blank"><tr>'
print u'<td><textarea cols="88" rows="20" style="font-size:8pt;" name="html_text"',
print u'mire_val="html4blog_text(html_text)">%s</textarea></td>' % (html_text)
print u'</tr><tr><td><pre>%s<pre></td>' % (html_text.replace(u'&amp;',u'&'))
print u'</tr><tr><td><center>',
print u'<input type="submit" style="font-size:8pt; width:567px">',
print u'</td></tr></form></table></center></td></tr></table>'


except: #vividな作成部分はhtm.display_err()
if debug > 0: #でdebug情報を取得。運用時はdebug=0
print '' #とし障害内容は表示させない。
display_err(locals()) #>mire.htm.display_err()#Web用の例外処理で障害切分
print '</span>'
else: #運用中のdebug message表示はセキュリティ上不適格。通常はdebug=0で以下のmessage
print '<pre>Error was occured.\nPlease, contact your system administrators.\n'
print 'You? Do Your Best!\n Test html4spam.py with debug=2. Good luck.</pre>'


########################################
## ##
## 処理実行開始位置 ##
## ##
########################################
try:
from mire.htm import display_err, html_header, html_footer
html_header(charset='UTF-8', title=u'HTML CODE_TEXT for BLOG 0.0.0 (C) 2009 Mire GPL license'
, body=['style="right-margin:0px; background-color:#808080;"'])
contents(debug=debug)
html_footer()

except:
if debug > 0:
display_err(locals()) #こちらは最後の抑え
else: #運用中のdebug message表示はセキュリティ上不適格。通常はdebug=0で以下のmessage
print 'Content-type: text/html\n\n<html>\n<head></head><body>'
print '<pre>Error was occured.\nPlease, contact your system administrators.\n'
print 'You? Do Your Best!\n Test html4spam.py with debug=2.\n\nGood luck.</pre>'
print '</pre></body></html>'


 昔々、例外Error処理がなかった当時は、全ての条件を頭に置いてif分での条件分岐を行ないエラー処理を書いていたものだ。当初、この「try:〜;except:〜;」は、いい加減な詰めの甘い仕組みに見えてしまい、使う気にならなかったものだ。でも、それはシステム言語や使用する開発ツールが完璧であり且つ、関わるシステム作成者全員間で完全無欠なコミュニケーションが取れる場合に言えることで、現実の開発環境ではありえないことだ。
 従って、例外Error処理を使うときの発想は、逆に想定外のエラーは起きて当り前、起きた場合の無難な処理を予め書いて置き、「1.システム作成中は効率的なDEBUG」を、「2.実用運転時には、次善の策として、利用者側に障害アクションをとってもらうメッセージや、システム管理者への通知、そして応急処理を組んで置くことに使うもの、そう言う逆転の発想で使うものと考える。

 従って、この説明用のサンプルソースコードの様に最低でも、先ずは、実行処理全体について、そして、作成中のvividな部分には必ず、「try:〜;except:〜;」で例外処理を入れて置く必要がある。そして、同時に、特にWebシステムの場合利用者は不特定多数となることを前提にセキュリティ上の配慮も加味し、debugレベルにより、表示する内容を抑制しする対処をすることになる。

 このサンプルでは、運用での障害発生時には、いずれも次の様なものが表示される様になっている。
Error was occured.
Please, contact your system administrators.

You? Do Your Best!
Test html4spam.py with debug=2. Good luck.
文字コード処理の不具合も考慮して敢えて英語のみのメッセージにしている。

 開発修正時のDEBUG時には、mire.htm.display_err()の定義に従い例外Errorの内容とローカル変数とその値が表示される。前稿と重複するが定義は次の通りである。
  mire.htm.py 内の display_err()関数


## エラー表示関数(コメント行文字化け対策+thread実行時のエラー情報表示の時系列混乱軽減) ##
def display_err(self,local, title = '\n\n#### EXCEPTION ERROR ####'):
"""
##########################################################################################
#エラー表示関数(コメント行文字化け対策 + thread実行時のエラー情報表示の時系列混乱軽減) #
#USAGE: 第一引数に「locals()」を指定することで、処理時の変数値を表示します。 #
# waitingはthread実行時のエラー情報表示の時系列混乱軽減の為のWAIT処理です。 #
# waiting = 0 #
# def foo(): #
# global waiting #
# sleep(waiting) #
# try: #
# 処理 #
# waiting = 0 #
# except: #
# display_err(locals(),'<例外処理の場所を表すタイトル>')# locals()指定は必須 #
# waiting = 1 #
# foo() #
##########################################################################################
"""
import traceback
from time import sleep
print('Content-type: text/html\n\n<html>\n<head>')
print('<body><pre>')
if local is None:
local =locals()
global waiting
frame0 = '\n*******************************************************************************'
frame1 = '*******************************************************************************\n\n'
errs = [frame0, title]
errs.append('%s' % (self.dsp_hex(traceback.format_exc()))) #> dsp_hex(s): コメント文字化け対策
sleep(waiting)
ls = local
keys = list(ls.keys())
errs.append('')
for key in keys: # display_err()関係の変数の表示を省く
# if not key in ['v', 'ls', 'keys', 'key', 'errs', 'txt', 'er', 'sleep']:
er = '* %s: %s' % (repr(key).ljust(24),repr(ls[key]))
errs.append(er)
errs.append(frame1)
txt = '\n'.join(errs)
print(txt)
print('</pre></body></html>')

## コメント文字化け対策 ##
def dsp_hex(self,s):
from re import search
charsets=['UTF-8','Shift_JIS','EUC-JP','iso-2022-jp'] # どれでもいいので、charsetで、
for charset in charsets: # unicode化し、コメント部分の
try: # 文字化けを防ぐ
return str(s,charset)
except:
print('%sでは変換不能でした' % (charset))
pass
sss=''
for ss in s: # 想定外のcharsetのときは16進数表記に
if (ord(ss)>=32 and ord(ss)<=126) or ss.isspace(): # Windowsにはcurses.ascii.isprint()が
sss=sss+ss # ないのでcurses/ascii.pyの中身を展開
else:
sss=sss+'\\'+hex(ord(ss))[2:].upper()
return sss
で実際にどの様なエラーメッセージが出るかというと以下の様になる。

ちょいと、長くなって息切れしたので、後ほど追記。(ソースコードも一部差替えます。)続きを読む
タグ:CGI Python
posted by Mire at 01:51 | Comment(0) | TrackBack(0) | Pythonプログラミング | このブログの読者になる | 更新情報をチェックする

2009年10月15日

【PythonでCGI】FORMタグでGUI TOOL 〜 SPAM迷惑投稿を切刻む

 このブログでは過去、cgiを書く上で必須となるヘッダ/フッター部分の関数とCGI引数の取得とGET型のURL引数表記を助ける関数を紹介した。この稿では、より一般的にCGIっぽいformタグを使ったツールを紹介する。
 説明を簡単にする為、formには一つのtextareaタグにsubmitボタンを配置し、入力データの送受信共に同じcgiプログラムでの関数で受ける程度のもので、データ加工も簡単なものにさせてもらった。

 今日、紹介するものは、textareaのテキストを1文字毎半角空白文字を挿入したものを生成する他愛のないものだ。用途は、タイトルの通り「SPAM迷惑投稿」の被害状況は消すことなく、SPAM迷惑投稿者の目的である下手な鉄砲も数打ちゃ当たる式でのURLやキーワード検索向上を阻止するとこにある。このブログでいうと、国内からはH系、海外からは薬物系の「SPAM迷惑投稿」があるが、以前はハンドでこの作業を行なって来たが今後は、このツールで対応出来る訳だ。

 先ずはスクリーンショットからご覧頂こう。わざわざtSPAM迷惑投稿を宣伝したくないので、今回はテキストでなく、取敢えず読める程度の縮尺イメージにさせてもらった。SPAM迷惑投稿を貼付て、実行ボタンをクリック!!
 SPAM迷惑投稿を貼付て、実行ボタンをクリックすると、Firefoxの場合は(formタグに「target="_blank"」を設定しているので)別タブに以下の画面が表示される。テキスト欄の必要な文字列をコピーし、Blogのコメント管理画面に貼付けて書替
 テキスト欄の必要な文字列をコピーし、Blogのコメント管理画面に貼付けて書替て作業完了となる。

 さて、これからはいつもの通り<pre>タグによるテキスト情報なので、コピペでのソース取得が可能だ。尚、今回より、汎用関数は当方の共通モジュールとして「Lib/site-packages/mire」以下に配置し、それをimportさせたので、今回説明するフォーム表示&データ処理、そして、次稿で説明するCGIプログラムのdebugの為の処理が目立つ程度で、後は、多少__doc__や__copyright__等、他人の配布モジュールにあるglobal変数を追加したことくらいである。
 Web/cgi-bin/html4spam.py


#!c:/Python26/python
# -*- coding: UTF8 -*-
# ※ Windows の場合1行目はdummyです

u"""
#####################################################################
# SPAM COMMENT SPLITTER 0.0.0 (C) Mire 2009-10-15 #
#####################################################################
 blogを持っていると
怒り^^;;を込めて、SPAM迷惑投稿を切り刻みます。コピペで上書きすれば、
内容はそのままでも目的のURL linkは全てはずれレンダリングも消えます。
USEGE:
1.SPAM迷惑投稿をテキスト欄に貼付けボタンをクリックして下さい。
2.別窓または別タブで1文字毎の半角スペース区切りテキストが表示。
3.このスペース区切テキストのCopy&PaseteでSPAM迷惑投稿を置換え
"""

__author__ = "Mire in Japan"
__version__ = '0.0.0'
__copyright__ = 'Copyright (c) 2009 Mire'
__license__ = 'GPL'
__url__ = 'http://pythonlife.seesaa.net/'

debug = 0 #debugレベル


########################################
## 当Tool専用関数の定義contents()のみ ##
########################################
def contents(debug=1):
u"""
コンテンツ「入出力フォーム」を表示します
"""
try:
from mire.htm import display_err, cgi_params

print u'<table width="590px" style="background-color:#F0F0F0;"><tr>'
print u'<td><font size="-1"><b>怒り^^;;を込めSPAM迷惑投稿を切刻みます。\
コピペで上書きすれば内容はそのままでもURLのレンダリングは消えます。</b>\
</font></td></tr><tr><td><center>',

prms=cgi_params() #> mire.htm.cgi_params(): CGI引数情報の辞書を返します

if debug > 1: #debugレベル2: CGI引数の名前と値を表示します。
print '<pre align="left" style="text-align:center; white-space: pre-wrap;\
white-space: -moz-pre-wrap; white-space: -pre-wrap; white-space: -o-pre-wrap;\
word-wrap: break-word; ">'
for p in prms:
print '%s: %s' % (p,prms[p])
print '</pre>'

if 'html_text' in prms: #cgi引数が存在したら、
html_text=unicode(prms['html_text']) # CGIの引数の値はunicode化が必要な様だ
ss=p=''
for s in html_text:
#unicodeはMultiBite文字も文字単位処理
if s=='\n' or s=='\r' or p=='\n' or p=='\r' or ss=='': #改行符号と頭の文字の
ss=ss+s #前後には空白文字を加えず
else: #そうでないなら
ss=ss+' '+s #空白文字を加える
p=s #直前の文字を代入
html_text=ss #html_textを置換え
else: #引数がないなら
html_text='' #0長文字列

#コンテンツ本体: table,form textarea,inputタグで入出力画面を表示
print u'<table><form method="post" target="_blank"><tr>'
print u'<td><textarea cols="88" rows="20" style="font-size:8pt;" name="html_text"',
print u'mire_val="html4blog_text(html_text)">%s</textarea></td>' % (html_text)
print u'</tr><tr><td><center>',
print u'<input type="submit" style="font-size:8pt; width:567px">',
print u'</center></td></tr></form></table></center></td></tr></table>'


except: #vividな作成部分はhtml
if debug > 0:
print '<span align="left">'
display_err(locals()) #>mire.htm.display_err() #用の例外処理で障害切分
print '</span>'
else: #運用中のdebug message表示はセキュリティ上不適格。通常はdebug=0で以下のmessage
print '<pre>Error was occured.\nPlease, contact your system administrators.\n'
print 'You? Do Your Best!\n Test html4spam.py with debug=2. Good luck.</pre>'


########################################
## ##
## 処理実行開始位置 ##
## ##
########################################
try:
from mire.htm import display_err, html_header, html_footer
html_header(charset='UTF-8', title=u'SPAM COMMENT SPLITTER (C) 2009 Mire GPL license'
, body=['style="right-margin:0px; background-color:#808080;"'])
contents(debug=debug)
html_footer()

except:
if debug > 0:
display_err(locals()) #こちらは最後の抑え
else: #運用中のdebug message表示はセキュリティ上不適格。通常はdebug=0で以下のmessage
print 'Content-type: text/html\n\n<html>\n<head></head><body>'
print '<pre>Error was occured.\nPlease, contact your system administrators.\n'
print 'You? Do Your Best!\n Test html4spam.py with debug=2.\n\nGood luck.</pre>'
print '</pre></body></html>'



 さて、ソースコード「html4spam.py」を早速眺め試よう。尚、今回説明する部分は太字にしておいた。先ずは「処理実行開始位置」のある下の方から見て行こう。

1. モジュールからの汎用関数のimport


 「from mire.htm import display_err, html_header, html_footer」では、「Lib/site-packages/mire/htm.py」に定義してある関数をimportして、Pythonの名前空間に登録し参照を可能にし、html_header()という記述で関数利用を可能にしているものだ。

2. CGIとしてのHTML文書を標準出力する


 既に標準化した関数で後述する「contents()関数」を挟んで、コンテンツを先ずは無難に表示させる様にしている。
html_header(charset='UTF-8', title=u'タイトル名', body=['style="right-margin:0px; background-color:#808080;"'])
contents(debug=debug)
html_footer()
 今回は取敢えず、スタイルシートは直書き、今風には使わない表示制御系のHTMLタグを多用したので、設定しなかったが、cssには「〜.css」といったスタイルシート定義ファイルを文字列リストとして複数設定出来る等、必要とされるほぼ全てのものがhtml_header()には網羅されている。
 ということで、今回のメインのお仕事は、実際に表示される中身を定義するcontents()関数を作るだけということになる。

3. CGI引数情報を取得する関数他をimport


 「from mire.htm import display_err, cgi_params」で、5行後にある「prms=cgi_params()」の1行でしWebブラウザとの間でCGIによるデータ受信が可能になる。直下のprint分は見栄えの為ごちゃごちゃしているが、「怒り^^;;を込めSPAM迷惑投稿を切刻みます。\
コピペで上書きすれば内容はそのままでもURLのレンダリングは消えます。」を表示したいだけだ。

4. テキスト欄の入力内容が引数「html_text」で返ってきたら「切刻み」


 引数「html_text」があったら、その中身を最初の1文字目と改行符号のある時を除き半角空白文字を挟んで行き、処理が終わったら、それ(ss)を「html_text」に代入し、そうでないなら「html_text」にゼロ長文字列を代入するという、このツール最大のお仕事をしているところだ。

5. 「コンテンツ本体」を表示


print u'<table><form method="post" target="_blank"><tr>'
ここで一番大切なところはこの行だ。
  1. formタグでmethodをpostに指定したことで、テキスト欄に思う存分の文字数を入れて実行出来る様になる。
  2. formタグでtargetを_blankにしたことで別窓(または別タブ)で開く様になる。
  3. action設定がないのでこの「html4spam.py」のurlがcgi通信を投げる相手は「html4spam.py」となる。


 これを前提に次の2行でtextareaタグとsubmitボタンを配置し、textareaタグ内には「html_text」の中身を表示させる様にしている。
print u'mire_val="html4blog_text(html_text)">%s</textarea></td>' % (html_text)
print u'<input type="submit" style="font-size:8pt; width:567px">',


 以上の仕組みで、テキスト欄に文字を入れてボタンをクリックすると、別窓または別タブの同じフォームに半角空白文字で切刻んだものが表示されることになる訳で、その動作を「SPAM迷惑投稿対策」に使うという付加価値を求め「SPAM COMMENT SPLITTER」と称しているのが、このツールの実体だ。


 最後になるが、このままでは、当方のmireパッケージがないので動かないので、以下に今回使ったモジュール内の関数4つを参考迄掲載して置く。
  Lib/site-packages/mire/htm.py


#!c:/Python26/python
# -*- coding: UTF8 -*-
# ※ Windows の場合1行目はdummyです

u"""
######################################################################
#01. html_header(charset, :html文書の開始タグ一式を標準出力します
# ,title,base :
# ,refresh :
# ,cache,robot:
# ,css,style :
# ,js,author :
# ,generator :
# ,keywords :
# ,description:
# ,body) :
#02. def html_footer() : html文書の終了タグ一式を標準出力
#03. url2str_list(url) : urlの示す文書を文字列リストで返します
#04. url2str(url,trim=0) : urlを文字列で返します。前後空白除去trim=1
#05. get_charset(s) : str文字列からmeta定義のcharsetを返します
#06. str2unicode(s,charset) : 文字列のunicode化を試みその文字列を返します
#07. cgi_params() : CGI引数を辞書化し返します
#08. param_lst(omit_params : 引数とその値をGET形式'引数名=値'文字列listを
# ,params_dic): 返す「url+'?'+'&'.join(<param_lst>)」で活用
#09. tag_encode(lines) : タグ文字のままHTML表示可能な文字列listに変換
#10.
#

"""
__author__ = "Mire in Japan"
__version__ = '0.0.0'
__copyright__ = 'Copyright (c) 2009 Mire'
__license__ = 'GPL'
__url__ = 'http://pythonlife.seesaa.net/'


def html_header0():
print 'Content-type: text/html\n'

## html文書の開始タグ一式を標準出力します
def html_header(charset='UTF-8',title='',base='',refresh=[],cache=0,robot=0
,css=['/css/default.css'],js=['/js/default.js'],author=''
,generator="Mire's Python CGI",keywords=[],description=[]
,style=[],body=[],h=1):
u"""
charset : 文字コード 'Shift_JIS','UTF-8','EUC-JP'等
title : HTMLヘッダタイトル 文字列指定
base : 相対URL表記のベースURL 文字列指定、無指定はcgiファイルの設置位置
、'/'はサーバroot
refresh : 指定秒後に自頁または指定頁へジャンプ [秒数] or [秒数,'ジャンプ先URL']
cache : cache期限を秒数で指定 整数、-1:期限なし、0:cacheなし
robot : 自動検索エンジンに表明 禁止:-1、了解:1
css : スタイルシートファイルをリストで指定 []:利用しない
style : 個別のスタイルをリストで指定 []:利用しない
js : JavaScriptファイル  をリストで指定 []:利用しない
author : 執筆者 文字列指定
generator : 作成エディタ 文字列指定
keywords : 検索エンジン用キーワードをリストで指定
description : 検索エンジン用文献説明をリストで指定
h : 'Content-type: text/html\n'の付加:h=1
"""
from time import time,gmtime,strftime
if h==1:
#print 'Content-type: text/html; charset=%s\n\n' % (charset)
print 'Content-type: text/html;\n\n'
print '<html>\n<head>'
if not base=='':
print '<base href="%s" target="_self">' % (base)
print '<meta http-equiv="Content-Type" content="text/html; charset=%s" />' % (charset)
if len(refresh)>0: # refresh秒のみが指定されたら、その間だけcasheする。
if len(refresh)==1 and cashe>refresh[0]:
cache=refresh[0]
if len(refresh)>1:
url='; url=%s' % (refresh[1])
else:
url=''
print '<meta http-equiv="refresh" content="%d%s">' % (reflesh[0],url)
print '<title >%s</title>' % (title) # ページタイトル
if cache==0:
print '<meta http-equiv="pragma" content="no-cache">'
elif cache>=1: #cache期限として現在時にcache秒を足した日時の"Sat, 31 Aug 2009 17:35:42 GMT"形式日時文字列
print strftime('<meta http-equiv="expires" content="%a, %d %b %Y %H:%M:%S GMT">',gmtime(time()+cache))
if len(author):
print '<meta name="author" content="%s">' % (author)
if not generator=='':
print '<meta name="generator" content="%s">' % (generator)
if len(description)>0: # description文書説明
print '<meta name="description" content="%s" />' % (','.join(description.sort()))
if len(keywords)>0: # キーワード
print '<meta name="keywords" content="%s" />' % (','.join(keywords.sort()))
if robot==1:
print '<meta name="robots" content="all">'
elif robot==-1:
print '<meta name="robots" content="noindex,nofollow">'
if len(js)>0: # JavaScript活用
print '<meta http-equiv="Content-Script-Type" content="text/javascript" />'
if len(css)>0: # StyleSheet活用
print '<meta http-equiv="Content-Style-Type" content="text/css" />'
for c in css: # css スタイルシートファイルリンク先 #
print '<link rel="stylesheet" href="%s" type="text/css" />' % (c)
for j in js: # javascriptファイルリンク先 #
print '<script type="text/javascript" src="%s"></script>' % (j)
if len(style)>0:
print '<style type="text/css">%s</style>' % (' '.join(style))
print '</head>'
print '<body %s>' % (' '.join(body))

## html文書の終了タグ一式を標準出力
def html_footer():
u"""
html文書の終了タグ一式を標準出力
"""
print '</body>\n</html>'


## CGI引数の辞書化 ##
def cgi_params():
u"""
## CGI引数の辞書化 ##
cgi.FieldStorage()で得られるcgi引数を辞書に収め返す
辞書構造とすることで修正が可能になる他、
必要な既存の引数を引継ぎインタラクティブにページを変化
させるときに便利。
【使い方】
下記の様に引数名を keys()で取得、順不同の為、必要より、
sort()の上、引数名を1つずつ取出し活用すると良い
param_dic = cgi_params()
keys = param_dic.keys()
for k in keys:
value = param_dic[k]
print k,value
"""
import cgi
form = cgi.FieldStorage()
params= {}
keys = form.keys()
for key in keys:
params[key]=form[key].value
return params


## エラー表示関数(コメント行文字化け対策+thread実行時のエラー情報表示の時系列混乱軽減) ##
waiting=0
def display_err(local, title = u'\n\n#### EXCEPTION ERROR ####'):
"""
##########################################################################################
#エラー表示関数(コメント行文字化け対策 + thread実行時のエラー情報表示の時系列混乱軽減) #
#USAGE: 第一引数に「locals()」を指定することで、処理時の変数値を表示します。 #
# waitingはthread実行時のエラー情報表示の時系列混乱軽減の為のWAIT処理です。 #
# waiting = 0 #
# def foo(): #
# global waiting #
# sleep(waiting) #
# try: #
# 処理 #
# waiting = 0 #
# except: #
# display_err(locals(),'<例外処理の場所を表すタイトル>')# locals()指定は必須 #
# waiting = 1 #
# foo() #
##########################################################################################
"""
import traceback
from time import sleep
print 'Content-type: text/html\n\n<html>\n<head>'
print '<body><pre>'
if local is None:
local =locals()
global waiting
frame0 = u'\n*******************************************************************************'
frame1 = u'*******************************************************************************\n\n'
errs = [frame0, title]
errs.append(u'%s' % (dsp_hex(traceback.format_exc()))) #> dsp_hex(s): コメント文字化け対策
sleep(waiting)
ls = local
keys = ls.keys()
errs.append(u'')
for key in keys: # display_err()関係の変数の表示を省く
# if not key in ['v', 'ls', 'keys', 'key', 'errs', 'txt', 'er', 'sleep']:
er = u'* %s: %s' % (repr(key).ljust(24),repr(ls[key]))
errs.append(er)
errs.append(frame1)
txt = u'\n'.join(errs)
print txt
print '</pre></body></html>'

## コメント文字化け対策 ##
def dsp_hex(s):
from re import search
charsets=['UTF-8','Shift_JIS','EUC-JP','iso-2022-jp'] # どれでもいいので、charsetで、
for charset in charsets: # unicode化し、コメント部分の
try: # 文字化けを防ぐ
return unicode(s,charset)
except:
print u'%sでは変換不能でした' % (charset)
pass
sss=u''
for ss in s: # 想定外のcharsetのときは16進数表記に
if (ord(ss)>=32 and ord(ss)<=126) or ss.isspace(): # Windowsにはcurses.ascii.isprint()が
sss=sss+ss # ないのでcurses/ascii.pyの中身を展開
else:
sss=sss+'\\'+hex(ord(ss))[2:].upper()
return sss
(※html4spam.pyで不要なものは省いている。)続きを読む
タグ:CGI Python
posted by Mire at 23:34 | Comment(0) | TrackBack(0) | セキュリティ | このブログの読者になる | 更新情報をチェックする

【PythonのHELP】Pythonにはhelp()関数有ったんだぁ

 そろそろ、自前のソースコードが貯まって来て、良く似た関数や処理を繰返し書くことが増えて来た。まあ、元々が、Pythonリハビリ目的なので関数のモジュール化には消極的だったが、PyPRecでは重箱の角をつついていると元居た角を忘れている自分が居て、そんな自分に閉口している所だ。

 そこで、やはり、自作の汎用関数は、Lib/sitepackages/ に放り込んで管理しようとやっと思うに至った。だが、以前やっていた様に同じファイルに味噌も糞も放り込んでいては、いずれまた、似た様な関数が散在し統一性がなくなるので、今度はフォルダ内にカテゴリーで分類して管理して行こうと思う。同時に、こういった関数群の使い方を文書で残し管理者である自分が最初の迷子にならない様にと思い、__doc__をこまめに書込む様にした。
 ただ、この__doc__はパッケージ(フォルダ)、モジュール(ファイル)、関数とクラス別、そしてクラスのメソッドに個別に書込むことが可能だ。そんな分散記載した__doc__を寄せ集めて簡易のマニュアルにしてしまえば、こんな自分も迷子にならなくて済むと思い、元々、空ファイルでしか活用してこなかったパッケージの__init__.pyで
Lib/site-packages/mire/__init__.py


<前略>
import std
__doc__=__doc__+'\n'+std.__name__+std.__doc__
import htm
__doc__=__doc__+'\n'+htm.__name__+htm.__doc__
import html
__doc__=__doc__+'\n'+html.__name__+html.__doc__
import std
<後略>
<注記: __man__等の自前global変数でするならprint __mam__で活用可能。自作help作成ならこちらかも>
等と書込み__doc__を表示させ遊んでいて、こんなの誰でもあったらいいなって思うよなと思っていたら、help(obj)という組込関数があることを発見!。 Pythonとのお付き合いは1.xの頃からなので見逃していた。(未だに、「Pythonテクニカルリファレンス」(ピアソンE.刊)2000-08-25を使っているくらいなので、それ以降の変化について行っていない^^;;)

 使い方は、pythonを起動して必要なパッケージモジュールをimportして、pythonの名前空間に認識させてからhelp(パッケージ名)とするだけだ。
Microsoft Windows [Version 6.0.6001]
Copyright (c) 2006 Microsoft Corporation. All rights reserved.

C:\Users\SysAdm>c:\Python26\python.exe
Python 2.6.2 (r262:71605, Apr 14 2009, 22:40:02) [MSC v.1500 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import mire
>>> help(mire)
Help on package mire:

NAME
mire

FILE
c:\python26\lib\site-packages\mire\__init__.py

DESCRIPTION
######################################################################
# mire module
######################################################################
##
## std 標準入出力+例外処理
## html関数群 : htm
## htmlクラス : html
##
##


mire.std
######################################################################
#標準入出力関係の関数群
#
#01. str2unicode(s,charset) :文字列のunicode化を試みます
#02. file2utf8list(file_name :fileを読込みunicodeのlistを返します
# ,stdin_charset) :


mire.htm
######################################################################
#01. html_header(charset, :html文書の開始タグ一式を標準出力します
# ,title,base :
# ,refresh :
# ,cache,robot:
# ,css,style :
# ,js,author :
# ,generator :
# ,keywords :
# ,description:
# ,body) :
#02. def html_footer() : html文書の終了タグ一式を標準出力
#03. url2str_list(url) : urlの示す文書を文字列リストで返します
#04. url2str(url,trim=0) : urlを文字列で返します。前後空白除去trim=1
#05. get_charset(s) : str文字列からmeta定義のcharsetを返します
#06. str2unicode(s,charset) : 文字列のunicode化を試みその文字列を返します
#07. cgi_params() : CGI引数を辞書化し返します
#08. param_lst(omit_params : 引数とその値をGET形式'引数名=値'文字列listを
# ,params_dic): 返す「url+'?'+'&'.join()」で活用
#09. tag_encode(lines) : タグ文字のままHTML表示可能な文字列listに変換
#10.
#


mire.html
######################################################################
# This code is tried to change my html display functions to class.
#html表示関係の関数をまとめてclass化して試たものです
#USAGE:
#h = html()
#h.contents = [u'通常、ここには別途作成した
', u'コンテンツをリストで指定します。']
#h.style = ['fine{background-color:#F0F0F0; font-size:10pt; line-height:12pt;}'
# , 'ss{font-size:6pt; line-height:6pt;}'
# , '.td{font-size:10pt; line-height:6pt;}']
#h.body = ['class="fine"']
#h.display()
#
#charset : 文字コード 'Shift_JIS','UTF-8','EUC-JP'等
#title : HTMLヘッダタイトル 文字列指定
#base : 相対URL表記のベースURL 文字列指定、無指定はcgiファイルの設置位置
# 、'/'はサーバroot
#refresh : 指定秒後に自頁または指定頁へジャンプ [秒数] or [秒数,'ジャンプ先URL']
#cache : cache期限を秒数で指定 整数、-1:期限なし、0:cacheなし
#robot : 自動検索エンジンに表明 禁止:-1、了解:1
#css : スタイルシートファイルをリストで指定 []:利用しない
#js : JavaScriptファイル  をリストで指定 []:利用しない
#author : 執筆者 文字列指定
#generator : 作成エディタ 文字列指定
#keywords : 検索エンジン用キーワードをリストで指定
#description : 検索エンジン用文献説明をリストで指定
#body : 文書全体への書式等をリストで指定
#contents=[]
#

PACKAGE CONTENTS
htm
html
mng
net
std

DATA
version = '2.6.2 (r262:71605, Apr 14 2009, 22:40:02) [MSC v.1500 32 bi...


>>>
>>>
>>>
という感じだ。

 ただ、残念なことにこのhelp()君、日本語は余りお得意ではない様で
安定しないのが欠点の様だ。仕方がないので、これ迄、複数文字コード利用にこだわり入れてなかった「sitecustomize.py」を設定して試て初めて得られたのが上の結果だ。

 尚、当然ながら、python3では、文字列をunicodeが則る仕組みなのでなんらの苦も無く以下の様な表示が出来る。
>>> help(mire.html.html)
Help on class html in module mire.html:

class html(builtins.object)
| ######################################################################
| #class html()html表示関係の関数をまとめてclass化したものです
| #charset : 文字コード 'Shift_JIS','UTF-8','EUC-JP'等
| #title : HTMLヘッダタイトル 文字列指定
| #base : 相対URL表記のベースURL 文字列指定、無指定はcgiファイルの設置位置
| # 、'/'はサーバroot
| #refresh : 指定秒後に自頁または指定頁へジャンプ [秒数] or [秒数,'ジャンプ先URL']
| #cache : cache期限を秒数で指定 整数、-1:期限なし、0:cacheなし
| #robot : 自動検索エンジンに表明 禁止:-1、了解:1
| #css : スタイルシートファイルをリストで指定 []:利用しない
| #js : JavaScriptファイル  をリストで指定 []:利用しない
| #author : 執筆者 文字列指定
| #generator : 作成エディタ 文字列指定
| #keywords : 検索エンジン用キーワードをリストで指定
| #description : 検索エンジン用文献説明をリストで指定
| #body : 文書全体への書式等をリストで指定
| #contents=[]
|
| Methods defined here:
|
| __init__(self)
|
| content(self)
|
| display(self)
|
| display_err(self, local, title='\n\n#### EXCEPTION ERROR ####')
| ##########################################################################################
| #エラー表示関数(コメント行文字化け対策 + thread実行時のエラー情報表示の時系列混乱軽減) #
| #USAGE: 第一引数に「locals()」を指定することで、処理時の変数値を表示します。 #
| # waitingはthread実行時のエラー情報表示の時系列混乱軽減の為のWAIT処理です。 #
| # waiting = 0 #
| # def foo(): #
| # global waiting #
| # sleep(waiting) #
| # try: #
| # 処理 #
| # waiting = 0 #
| # except: #
| # display_err(locals(),'<例外処理の場所を表すタイトル>')# locals()指定は必須 #
| # waiting = 1 #
| # foo() #
| ##########################################################################################
|
| dsp_hex(self, s)
|
| footer(self)
|
| header(self)
|
| ----------------------------------------------------------------------
| Data descriptors defined here:
|
| __dict__
| dictionary for instance variables (if defined)
|
| __weakref__
| list of weak references to the object (if defined)


 よかったら、皆さんも__doc__を書きませんか?
各階層の頭に最初に書く文字列が__doc__になるので通常
  〜.pyの参考例:


"""
ここがこのファイルモジュールの__doc__になる
"""
def func():
"""
ここはfunc.__doc__になる
"""
<関数定義>

class class_a(object):
"""
ここはclass_a.__doc__になる
"""
def method1():
""""
ここはclass_a.method1.__doc__になる

""""
<method定義>
タグ:Python
posted by Mire at 14:16 | Comment(0) | TrackBack(0) | Pythonプログラミング | このブログの読者になる | 更新情報をチェックする

2009年10月12日

【PythonのERROR情報】traceback を使った display_err()関数

 余程に完全無欠な人で完璧なソースコードを一発で書く様でない限り、ソフトウエア作成中のエラー情報の活用は不可欠であろう。Pythonでは通常、何もしないでも、継続不能な例外エラーが発生すれば、その例外タイプと原因、そしてその発生した行番号とソース行が表示される。
 しかし、例外エラー発生の原因を絞り込むには、その示す位置に「try:〜;except:〜;」という例外処理を加え、その情報を得たい場合には、tracebackやsys.exc_info()、そしてlocals()等を活用することになる。一般的には、不具合に出会う度に手書きで逐次対処していることが多いだろうが、今回、その為の関数「display_err()」を作成して試た。

 tracebackモジュールでは、thread freeでなかったり、循環処理の可能性がある等の理由で成果物への埋め込みは必ずしも推奨しないが、debug時には、障害発生箇所と原因を掴めるので欠かせない。この関数では、traceback objoctの返す情報をtraceback..format_exc()で文字列として取得し、表示文字コード処理で日本語コメントの文字化けに対処した他、thread実行時のエラー情報表示の時系列混乱を防ぐ為にwaitingというglobal変数を使い乱れを軽減した。

  TestCode/display_err_by_traceback_test.py


#!c:/Python26/python.exe
# -*- coding: UTF-8 -*-
# ※ Windows の場合1行目はdummyです。

waiting = 0 #  これはdisplay_err() 実行時にWAITを置き、
# thread実行時のエラー情報表示の時系列混乱を
# 防ぐ為のglobal変数

## エラー表示関数(コメント行文字化け対策+thread実行時のエラー情報表示の時系列混乱軽減) ##
def display_err(local, title = u'\n\n#### EXCEPTION ERROR ####'):
"""
##########################################################################################
#エラー表示関数(コメント行文字化け対策 + thread実行時のエラー情報表示の時系列混乱軽減) #
#USAGE: 第一引数に「locals()」を指定することで、処理時の変数値を表示します。 #
# waitingはthread実行時のエラー情報表示の時系列混乱軽減の為のWAIT処理です。 #
# waiting = 0 #
# def foo(): #
# global waiting #
# sleep(waiting) #
# try: #
# 処理 #
# waiting = 0 #
# except: #
# display_err(locals(),'<例外処理の場所を表すタイトル>')# locals()指定は必須 #
# waiting = 1 #
# foo() #
##########################################################################################
"""
import traceback
from time import sleep
if local is None:
local =locals()
global waiting
frame0 = u'\n*******************************************************************************'
frame1 = u'*******************************************************************************\n\n'
errs = [frame0, title]
errs.append(u'%s' % (dsp_hex(traceback.format_exc()))) #> dsp_hex(s): コメント文字化け対策
sleep(waiting)
ls = local
keys = ls.keys()
errs.append(u'')
for key in keys: # display_err()関係の変数の表示を省く
# if not key in ['v', 'ls', 'keys', 'key', 'errs', 'txt', 'er', 'sleep']:
er = u'* %s: %s' % (repr(key).ljust(24),repr(ls[key]))
errs.append(er)
errs.append(frame1)
txt = u'\n'.join(errs)
print txt

## コメント文字化け対策 ##
def dsp_hex(s):
from re import search
charsets=['UTF-8','Shift_JIS','EUC-JP'] # どれでもいいので、charsetで、
for charset in charsets: # unicode化し、コメント部分の
try: # 文字化けを防ぐ
return unicode(s,charset)
except:
print u'%sでは変換不能でした' % (charset)
pass
sss=u''
for ss in s: # 想定外のcharsetのときは16進数表記に
if (ord(ss)>=32 and ord(ss)<=126) or ss.isspace(): # Windowsにはcurses.ascii.isprint()が
sss=sss+ss # ないのでcurses/ascii.pyの中身を展開
else:
sss=sss+'\\'+hex(ord(ss))[2:].upper()
return sss



###################
#### TEST CODE ####
###################

## threadで実行に組込んだ関数 ##
def test_func():
"""
datetimeの演算は引算のみ、足算は出来ないぞ
"""
from time import sleep
from datetime import datetime

global waiting
sleep(waiting)
try:
a=datetime.now()
b=datetime.now()
sleep(waiting)
c=datetime.now()
a=b-c
d=c+b # datetimeを足したいの I what to add datetime object's.
print a
waiting = 0
except:
display_err(locals(),title = u'### main()内例外発生時の情報 ###') # locals()指定は必須
waiting = 1
raise


from thread import start_new_thread
from time import sleep
try:
while 1:
try:
start_new_thread(test_func,())
#waiting = 0
except:
waiting = 1
display_err(locals(), title = u'### thread実行loopでの例外発生時の情報 ###')
break
sleep(waiting)
#print waiting
except:
display_err(locals(), title = u'### 終了時の情報 ###') # 終了時の情報

 以下が、上記テストコードの実行結果だ。連続LOOPの為、当然、Ctrl+Cで停止して取得している。残念ながら、Windowsのコマンドプロンプトでの実行では、「Unhandled exception in thread started by <function test_func at 0x01C6CE30>」の発生内容がECHOされ文字化けしたtraceback情報が表示されている。
D:\TestCode>python display_err_by_traceback_test.py

*******************************************************************************
### main()内例外発生時の情報 ###
Traceback (most recent call last):
File "traceback_exc_info_and_locals_within_thread5.py", line 90, in test_func
d=c+b # datetimeを足したいの I what to add datetime object's.
TypeError: unsupported operand type(s) for +: 'datetime.datetime' and 'datetime.datetime'


* 'a' : datetime.timedelta(0)
* 'c' : datetime.datetime(2009, 10, 12, 6, 16, 36, 765000)
* 'b' : datetime.datetime(2009, 10, 12, 6, 16, 36, 765000)
* 'sleep' : <built-in function sleep>
* 'datetime' : <type 'datetime.datetime'>
*******************************************************************************

<中略: thread実行の為出力順が途中乱れる>

Unhandled exception in thread started by <function test_func at 0x01C6CE30>
Traceback (most recent call last):
File "traceback_exc_info_and_locals_within_thread5.py", line 90, in test_func
d=c+b # datetime繧定カウ縺励◆縺・・ I what to add datetime object's.
TypeError: unsupported operand type(s) for +: 'datetime.datetime' and 'datetime.datetime'

*******************************************************************************
### main()内例外発生時の情報 ###
Traceback (most recent call last):
File "traceback_exc_info_and_locals_within_thread5.py", line 90, in test_func
d=c+b # datetimeを足したいの I what to add datetime object's.
TypeError: unsupported operand type(s) for +: 'datetime.datetime' and 'datetime.datetime'


* 'a' : datetime.timedelta(-1, 86399)
* 'c' : datetime.datetime(2009, 10, 12, 6, 21, 0, 292000)
* 'b' : datetime.datetime(2009, 10, 12, 6, 20, 59, 292000)
* 'sleep' : <built-in function sleep>
* 'datetime' : <type 'datetime.datetime'>
*******************************************************************************


Unhandled exception in thread started by <function test_func at 0x01C6CE30>
Traceback (most recent call last):
File "traceback_exc_info_and_locals_within_thread5.py", line 90, in test_func
d=c+b # datetime繧定カウ縺励◆縺・・ I what to add datetime object's.
TypeError: unsupported operand type(s) for +: 'datetime.datetime' and 'datetime.datetime'

*******************************************************************************
### 終了時の情報 ###
Traceback (most recent call last):
File "traceback_exc_info_and_locals_within_thread5.py", line 110, in <module>
sleep(waiting)
KeyboardInterrupt


* 'test_func' : <function test_func at 0x01C6CE30>
* '__builtins__' : <module '__builtin__' (built-in)>
* 'display_err' : <function display_err at 0x01C6CEB0>
* '__file__' : 'traceback_exc_info_and_locals_within_thread5.py'
* 'start_new_thread' : <built-in function start_new_thread>
* '__package__' : None
* 'dsp_hex' : <function dsp_hex at 0x01C6CE70>
* 'waiting' : 1
* 'sleep' : <built-in function sleep>
* '__name__' : '__main__'
* '__doc__' : None
*******************************************************************************

D:\TestCode>
タグ:Python
posted by Mire at 07:24 | Comment(0) | TrackBack(0) | Pythonプログラミング | このブログの読者になる | 更新情報をチェックする

2009年10月09日

【PythonでClass】気の迷いで^^;; CGI HTML出力系関数をclass化

 ちょいとした気の迷いから、日頃すっきりし過ぎて使い方が判らなくなりそうなのでやっていないクラス作成をやって試た。

 日頃は、結構、場当たり発想によるしゃかしゃかコーディング派なので発想を大切にした関数の書き殴りしかしないのだが、たまにはクラスも書いていないと、人の作ったモジュールを使う時にかったるい想いをするので、少しは頭に強く植え付けて置くのも悪くないかもと少しだけ時間を使ってトレーニングした。ついでに自分で理解したよと言う想いを持つ為に何かをクラス化しよう思ったが、あまり関連付けの強い関数群が思い当たらない。仕方がないので、以前書いた「html_header()」と「html_footer()」を一括記載するだけのメリットしかないクラス「html」を作成することにした。このクラスでは以前の関数で端折っていたstyleタグの埋め込みやコンテンツをリストで渡せる様にしてまとめた。結果は次の通り。
 TestCode/html.py


#!c:/Python26/python
# -*- coding: UTF8 -*-
# ※ Windows の場合1行目はdummyです。

## HTML文書のCGI出力 ##
class html(object):
"""
charset : 文字コード 'Shift_JIS','UTF-8','EUC-JP'等
title : HTMLヘッダタイトル 文字列指定
base : 相対URL表記のベースURL 文字列指定、無指定はcgiファイルの設置位置
、'/'はサーバroot
refresh : 指定秒後に自頁または指定頁へジャンプ [秒数] or [秒数,'ジャンプ先URL']
cache : cache期限を秒数で指定 整数、-1:期限なし、0:cacheなし
robot : 自動検索エンジンに表明 禁止:-1、了解:1
css : スタイルシートファイルをリストで指定 []:利用しない
js : JavaScriptファイル  をリストで指定 []:利用しない
author : 執筆者 文字列指定
generator : 作成エディタ 文字列指定
keywords : 検索エンジン用キーワードをリストで指定
description : 検索エンジン用文献説明をリストで指定
body : 文書全体への書式等をリストで指定
contents=[]
"""

def __init__(self):
self.charset = 'UTF-8' #文字コード 'Shift_JIS','UTF-8','EUC-JP'等
self.title = '' #HTMLヘッダタイトル 文字列指定
self.base = '' #相対URL表記のベースURL 文字列指定
#無指定はcgiファイルの設置位置、'/'はサーバroot
self.refresh = [] #指定秒後に自頁または指定頁へジャンプ
# [秒数] or [秒数,'ジャンプ先URL']
self.cache = 0 #cache期限を整数秒で指定 -1:期限なし,0:cacheなし
self.robot = 0 #自動検索エンジンに表明 禁止:-1,了解:1
self.css = ['/css/default.css'] #スタイルシートファイルをlistで指定[]:利用しない
self.style = [] #個別のスタイルをリストで指定 []:利用しない
self.js = ['/js/default.js'] #JavaScriptファイルをリストで指定 []:利用しない
self.author = '' #執筆者 文字列指定
self.generator = "Mire's Python CGI" #作成エディタ 文字列指定
self.keywords = [] #検索エンジン用キーワードをリストで指定
self.description = [] #検索エンジン用文献説明をリストで指定
self.body = [] #文書全体への書式等をリストで指定
self.contents = [] #文書コンテンツ本体をリストで指定

def header(self):
#, charset='Shift_JIS',title='',base='',refresh=[],cache=0,robot=0
# ,css=['/css/default.css'],js=['/js/default.js'],author=''
# ,generator="Mire's Python CGI",keywords=[],description=[]):
from time import time,gmtime,strftime
print 'Content-type: text/html\n\n<html>\n<head>'
if not self.base=='':
print '<base href="%s" target="_self">' % (self.base)
print '<meta http-equiv="Content-Type" content="text/html; charset=%s" />' % (self.charset)
if len(self.refresh)>0: # self.refresh秒のみが指定されたら、その間だけcasheする。
if len(self.refresh)==1 and self.cashe>self.refresh[0]:
self.cache=self.refresh[0]
if len(self.refresh)>1:
url='; url=%s' % (self.refresh[1])
else:
url=''
print '<meta http-equiv="refresh" content="%d%s">' % (self.reflesh[0],url)
print '<title >%s</title>' % (self.title) # ページタイトル
if self.cache==0:
print '<meta http-equiv="pragma" content="no-cache">'
elif self.cache>=1: #cache期限として現在時にcache秒を足した日時の
#"Sat, 31 Aug 2009 17:35:42 GMT"形式日時文字列
print strftime('<meta http-equiv="expires" content="%a, %d %b %Y %H:%M:%S GMT">'
,gmtime(time()+self.cache))
if len(self.author):
print '<meta name="author" content="%s">' % (self.author)
if not self.generator=='':
print '<meta name="generator" content="%s">' % (self.generator)
if len(self.description)>0: # description文書説明
print '<meta name="description" content="%s" />' % (','.join(self.description.sort()))
if len(self.keywords)>0: # キーワード
print '<meta name="keywords" content="%s" />' % (','.join(self.keywords.sort()))
if self.robot==1:
print '<meta name="robots" content="all">'
elif self.robot==-1:
print '<meta name="robots" content="noindex,nofollow">'
if len(self.js)>0: # JavaScript活用
print '<meta http-equiv="Content-Script-Type" content="text/javascript" />'
if len(self.css)>0: # StyleSheet活用
print '<meta http-equiv="Content-Style-Type" content="text/css" />'
for c in self.css: # css スタイルシートファイルリンク先 #
print '<link rel="stylesheet" href="%s" type="text/css" />' % (c)
for j in self.js: # javascriptファイルリンク先 #
print '<script type="text/javascript" src="%s"></script>' % (j)
print '<style type="text/css">%s</style>' % (' '.join(self.style))
print '</head>'
print '<body %s>' % (' '.join(self.body))

def footer(self):
print '</body>\n</html>'

def content(self):
for c in self.contents:
print c.rstrip()

## HTML文書設定を加えたコンテンツを順番通り標準出力 ##
def display(self):
self.header()
self.content()
self.footer()


if __name__ == "__main__":
h = html()
h.contents = [u'通常、ここには別途作成した<br/>',u'コンテンツをリストで指定します。']
h.style = ['fine{background-color:#F0F0F0; font-size:10pt; line-height:12pt;}'
, 'ss{font-size:6pt; line-height:6pt;}'
, '.td{font-size:10pt; line-height:6pt;}']
h.body = ['class="fine"']
h.display()
print vars()


 後、cgi引数関係何ぞも入れると良いのかもなと思うが取敢えず目的は果たしたので本日はここ迄とする。でも、何か見通しが悪い様な気がしてならないのは気のせいか。まだクラスは好きになれない。

 取敢えず関数のクラス化で必要なことをまとめると次の内容となる。
    単純な関数をクラス化する。
    def prn(a='Hello, World!!'):
    print a





    a='aaaa'
    prn(a=a)

    class f(object):
    def __init__(self):
    self.a = 'Hello, World!!'
    def prn(self):
    print self.a

    x=f()
    x.a ='aaaa'
    x.prn()
    何処が便利なんだと言われそうな、このコンパクトなクラス化メリットマイナスの例で説明する。

    1. 関数の引数kの既定値はdef __init__(self):内にself.変数名=〜として設定することになる。
    2. 利用時には先ず、クラスの実体、インスタンスをインスタンス名 = クラス名()で生成する手続が必要となる。
    3. 利用時の引数の値はインスタンス.変数名=〜として設定することになる。
    4. 関数の動作を行なうメソッドとなったprnもインスタンス.メソッド名を記述し実行させることになる。


 便利かどうかは用途によるので、クラスを使うかどうかは関数を書き貯めてから、関係の深いもの、重複しているものをまとめるときに使うものと考えて使った方が、この場当たり発想によるしゃかしゃかコーディング派で、発想を大切にした関数の書き殴りしかしない、システムは体力だという向きの人間には良い様に思う。

 当方の場合最初から見通しが利く程の人間でもないので、最初から縛りをつけても、その思想が返って禍することも多いだろう。自らの課題に対応する発想を先ずは大切にし今後も進めて行く。私は強情だ。^^;;続きを読む
posted by Mire at 21:30 | Comment(0) | TrackBack(0) | Pythonプログラミング | このブログの読者になる | 更新情報をチェックする

2009年10月07日

NW死活監視用関数「pings()」をpythonモジュール「dpkt」で実現

 前稿では、popen()で、OSコマンドを呼出す形での死活監視実現であったが、その後、調べて試ると、windows (vista)でも有効なモジュールが見つかった。今回はそのモジュールとそのexamples中にあったpingコマンドを模したコードを芸もなく丸ごと拝借し、不要な標準出力をコメントの上必要となる応答の有無出力をreturnさせる様にして前稿のものに組み込んませてもらった。ライセンスは「New BSD License」とのことだ。

 尚、依然としてVistaでは、コマンドプロンプトを「管理者として実行」で起動したものでないと使えないので注意して欲しい。その場合とモジュールがない人様に例外処理として従来のpopen()で、OSコマンドを呼出すものが実行される様にはした。勿論、popen()でプロセスを呼出さない分CPU付加は低く軽快になるので「dpkt」の利用を推奨はする。

 但し、必要なモジュール「dpkt」は、現在dpkt-1.6が最新だが、少なくともPython2.6上では、そのままでは動作しないのでプロジェクトのsvnより「bgp.py」をとって来て置換えている。

 当方の環境では、waitは、popen()の場合には0.8秒程度が適当だったが、dpkt活用では、3秒辺りが最適の様だ。これは、dpktでのpingのweitは相手の応答時にしか効いていない様で、約3秒程の間、5〜6回程度who hasパケットを送り続ける為だ。どうも今回のthread利用ではping処理自体のwaitを実際にかかる秒数付近にした場合に効率的に処理が進む様だ。

 テストソースコードは以下の通り。(青色文字のところがdpktのexaplesにあるping.pyをコピーし、一部書き換えたもの)
/PyPRec/pings.py 〜 Test Code


#!c:/Python26/python
# -*- coding: UTF8 -*-
from datetime import datetime

import math, optparse, random, socket, sys, time
import dpkt

class Ping(object):
def __init__(self):
usage = '%prog [OPTIONS] '
self.op = optparse.OptionParser(usage=usage)
self.op.add_option('-c', dest='count', type='int', default=sys.maxint,
help='Total number of queries to send')
self.op.add_option('-i', dest='wait', type='float', default=1,
help='Specify packet interval timeout in seconds')

def gen_ping(self, opts):
pass
def open_sock(self, opts):
pass
def print_header(self, opts):
pass
def print_reply(self, opts, buf):
pass

def main(self, argv=None):
#if not argv:
# argv = sys.argv[1:]
opts, args = self.op.parse_args(argv)

if not args:
self.op.error('missing host')
elif len(args) > 1:
self.op.error('only one host may be specified')

host = args[0]
opts.ip = socket.gethostbyname(host)
sock = self.open_sock(opts)

sent = rcvd = rtt_max = rtt_sum = rtt_sumsq = 0
bm_tm = datetime.now()
rtt_max = 0.0
#rtt_min = 0xffff
rtt_min = 999999.0
try:
#self.print_header(opts)
for ping in self.gen_ping(opts):
try:
#start = time.time()
st=datetime.now()-bm_tm
start = ((st.days*24)*60)*60+st.seconds+st.microseconds*0.0000001
sock.send(ping)
buf = sock.recv(0xffff)
ct = datetime.now()-bm_tm
rtt = ((ct.days*24)*60)*60+ct.seconds+ct.microseconds*0.0000001 - start
if rtt < rtt_min: rtt_min = rtt
if rtt > rtt_max: rtt_max = rtt
rtt_sum += rtt
rtt_sumsq += rtt * rtt

#self.print_reply(opts, buf, rtt)
rcvd += 1
except socket.timeout:
pass
sent += 1
time.sleep(opts.wait)
except KeyboardInterrupt:
pass
#print '\n--- %s ping statistics ---' % opts.ip
#print '%d packets transmitted, %d packets received, %.1f%% packet loss' % \
# (sent, rcvd, (float(sent - rcvd) / sent) * 100)

rtt_avg = rtt_sum / sent
if rtt_min == 0xffff: rtt_min = 0
#print 'round-trip min/avg/max/std-dev = %.3f/%.3f/%.3f/%.3f ms' % \
# (rtt_min * 1000, rtt_avg * 1000, rtt_max * 1000,
# math.sqrt((rtt_sumsq / sent) - (rtt_avg * rtt_avg)) * 1000)
#print 'return', datetime.now()
return 1 + rcvd - sent #response


class ICMPPing(Ping):
def __init__(self):
Ping.__init__(self)
self.op.add_option('-p', dest='payload', type='string',
default='hello world!',
help='Echo payload string')

def open_sock(self, opts):
sock = socket.socket(socket.AF_INET, socket.SOCK_RAW, 1)

sock.connect((opts.ip, 1))
sock.settimeout(opts.wait)
return sock

def gen_ping(self, opts):
for i in xrange(opts.count):
icmp = dpkt.icmp.ICMP(
type=8, data=dpkt.icmp.ICMP.Echo(id=random.randint(0, 0xffff),
seq=i, data=opts.payload))
yield str(icmp)

def print_header(self, opts):
#print 'PING %s: %d data bytes' % (opts.ip, len(opts.payload))
pass

def print_reply(self, opts, buf, rtt):
ip = dpkt.ip.IP(buf)
if sys.platform == 'darwin':
# XXX - work around raw socket bug on MacOS X
ip.data = ip.icmp = dpkt.icmp.ICMP(buf[20:])
ip.len = len(ip.data)
#print '%d bytes from %s: icmp_seq=%d ip_id=%d ttl=%d time=%.3f ms' % \
# (len(ip.icmp), opts.ip, ip.icmp.echo.seq, ip.id, ip.ttl,
# rtt * 1000)

def ping(ip,wait=0.1,debug=0):
from os import popen
from time import sleep
global PINGs
global PING0
global PING1
try:
argv = ['-i','%f' % (wait),'-c','1', ip]
p= ICMPPing()
nw=datetime.now()
response = p.main(argv=argv)
PINGs.append((ip,response,nw))
if response==1:
PING1.append((ip,1,nw))
elif response==0:
PING0.append((ip,0,nw))
if debug>2: print ip,response,datetime.now()

except:
ppi=popen('ping -n 1 -w 1 %s' % (ip))
lines = ppi.readlines()
for l in lines:
s=l.find('(')
e=l.find('%')
if s>0 and e>0:
loss=int(l[s+1:e])
print ip,int(l[s+1:e])
if loss==100:
i=0
while i<=3:
try:
PINGs.append((ip,0))
PING0.append((ip,0))
i=4
except ProgrammingError,err:
print '\a',err
i=i+1
sleep(0.01*i)
pass
elif loss==0:
i=0
while i<=3:
try:
PINGs.append((ip,1))
PING1.append((ip,1))
i=4
except ProgrammingError,err:
print '\a',err
i=i+1
sleep(0.01*i)


def arp_v_a():
from os import popen,environ
if environ['os'].upper()[:3]=='WIN':
ppi=popen('arp -v -a')
lines = ppi.readlines()
datas=[]
for l in lines:
s = l.strip().split()
if len(s)>=3:
ip=s[0]
mac=s[1]
if len(mac.split('-'))>=6 and not mac=='00-00-00-00-00-00':
print ip,mac
datas.append([ip,mac])
return datas
else:
#ここは、Mireの開発環境外対応を机上で考えた暫定版である
#Windows以外のOSでの処理は利用可能なpythonモジュールに置換えが推奨される。
ppi=popen('arp -v -a')
lines = ppi.readlines()
datas=[]
for l in lines:
s = l.strip().split()
if len(s)>=3:
ip=s[0]
mac=s[2]
if len(mac.split(':'))>=6 and not mac=='00:00:00:00:00:00':
print ip,mac
datas.append([ip,mac])
return datas


def pings(wait,debug=0):
from datetime import datetime
from thread import start_new_thread
from time import sleep
global PINGs
tm_s = datetime.today()
tm=tm_s
PINGs=[]
PING0=[]
PING1=[]
for i in xrange(254):
start_new_thread(ping,('192.168.0.%d' % (i+1),wait,debug,))
#sleep(0.08) # 「Unhandled exception in thread started by」除けお呪い
sleep(0.08) # 「Unhandled exception in thread started by」除けお呪い
tm_p=tm
tm = datetime.now()
if debug>0: print tm-tm_p
tm_e = datetime.now()
sleep(3.0) # 最後に実行したthreadが終了する最大マージン分待つ
while not len(PINGs)==254:
sleep(0.1)
print tm-tm_s
macs = arp_v_a()

return PINGs # grobal変数なのでreturnは不要と言えば不要かも


debug=3
wait=3.2
i=0
while i<5: #5は連続実行テスト回数
PINGs=[]
PING0=[]
PING1=[]
datas = pings(wait=wait,debug=debug)
for d in datas:
print d
i=i+1
arp_v_a()
続きを読む
posted by Mire at 11:31 | Comment(0) | TrackBack(0) | セキュリティ | このブログの読者になる | 更新情報をチェックする

2009年10月04日

NW死活監視用関数「pings()」の制作

 死活監視には、前稿の様なsnmp問合せに失敗したときに本当に死んでいるのかを確認したい時のやり方と、今回紹介するNetworkに接続されている端末を調べたい場合がある。本日はそれがお題だ。
 前稿との差は、予め指定した監視対象端末に対しての問合せであったのに対し、今回は管理するLANネットワーク(サブネット)全体を対象にしていることだ。まあ、大企業や大学の様のLANでない限り、普通はCクラス程度のアドレス空間を上限と考えたとして、デフォゲを含めて頭とお尻の0と255を除いた254個IPを定期的にループチェックする訳だから、その所要時間をどれだけ縮めるとこが出来るかという対応が必要となる。
 もし、全稿の関数をそのまま使うのであれば、それだけで、1.5秒×254個=381秒と6分以上かかってしまうので、thread利用と死活確認をある程度簡便なものにして行くしかない。また、前稿では、thread処理内の処理はprint出力のみであった訳だか、実際のツールでは、これをデータとしてツール本体に返り値として戻してやる必要もある。

 今回は取敢えず、話を簡単にする為に、死活確認は「ping -n 1 -w 1 <IP Address>」の一つだけとし、一つ当たりの実行所要時間を0.5秒に節約して書いて試みた。

 threadから関数を呼んだ場合その返り値を受取ることが出来ない(様にみえる)。Pythonの場合、原則global変数は使わないで書くのが御作法だし、単純に関数内で呼出元にある変数名と同じ名前の変数を使っても思った様に振舞ってくれる訳ではない。そんな場合にはThread Freeなデータ渡しの手法して、データベースへの書出しに期待したくなる。

 今回、試しに sqlite3のメモリ上のDBに期待をかけたが、残念ながらsqlliteは今現在はthreadでconnectやcursorを渡して利用すること自体が出来ない様だった。また、当方にとってDBと言えばFIREBIRDなので、threadに何処迄対応可能かを見て試た。結論は想定通り、出来ないことはないが、例外処理での再処理だけでは解決出来ないことが、OSとサーバの種類(clasic / super)により発生する。今回もVistaとsupers\ serverとの組み合わせでは、kinterbasdb内で使っているcコードで出会い頭の対応不可能な事故も発生した。この辺りはLinuxでもマルチコアCPU利用でも起きたことなので今は諦めて別解を求めた方が賢いというものだろう。で、結局のところ、grobal変数を準備してそれに書き込ませることで解決させた。

 下記のソースコードでは、参考迄FIREBIRD書込み分も行頭に「##」でコメントにして掲載した。尚、今回使ったgrobal変数は、本来返り値としてのローカル変数の代わりに利用する訳なので、利用に当たり初期化させているし、thread内で使われているので、thread呼出ししている関数双方での利用以外はしない様にしなければ正常に機能しなくなる。
#!c:/Python26/python
# -*- coding: UTF8 -*-

##def ping(ip,conn,cur):
def ping(ip):
from os import popen
## from kinterbasdb import ProgrammingError
from time import sleep
global PINGs
ppi=popen('ping -n 1 -w 1 %s' % (ip))
lines = ppi.readlines()
for l in lines:
s=l.find('(')
e=l.find('%')
if s>0 and e>0:
loss=int(l[s+1:e])
print ip,int(l[s+1:e])
if loss==100:
i=0
while i<=3:
try:
## cur.execute("INSERT INTO PINGS (IP,LIVE)VALUES('%s',0);" % (ip))
PINGs.append((ip,0))
i=4
except ProgrammingError,err:
print '\a',err
i=i+1
sleep(0.01*i)
pass
elif loss==0:
i=0
while i<=3:
try:
## cur.execute("INSERT INTO PINGS (IP,LIVE)VALUES('%s',1);" % (ip))
PINGs.append((ip,1))
i=4
except ProgrammingError,err:
print '\a',err
i=i+1
sleep(0.01*i)
##【Firebird2が完全なthread freeではない現実】
##
##
## その1: 多分、カーソルが使用中で書き込めない場合
##
## Unhandled exception in thread started by
## 192.168.0.21Unhandled exception in thread started by
## Traceback (most recent call last):
##
## Traceback (most recent call last):
## File "alive_hosts.py", line 31, in ping
## File "alive_hosts.py", line 31, in ping
## cur.execute("INSERT INTO PINGS (IP,LIVE)VALUES('%s',1);" % (ip))
## kinterbasdb100.ProgrammingError:
## (0L, 'Invalid cursor state. The cursor must be open to perform this operation.')
## cur.execute("INSERT INTO PINGS (IP,LIVE)VALUES('%s',1);" % (ip))
## kinterbasdb.ProgrammingError: (0L,
## 'Invalid cursor state. The cursor must be open to perform this operation.')
## 0:00:00.096000
## 0:00:00.091000
##
##
##その2: 状況は判らないが、コンパイルモジュール側で障害が発生し停止する。次期メジャーバージョン待ち
##
## Assertion failed: ps != NULL, file c:\kinterbasdb\kinterbasdb-3.3.0\_kicore_xsqlda.c, line 147
##
## This application has requested the Runtime to terminate it in an unusual way.
## Please contact the application's support team for more information.
##
##


##def pings(conn=None, cur=None, dsn='', user='SYSDBA', password='masterkey',dialect=3):

def pings():
from datetime import datetime
from thread import start_new_thread
from time import sleep
## from kinterbasdb import connect
global PINGs
tm_s = datetime.today()
tm=tm_s
## if conn is None:
## conn = connect(dsn=dsn,user=user,password=password,dialect=dialect)
## cur = conn.cursor()
## cur.execute('DELETE FROM PINGS;')
PINGs=[]
for i in xrange(254):
## start_new_thread(ping,('192.168.0.%d' % (i+1),conn,cur,))
start_new_thread(ping,('192.168.0.%d' % (i+1),))
sleep(0.08) # 「Unhandled exception in thread started by」除けお呪い
tm_p=tm
tm = datetime.today()
print tm-tm_p
tm_e = datetime.today()
sleep(1.0) # 最後に実行したthreadが終了する最大マージン分待つ
while not len(PINGs)==254:
sleep(0.1)
## conn.commit()
## cur.execute('SELECT IP,LIVE FROM PINGS;')
## datas=cur.fetchall()
## cur.execute('DELETE FROM PINGS;')
## #conn.commit()
print tm-tm_s
## return datas
return PINGs # grobal変数なのでreturnは不要と言えば不要かも

def create_db(dsn='localhost:DUMMY',user='SYSDBA',password='masterkey',page_size=None):
from kinterbasdb import create_database
ds=dsn[len(dsn.split(':')[0]):]
sql="CREATE DATABASE '%s' USER '%s' PASSWORD '%s'" % (ds,user,password)
if not page_size is None:
sql=sql+'PAZE_SIZE %d' % (page_size)
conn=create_database(sql)
conn.commit()
conn.close()

def create_tbl(sql='',dsn='localhost:DUMMY',user='SYSDBA',password='masterkey'):
from kinterbasdb import connect
conn=connect(dsn=dsn,user=user,password=password)
cur=conn.cursor()
cur.execute(sql)
conn.commit()
conn.close()

def exists_db(dsn='', user='SYSDBA', password='masterkey'):
"""
#### 接続して試て、DBの存在を確認 ####
存在したら 1を返し、でなければ、0を返す
"""
from kinterbasdb import connect
try:
conn=connect(dsn=dsn,user=user,password=password)
conn.close()
#print 'EXISTS_DB'
return 1
except:
#print 'NOT EXISTS_DB'
return 0

def exists_tbl(table,conn=None,cur=None,dsn='', user='SYSDBA', password='masterkey'):
"""システムテーブル「RDB$RELATIONS」に接続し作成予定のテーブル名が
既存テーブルとダブってないか調査
"""
from kinterbasdb import connect
sql_exists="""SELECT RDB$RELATION_ID
FROM RDB$RELATIONS
WHERE RDB$RELATION_NAME='%s';""" % (table)
if conn==None:
try:
conn=connect(dsn=dsn,user=user,password=password)
cur=conn.cursor()
cur.execute(sql_exists)
if len(cur.fetchall())==0: # 存在しなかったら
return 0
else:
return 1
except:
return -1
finally:
conn.close() # 接続を閉じる。
else:
try:
cur.execute(sql_exists)
if len(cur.fetchall())==0: # 存在しなかったら
return 0
else:
return 1
except:
return -1
finally:
conn.close() # 接続を閉じる。


def init_db(dsn, user='SYSDBA', password='masterkey',dialect=3):
if not exists_db(dsn=dsn,user=user,password=password):
create_db(dsn=dsn,user=user,password=password)

def init_table(table,sql,conn=None,cur=None,dsn='', user='SYSDBA', password='masterkey',dialect=3):
from kinterbasdb import connect
if not exists_tbl(table,conn=None,cur=None,dsn=dsn,user=user,password=password):
create_tbl(sql=sql,dsn=dsn,user=user,password=password)

#telnet('192.168.0.23',80)
##dsn='localhost:K:\\PyPRec_Alive.fdb'
##user='SYSDBA'
##password='masterkey'
##dialect=3
##init_db(dsn=dsn,user=user,password=password)
##sql='CREATE TABLE PINGS(IP VARCHAR(16), LIVE INTEGER,PRIMARY KEY(IP));'
##init_table(table='PINGS', sql=sql, conn=None, cur=None, dsn=dsn, user=user, password=password)
##print pings(conn=None, cur=None, dsn=dsn, user=user, password=password, dialect=dialect)
i=0
while i<1000:
PINGs=[]
datas = pings()
for d in datas:
print d
i=i+1

 尚、このpings()関数はPyPRecでは、1分間隔での定時実行と全IP端末の記録を行なうことで、プロセス情報取得時の死活判断の補助情報として活用する。また、pings()の最後には「arp -a」を実行し、その捕捉情報も活用予定である。現時点では、残念ながらVISTA上なので、LINUX用のコーディングが出来ないので難しいが、ISC-DHCPD情報の活用や別サーバでの収集情報の相互活用等より精度の高い情報になる様にして行きたいと思っている。
posted by Mire at 05:17 | Comment(0) | TrackBack(0) | セキュリティ | このブログの読者になる | 更新情報をチェックする

2009年10月03日

個別死活監視用関数「alive_host()」の制作

 監視端末に対するsnmp問合せに失敗したときに、その端末自体が、電源OFFや持出されてNetworkに居なくなっているのであれば、問合せはあきらめてその端末を飛ばして監視して行く必要がある。
 その為には監視端末の死活監視を出来るだけスマートに行いたいものである。ここで紹介する関数は残念ながら妥協の産物であり、取敢えずの産物であることを予めお断りしておく。

 仕組みとしては、次の3つをスマートにpythonコードで実行したいところだ。
1. 「arp -d <ip adress>」でarpテーブルから指定IPの情報の削除を試み。
2. 「ping -n 1 -w 1 <ip adress>」で「Who has <ip adress>」のBroadcastをさせ、ipを持ったNW-i/fに口を割らせる。
3. 「arp -a <ip adress>」で最後に該当するIPが、arpテーブルにがあるかどうかをチェックする。

 しかし、当方のWindowsVistaという開発環境は最悪で、arpをpythonで実現可能なAP_PACKETにWindows未対応な為、socketではシステムが(多分)書けない。従って、折角の「arprequest」が使えない。また、ping、icmp通信にも「pyip」があるが、VISTAではセキュリティで拒否されてしまう(2009-10-09誤解されそうなので追記:コマンドプロンプトを「管理者として実行(A)...」で起動しその中で使う限りでは問題なく動作する。ただ、pypiのサンプルping.pyは指定IPがいないとエラーとなる等多少手抜きだったことに加えその時の待ちが長いことを嫌い採用ししなかった。結論として、後述の「NW死活監視用関数「pings()」をpythonモジュール「dpkt」で実現」にある通り当方では「dpkt」を別用途で活用予定。これらは有るだけでも有難いのではあるが、欲を言わせてもらえるならpyipもdpktもドキュメントが殆どないのでサンプルコードを手かがりとして解析し使い始めるしかないのには閉口してしまう。packet通信に疎い当方程度の進歩のない厨房には敷居は高い。)。結局、3つ共、popenでコマンド実行することになった。とても残念な結果書いたテストコードが次のものだ。たかだか3つのコマンド実行ながら、Cクラス256区画のスキャンでは6分以上もかかるので、試しにthread実行させて試た。2分半程度に収まったので効果はある。
#!c:/Python26/python
# -*- coding: UTF8 -*-

def alive_host(ip,retry=3):
"""
 死活監視は端末利用状況の把握と不正接続端末の監視に必要である。
しかし、全アドレス空間のチェックには時間がかかってしまう。
 この関数は、IP個別の死活状態を確認する為のもので、最大1.5秒
かかるので、監視端末を予め絞った管理には使えるが空間全体をなめまわすなら
thread実行が必要だろう。しかし、その場合、CPU使用率と同時起動thread数の制限
等による不具合への配慮を入れる必要がある。
"""
from os import environ, popen
os = environ['os']

#print (os)
# OS別で処理方法を分ける。
if os[:7]=='Windows':
i=0
while i=6 or len(l.split(':'))>=6):
mac=l.strip()[len(ip):].strip()[:17]
print '%s mac=%s' % (ip,mac) # 判定には不要
return [1,mac]
i=i+1
return [0,'']
else:
# UNIX系であれば、arprequestとpyipが使えるので、
# チェックにプロセスを起動させることはない。
# 多分結構軽いものになると思う。
# http://pypi.python.org/pypi?%3Aaction=search&term=icmp&submit=search
from arprequest import ArpRequest



from datetime import datetime
from threading import Thread
from thread import start_new_thread
tm_s=datetime.today()
print tm_s
tm=datetime.today()
for i in xrange(255):
ip='192.168.0.%d' % (i+1)
#alive_host(ip=ip) # 直接関数を実行すると逐次処理の為、
# 監視対象が増えると実用的でない
#Thread(target=alive_host, args=(ip,)).run() # Thread().run()だと、CPUが解放されないので
# threadにした意味がない
start_new_thread(alive_host, (ip,)) # 一番簡易なthread実行方法。但し同時多量起動
# の影響は別途考慮のこと
tm_p=tm
tm=datetime.today()
print tm-tm_p # threadに処理が渡されたら表示されてしまう。

tm_e=datetime.today()
print tm_e,'-',tm_s,'=',tm_e-tm_s # 経過時間

 NWブートが可能なPCでは、NWカードの死活だけではOSの死活迄は判らない。その点注意を要する。
 また、DHCPでダイナミック付与されたIPについては、ISC-DHCPDであれば、IP付与の記録を死活状況判定に役立てることも可能である。続きを読む
posted by Mire at 04:59 | Comment(0) | TrackBack(0) | セキュリティ | このブログの読者になる | 更新情報をチェックする

2009年10月01日

【はまりました】コマンドと同じ名前のソースコード名は鬼門

 PyPRec用のsnmpモジュール作りに励んでいて、監視端末がダウンしたときの処理をどうするかを今考えている(というより、スパッと割り切れずに悩んでいる)ところで、LAN上に居なくなったこと、つまりいわゆる死活監視の関数の必要性を感じそちらを先に上げようと思いARPをPythonで実現しようと思ったが、window用は見つからない。また、当方には、まだ、socketを使った通信ツールを作った経験も、そのプロトコルの認識も薄く敷居が高い。
 そこで、PyPRecから別プロセスを呼ぶのは嫌なのだが、取敢えずの場当たりでwindowsのコマンドを使って代用品を作ろうとした。必要となるコマンド行は次の3つである。
  1. arpで対象IPのMAC情報をテーブルから削除することを試みる
  2. pingを打ってbroadcast呼びかけで、対象IPのMAC情報を登録させる
  3. arp で対象IPの情報にアクセスして存否を確認する

mired_ping_py.png
 いつもの様にPyPRecのフォルダに何気なくこの関数を入れて動作テストをすると動作が遅い。pingのオプション指定が不足していることに気付き補完し再実行するとなかなか情報が帰って来なくなって来た。コマンドに誤りかなと思い直接コマンドの手打ちでも入れるとそれも動かない。見てみるととハードディスクが忙しそうだ。何のことか判らず暫く放置していると益々動きが悪くなってしまった。
 「俺何も悪いことしていないぞ」と思いつつ「タスクマネージャ」でプロセスを見ると笑えない状況、何と起動プロセスが千件超えでどんどん増えている。動きの悪い中、プロセスのコマンドラインを見ると「ping.py」とか言う起動指示した記憶のないプロセスが多数起動していた。忘れていたが、確かにpingという名前で何気なくpingコマンドを含んだテストソースを書いていた様だったので、エクスプローラを必死で開き、PyPRecフォルダ内のping.pyをpinger.pyにRENAMEし、このpingの高速増殖連鎖を断ち切った。これで何とか、少しずつ起動プロセスは減少して行くものの、とてもゆっくりなので、ハンドでもプロセスを殺し、約1時間程度で終息することになった。

 確かにPyPRecの開発に使っているフォルダにはPATHは通していないので、普通にpingとすれなら問題はない。でもPyPRecの開発に使っているフォルダにcdしてしまうとそちらを優先して実行ファイルを探すのは当然のこと。誠にうかつであった。

 結論として、タイトルの通り「コマンドと同じ名前のソースコード名は鬼門」ということだ。皆様もお気を付けあれ。
posted by Mire at 23:46 | Comment(0) | TrackBack(0) | 泥沼 Mired Point! | このブログの読者になる | 更新情報をチェックする

【はまりました】新規作成の窓が画面の外で開く

 PyPRec用の関数を作成しようとしていて、MKEditorを別窓起動しようとしたところ、画面に表れない。良く見るとどうも右の画面の外で窓が開いている様である。新規分が画面上に表れないと何にも出来ない、さあ、どうしたものか。

当方の画面設定では拡張ディスプレィを上に配置。その結果右下に表示されない矩形区画がある。 当方のディスプレィ環境はNotePCの横幅1280の画面の上に同1920の拡張ティスプレイを配置して利用している。その結果、右NotePC画面の右に表示されない矩形区画が発生している。今回は、そこにMKEditorが落込んでしまったのである。これ自体はMKEditorに関係なくあることで、例えば画面解像度を変更したとき等によく遭遇し、珍しいことではない。通常、その様な場合には、画面下のスタートメニューの該当するアプリを右クリックして、その中から「移動」を選択しカーソルキーで移動して対処していた。

 ところが、MKEditorの場合にはこのメニューがないのである。さて困った。Windowsも古いころは、ALTキーの後のカーソルキー操作で窓右上角のアイコンにある「移動」等のメニューの選択が出来たのでこんな場合にも何とかなったが今は出来ない。色々とキーを試したが操作が判らなかった。結局、グーグル君に聞いてみると何とか「ALT+スペース」で出来るとのことであった。操作は次の通りだった。

  1. スタートメニューで、対象のアプリの窓を選択しフォーカスする。フォーカスされているか、最小化されているかは判り辛いが、クリック時の画面の動きを注意深く見ることで窓が開く方向に画像が動きが判るはずだ。それで開いていることとその位置を確認する。
  2. ALT+スペース」を押す。
  3. M」を押す。
  4. マウスで左ボタンを押した状態でカーソルを動かして(ドラック&ドロップ)操作可能な位置に持って行く。(あるいは、NotePCの様にマウスがない時にはカーソルキーを押しても移動可能です。)


 恐らくこの「ALT+スペース」の操作が次に必要になるときには、また忘れているんだろう。これはその時の為の備忘録だ。同じ様にはまった方もどうぞご利用下さい^^;;
posted by Mire at 22:29 | Comment(0) | TrackBack(0) | 泥沼 Mired Point! | このブログの読者になる | 更新情報をチェックする
月額見放題1,000円開始キャンペーンバナー(画像ありver)
紺碧の艦隊 ルパン三世 GREAT CHASE クリックプロモーション
<< 2009年10月 >>
        1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
カテゴリ
タグクラウド
ファン
利用中のオープンソース
最近のコメント
最近の記事
過去ログ
QRコード
レガシーなアプリはいかが?
Dell 法人のお客様ページ
  • 【法人様向け】デル、お得なキャンペーン情報
  • 法人のお客様向け ストレージソリューション
  • 法人のお客様向け ネットワークソリューション
  • 【SOHO法人様向け】デル・オンライン広告限定ページ
  • デル-個人のお客様ページ
  • 【個人のお客様向け】デル・オンライン広告限定ページ
  • オンライン広告限定キャンペーンページ
  • ソフトウェア&周辺機器 パソコン工房
    ツートップインターネットショップ(twotop.co.jp) マウスコンピューター/G-Tune