Windows 8 Developer Preview

Windows8 Desktop
Windows8 Desktop

Windows8 Start menu
Windows8 Start menu

Windows8 Internet Explorer
Windows8 Internet Explorer

Windows8 Explorer
Windows8 Explorer

あふw on Windows8
あふw on Windows8

Windows8 を Windows 7 Prof. x64 上にゲストOSとして入れてみた.
Windows Virtual PC にはうまく入れられなかったので,VirtualBox へ入れた.
環境はこんな感じ.

ホストOS Windows 7 Prof. SP1
ハード AMD x64 アーキテクチャ
VM VirtualBox 4.0.12
インストール時の設定等
VBox の OS 選択 Windows 7 (x64)
RAM 1024MB
グラフィックカードの設定 RAMは30MB 2D/3Dアクセラレーション ON

これで動いた.

その他,メモ.

  • Windows 8 のインストールには,Windows Live ID を準備させられた.アカウントは Live ID と連携する.Androidをインストールするのに似ている気がする.
  • Windows 8 搭載のブラウザは, IE 10.
  • Windows 8 のエクスプローラでは,Office 2007 以降に採用されたリボンが使われていた.
  • 愛用の あふw (afxw) は動いた.
  • Firefox は,2011/9/23 現在ではインストールできない.OSが未対応とエラーが出る.バイナリ入れたら動きそうな気もするが,試してましぇん.
  • Winキー+○ のショートカットは健在. Win+Rshutdown /s /t 1 でシャットダウン

CPU 稼動率 in Win7

リソースモニタ
リソースモニタ

AMD のプロセッサを使っており,CPU ダウンクロックの状況を見たかったので,公式ソフトの AMD Power Monitor を探したのだが,どうも公式サイトから消えているらしい.
なぜだろうと考えてみると… Cool'n'Quiet ドライバが Vista 以降の OS 向けに出ていないのと同じ理由ではないか…,つまり OS が標準で類似の機能を搭載しているんじゃないかと考え,
タスクマネージャのパフォーマンスタブを開いてみると,「リソースモニター」とかいうそれっぽいボタンがあった.
当たりでした.

プロセスのトコにある「最大周波数」が,100%の状態で CPU がフル稼動らしい.
ためしに, Pixia で 5000x5000 のキャンパスを開いてお絵描きしてみたら,あっという間に 100% になってしまった.
CPU 使用率が 50% ちょいで止まっていたのは, Dual core だからだろう.

なお,起動オプションを調べてみたら,これで動くらしい.
C:\Windows\System32\prefmon.exe /res
または
C:\Windows\SysWOW64\prefmon.exe /res

もっと省エネを本当に考えるなら,core 毎にクロックダウンできた方がよさそうだ.
って,別チップやん,それじゃぁ.

spammer counter

アクセス禁止したスパマーが,その後どれだけアクセスしているかカウントする.

以前,スパム増加という記事でも触れたが,
本サイトではアクセス禁止リストにあるホストからのアクセスを禁止している.
ところが,似たようなIPからのアクセスが絶えず続いており,どんどんホストを追加している状態である.
このままではアクセス禁止リストが延々と伸びていってしまうので,特にアクセスの多いアドレス空間については,
適当なサブネットマスクでもってアク禁とすることにしたい.

ところが,一度アクセスを禁止してしまうと,その後はどの程度のアクセスがあるのか分からない.
アク禁リストのアップデートをするための情報として,アク禁を解除しないまま,アクセス数を把握する方法を考えた.

ずばり,403 エラードキュメントをphpにして,アクセス元をカウントアップする作戦である.
そして普通に誤った操作をした人に疑問を与えないよう,403を忠実に再現したい.
ということで,こんなコードを生成してみた.

<?php
header("HTTP/1.1 403 Forbidden");
header("Content-Type: text/html; charset=iso-8859-1");
?>
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<HTML><HEAD>
<TITLE>403 Forbidden</TITLE>
</HEAD><BODY>
<H1>Forbidden</H1>
<?php printf("You don't have permission to access %s\non this server.",
             htmlentities(strip_tags($_SERVER['REQUEST_URI']))); ?><P>
<HR>
<ADDRESS><?php
$e = explode(' ',$_SERVER['SERVER_SOFTWARE']);
printf("%s Server at %s Port %d",$e[0],$_ENV['SERVER_NAME'],$_ENV['SERVER_PORT']);
?></ADDRESS>
</BODY></HTML>
<?php
// count IP addr
$addr = $_SERVER['REMOTE_ADDR'];
$fobj = fopen("counter.dat","r");
if (flock($fobj, LOCK_EX)) {
    $oobj = fopen("counter.tmp","w");
    $flag=false;
    for(;!feof($fobj);)
    {
        if ($flag) { fwrite($oobj,fgets($fobj));}
        else {
            $s=fgetcsv($fobj);
            if (count($s)<2) { break;}
            if ($s[0] === $addr) {
                $s[1]=(int)$s[1]+1;
                $flag=true;
            }
            fputcsv($oobj,$s);
        }
    }
    if (!$flag) { fprintf($oobj,"%s,1\n",$addr);}
    fclose($fobj);
    fclose($oobj);
    copy("counter.tmp","counter.dat");
} else {
    fclose($fobj);
}
?>

ファイルロックなんて,何年か振りに実装した.
普通に php のオンラインドキュメントにあるようなファイルロックにしていないのは,
各行毎に読み込み/書き込みをしたかったから.
読み込み用ファイルを排他ロックして,読み込めた人だけ処理が進むようにしてみた.
そんな処理が問題になるほど膨大なログが溜まる頃には,レンタルサーバのスペースを
食い潰してアカウント消されていそうだけどね…

んで,アク禁で ErrorDocument 403 へ飛ばす場合の注意.
403 で飛ばす先の php ファイルへのアクセスは可能とすること.
さもなくば, 403 の転送で無限ループが発生する.

<Files hogehoge.php>
allow from all
</Files>

とかでOK.

余談だが, ErrorDocument で http://~~ と URI 指定すると,
別サーバへの転送と同様に処理されてしまうらしく,呼び出し元が引けなくなるので注意.

AutoFollowersBlocker

GAE 上で動作し, cron で呼び出されて, twitter アカウントの follower を監視し,
プロファイルの文字列によって自動ブロッキングをするスクリプトを作成した.
きっかけは,昔むかし,山のように spammer からフォローされまくって,鬱陶しかったため.
当時の記事はこちら → twitterのspammerのfollowが多い

で,作ってみたのが, twitter を OAuth 認証でアクセスするためのクラス twit_oauth.py
そして,呼び出し元の AFBsample.py
いずれも分量が多いので,ソース自体はリンク先を参照されたい.

また,GAEで使うためのyamlファイルもついでに貼り付けしておく.

application: afb-sample
version: 10
runtime: python
api_version: 1

handlers:
# handling mode
- url: /cron
  script: AFBsample.py
  login: admin
# viewer mode
- url: /.*
  script: AFBsample.py
cron:
- description: polling job
  url: /cron
  schedule: every 5 minutes

さてこれで,次の4つを GAE へ放り込めば動く.
GAE の使い方については,web を参照されたいが,以前に hadacchi が調べたメモもある → twitterのspammerのfollowが多い
これでも,多少は参考になるかも知れない.

  • AFBsample.py
  • twit_oauth.py
  • app.yaml
  • cron.yaml

さて,今回のハマりポイントは,呼出 URL による処理の振り分けだった.

handlers:
# handling mode
- url: /cron
  script: AFBsample.py
  login: admin
# viewer mode
- url: /.*
  script: AFBsample.py
application = webapp.WSGIApplication([
    ('/cron', AutoFollowerBlocker),
    ('/', AFBview)
    ])

def main():
    wsgiref.handlers.CGIHandler().run(application)

当初は app.yaml の url 行を修正すれば呼び出し URL に応じて処理を振り分けできると思っていたが,
呼び出される側の python スクリプト内の webapp.WSGIApplication() の意味に気付いていなかった.
こいつの引数は,長さ 2 のタプルのリストであるが,タプルの第 1 要素は呼び出しURLになっていて,
ここでも呼び出し URL に応じて処理クラスを振り分けできる.
きちんと GAE の処理を読んでいないが,多分 app.yaml による振り分けは login 行におけるパーミッション制御や,
スクリプトファイルを分けることにより,クロスサイトスクリプティングみたいなアタックに対してある程度の
対処をしたい場合などに使うのが良いのかも知れない.

今回の構成では,
http://pjname.appspot.com/ へのアクセスで前回の実行結果を表示し,
http://pjname.appspot.com/cron へのアクセスでフィルタを手動実行する.

他の工夫としては,運用面で使い易くするため,自動 BLOCK 後に手動で UNBLOCK したユーザは対象から除外するようにしたり,
AND/OR 検索で重複マッチを走らせないようにしたり,
空フィールドに対して None が返却されるので事前に置換しておいたり,(デバッグの時にはjsonファイルを直接食わせる関係から,
マッチ関数内にもNoneの処理は残しているが…)
といった小細工は少ししてみた.

今後の課題としては,プロファイルを 1 call で 100 id 分まで抜ける API を見落としていたことが
分かったので,この API へ対応させた上で, follower が 10000 を越えるユーザでも TwitterAPI の
呼出制限にかからないよう初期化する実装を行なうことがある.
と難しく言ってみたものの,既チェック ID をパスするロジックなので, API の回数制限にかかる手前で
ループを break させてしまえば良いだけである.

参考にした web site は, Python アプリケーション設定 - Google App Engine - Google Code などの GAE のオンラインドキュメントと,
REST API Resources | Twitter Developers などの Twitter のオンラインドキュメントに加え,
前回までの記事 twitterでspammerのfollowを自動block 及び twitterのspammerのfollowが多い 内で参照している各ページである.

twitterでspammerのfollowを自動block

-- 追記2
ごめん,バグあった.文字列操作まわりのencodingがかなり怪しい.
空の時,Noneが入ってくるのは空文字列に置き換えるべきか.

-- 追記
きっと誰も AND/OR 検索を実装してくれないので,実装した.
ついでに, twit_oauth.py を更新して,フォロワだけでなくフォローしてる人の一覧も取れるようにした.

先の記事twitterのspammerのfollowが多いでも書いた,spammerのキーワード抽出について.
GMail からの PUSH 通知をトリガとした動作がうまく実装できなかったので (なぜか python2.5.xでは,imaplib2 がうまく動かない)
とりあえずトリガーは何も考えてません.cron でも,IMAP/IDLE でも,好きに実装してください.

twitter を変なライブラリなしで OAuth 認証で動かすクラスは,こんな感じで実装してます → twit_oauth.py
で,こいつを使って,下記のように使うとスパムフィルタのできあがり.

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import simplejson,re
from twit_oauth import twit_oauth

__KEYWORDS = [(re.compile(u'キーワード1'),),
              (re.compile(u'キーワード2-1'),re.compile(u'キーワード2-2'))
             ]

# プロファイルリスト取得関数
def getProfiles(followers,pobj):
    profiles = {}
    for f_id in followers:
        profs=simplejson.loads(pobj.callAPI('profile',`f_id`))
        if profs['name']==None: name=''
        else: name=''.join(profs['name'].split('\n'))
        if profs['description']==None: desc=''
        else: desc=''.join(profs['description'].split('\n'))
        profiles[`f_id`]=(name,desc)
    return profiles

# テキストマッチ関数
def filterByKeys(profiles):
    fil_list = []
    for (id,prof) in profiles.items():
        # __KEYWORDS のいずれかの要素1つでも合致すればブロック (OR)
        for keys in __KEYWORDS:
            fil_list.append(id)
            # __KEYWORDS の1要素の中の,全てのマッチが成功すればブロック (AND)
            for k in keys:
                if not k.search(prof):
                    del fil_list[-1]
                    break
            # 重複登録回避
            if len(fil_list) != 0 and fil_list[-1] == id: break
    return fil_list


pobj= twit_oauth('xxxxxxxxxxxxxxxxxx','xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
                 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx','xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx')


# 自分の username を入れて,フォロワーを取得
followers = simplejson.loads(pobj.callAPI('getfollowers','username'))
# フォロワーのプロファイルを取得
profiles  = getProfiles(followers,pobj)
# キーワードマッチでフィルタ対象を取得
fil_list  = filterByKeys(profiles)
# ブロック
for fid in fil_list:
    print pobj.callAPI('block',fid)
# report_spam 自動処理で報告してしまうので,非推奨
# for fid in fil_list:
#    print pobj.callAPI('report_spam',fid)

report_spam を呼んでないのは,巻き添えレポートを防ぐため.
キーワードに絶対の自信があれば,使ってください.
and検索,or検索したい場合は,k.search(prof) の所を工夫してください.
実装済.

twitterのspammerのfollowが多い

級にspammerが来始めたので,なんか炎上してた人をフォローしたせいか,大手画像サイトとかをフォローしたせいだろうなぁ.
で,私のfollowerリストから更に他の人に飛び火すると悪いので(もう遅いかも知れんが…),一旦非公開アカウントにしました.
spammerの自己紹介や行動には,一目見て分かるほど特徴が沢山あるので,非公開にしているうちに,自動blockするスクリプトを作ることにした.
これまでの経験上,誰かが私をfollowするのは,頻度が高くても1人/週程度なので,1週間を目処に解決を目指そう.

前提

  • 今借りているレンタルサバ上でwebに溢れているサンプルコードを動かそうとすると,モジュールが足りない
  • pythonのモジュールは,同じディレクトリに置けば動かんこともないが,twitter関係の操作に必要なモジュールを1から入れようとすると,依存関係のため入れるべきモジュールが多い上,それぞれのimport文に対応するよう配置しないといけないので大変すぎる.
  • 自宅PCは最近は1~2回/週しか立ち上げないので,それではspammerのやりたい放題

つーことで,新たな常時起動しているサバを用意するか,コードをある程度自作する必要があることが分かった.
とか思考を全部書いていくと時間が足りないので結論だけ書く.
Google AppEngineでpythonコードを動かすか,標準モジュールだけでpythonコードを動かすかの両睨みができる方法を取ることにする.
具体的には,標準モジュールだけでTwitter APIを操作できるようにしながらも,GAEの開発環境は用意し呼出し部は2パターン作った.

で,cronを使うよりも,twitterでfollowされる度に飛んでくる通知メールをGMailで受け取って,それをトリガーに動作させてみたいと思い,GAEに挑戦することにした.
追記: GAEだもの,GMail くらい直接触れるでしょ,なんて思い込みがあったが,触れないことが分かった.オーノー

GAEについて

pythonしか試していないのでpythonのことを書く.
Google AppEngine より,登録してSDKを落とす.
Windows版はmsiファイル,Linux版はただのzipファイル.
Win版は,C:\Program Files (x86)\Google\google_appengineへインストールされる.Linux版は,unzipして展開するだけ.
python2.5.x でないと動かない.

$ python (PATH)dev_appserver.py demos/guestbook

と実行すれば,サンプルが動作する.

guestbookと同じように,app.yamlとそこから呼び出されるpyファイルを配置すればOK.
制限をかけたい場合は,app.yamlの制限したいscriptを定義しているscript行の下あたりに,login: required (Googleアカウントでログインしてないとダメ) とか, login: admin (GAEの該当プロジェクトの管理者権限がないとダメ) とか書く.
GAEへアップロードするには,

$ python appcfg.py update project_name

とかする.
アクセス先は GAE の dashboard の application settings にあるが,http://application_name.appspot.com とかだと思う.
サンプルみたいに wsgiref.handlers.CGIHandler().run(application) で呼び出してもいいが,デバッグしたい時は,from google.appengine.ext.webapp import utilとインポートしておいて,util.run_wsgi_app(application)とすると,ブラウザ上にデバッグメッセージが表示される.
どうせ開発環境では,dev_appserver.pyを呼び出している窓にも同じメッセージが表示されるけど.
詳しくは,ユーティリティ関数 - Google App Engine - Google Codeとかを参照のこと.
あと,simplejsonとか,ちょっと欲しいモジュールは入っていたりするけど,oauthtwitterとかニッチなのはない.
外部ファイルからクラスをインポートしたい時は,同じフォルダにpyファイルを置いてimportすれば,開発環境では動く.GAE上では試してないので不明.

twitterAPIについて

仕様がよく変わるので,公式の最新のもの(英語)Documentation | Twitter Developersの REST API を見た方が早い.
BASIC認証はもう使えないらしいので,OAuth認証を使う覚悟をする.
情報取得系はGETで叩き,情報更新系はPOSTで叩くRESTful I/F.
応答はJSONかXML.
アクセストークンの発行が死ぬほど面倒くさいので,頑張る.私は,やる夫と Python で学ぶ Twitter の OAuth - YoshioriのBlogを参考にした.
どうせReadもWriteもやりたくなるので,Read/Writeは少なくともつけておく.
QUERYをトークンをキーに符号化したものを署名としてHTTPヘッダへ埋め込み,肝心のQUERYは上記の通りGETかPOSTで投げるので,二重に必要なことを忘れない.

で,上に記載のやる夫と Python で学ぶ Twitter の OAuth - YoshioriのBlogのソースコードを改変して作ったのがこんなクラス → py_twit.py 更新しました → twit_oauth.py
無駄に書いてるimportとかはそのうち消します.
なお,screen_nameをuser_idとする場合,idは文字列で渡すこと.
また,statuses/updateは同じ発言を2回書くと403を返す,など応答については各々調べること.

あんま関係ないが,pythonのこと調べてると,大学時代の同級生がたいてい出てくるので,よくビビる.
今回の案件では,コードの美しさというよく分からん評価軸について語っていたので,反映しなかった.

VirtualBoxへUbuntu11.04

VirtualBoxも,Ubuntuも,かつて使っていたソフトなりOSであるが,すっかり使い方を忘れてしまった.
ハマったポイントを改めて書いておく.

  • Ubuntu serverを入れる場合,日本語を選択すると後で言語設定をやりなおすハメになるので,Englishを選んでおく方が無難.
    X入れる場合は気にしなくていいけど.
  • インストールが終わったら,まずはGuest Additionsをインストールすること.
    具体的な手順は,

    1. ゲストOS起動
    2. デバイス>Guest Additionsをインストール
    3. sudo mount /dev/cdrom /mnt
    4. sudo /mnt/VBoxLinuxAdditions.run
  • ネットワークアダプタの設定を,「ブリッジアダプタ」または「ホストオンリーアダプタ」あたりにして,ホストとの直接通信が可能なようにする.
    しなくてもwwwには接続できるけど,不便で仕方がない.
  • sshd_configで,passwordloginをyesにしておく

これだけやっておけば,普通にLAN上に新しいUbuntuサーバを立てたのと同じところからスタートできるはず.

Yahoo Messenger のメッセージウィンドウにメッセージが表示されない

-- 追記
やっぱし直らなかったので,Yahoo Messenger 9.5 を入れたら直った.
9.5はこちら→ Windows版メッセンジャー ヘルプ - お試し版Yahoo!メッセンジャー バージョン9.5について

--

最近,メッセージウィンドウに表示されるはずの文字が再描画されず,発言があったことを示す窓の点滅と音がすれど,窓は真っ白なままという現象があった.
窓サイズを変更すると,描画コマンドが走るためか,その時点で発言されている文字が表示される.

で,見付けた解決方法はこれ.
Windows版メッセンジャー ヘルプ - メッセージが表示されない

どうやら,IE9にした際に設定が変更されたらしい.

Outlook 2007 で重複メールを削除する

vectorで更改されている重複メール削除アドインでは、受信トレイとは別の重複メールを削除できない。
私の環境のように、会社メールがMicrosoft Exchangeで運用されていて、容量の制約があるために受信トレイに多くのメールを残しておけないため、ほとんどのメールを仕分けしてローカルフォルダに移動している場合、このアドインはほとんど役立たない。

で、役立つのがこのサイト (Outlookの重複メールの削除 - ひぐらし) にある方法。
ODIRは重い、と記載されているが、ツールバーから実行しなければ動かない気がするので、重いとは感じない…ので、入れたままにしている。

マイドキュメントとかをD:に移動する

  1. `username' という表記を,自分が使っているPCのユーザ名と置き換えて読むこと.
  2. 移動後,フォルダのセキュリティ (パーミッション) を再設定する必要がある.
    具体的には,一番上位のフォルダを右クリック→プロパティ→セキュリティ→詳細設定→アクセス許可の変更→追加→`username' を入力しEnter→フルコントロールにチェックを入れ,Enter (「これらの~にのみ適用する」はチェックしないこと)→Yesを2回選択

マイドキュメントの場合.
C:\Users\`username'\Documents を右クリック→プロパティ
場所,という名前のタブがあるはずなので,選択すると,フォルダパスを入力するボックスがあり,上記のC:から始まる文字列が入っているはず.
この部分を移動先のフォルダパスに書き換えて,適用ボタンを押せば良い.
あとは,ダイアログに従って選択すればOK

上記で簡単にできてしまうことが分かったので,もはや意味はないが,Windows 7でハードリンク,シンボリックリンク,ジャンクションを扱うための知識も調べたのでちょろっとメモ.

シンボリックリンクとジャンクションは,MKLINKコマンドを実行すれば,ヘルプが出る.
なぜか,hadacchiの環境では別ドライブのフォルダとの間にシンボリックリンクが貼れなかったため,ジャンクションで対応した.
ジャンクションは,フォルダにしか適用できない劣化シンボリックリンク,ということらしい… (参考:Windowsにおけるシンボリックリンクとジャンクション、そしてハードリンクを理解する « neetu )

ハードリンクは,同ドライブ内にしか適用できないらしく,hadacchiの目的に合致してなかったので,試してもいない.
fsutilを使うとできるらしいということだけ分かった.