はてなキーワード: dirとは
Re: 〇〇日で月間アクセス〇〇万PVを達成した方法の真実なんて1つしかない - http://anond.hatelabo.jp/20110830144753
------------------------------------------------------------------------------------------------------------------------------------------------
2ちゃんねるブログ板でも相互ブックマーク(管理人同士でお互いのブログをはてブしあう行為)が頻繁に話題になっている。
34 : Trackback(774) : 2011/08/27(土) 16:48:06.92 ID:qR88936B [3回発言]
36 : Trackback(774) : 2011/08/27(土) 17:00:29.83 ID:SVBG7kK5 [6回発言]
はてぶ自演しててもいいとおもうけどねー俺は
零細はそれくらいしてでも這い上がってきてもらわないと
だってお前らそういうことしないと上がってこれねーじゃん
54 : Trackback(774) : 2011/08/27(土) 18:23:16.53 ID:HB0ltaAL [4回発言]
ただ、自演したところでお前ら管理人だけ気にしてるだけでブログを見に来てる一般層は何一つ気にしてないってことだけは確かだからな。
もしそれをチャンスと思えないならそれでいい。綺麗事言って大手になろうとしてるのなら頑張ってくれとしかいえないな
713 : Trackback(774) : 2011/08/02(火) 22:19:42.17 ID:ga/wsK7A [3回発言]
面白いの見つけた
はてブ自動投稿プログラム、Twitter自動フォロープログラムっぽい。
ttp://tool.matomeja.jp/twitter/account_list.txt
これがフォローすると高確率でフォロー返ししてくるTwitterIDリストか?
ttp://tool.matomeja.jp/hatima/rt_ranking.txt
はちまのRT数ランキングを生成するPHPも.txtファイルで置いてあった。
アップロードしたファイルのURLがttp://2-br.jp/になってたから、
ツーブラってまとめツールの作成者=yoshihiraか?
こんなツールまで出回っている始末。
yoshihiraというのは、
などの2chコピペブログのページ末尾から「Customize by yoshihira」などとリンクされているコピペブログ専門のWebデザイナーということになってる人物。
ちなみに、はちま起稿のページ末尾には
と書かれているが、Convoyの管理するドメインにyoshihiraの管理するサイトのデータが置いてあったとかで、yoshihiraとConvoyとVIPPER速報管理人は同一人物である可能性が高いとされてる。
708 : Trackback(774) : 2011/08/02(火) 18:48:24.11 ID:ga/wsK7A [3回発言]
こんなのがあった
[DIR] Parent Directory 31-May-2011 06:07 -
[DIR] 0taku.livedoor.biz/ 10-May-2011 16:20 -
[DIR] check/ 17-May-2011 03:42 -
[DIR] contact/ 23-Jul-2011 08:49 -
[DIR] hatima/ 21-Jul-2011 04:29 -
709 : Trackback(774) : 2011/08/02(火) 19:25:28.17 ID:JCIXDAoN [1回発言]
>>708
710 : Trackback(774) : 2011/08/02(火) 19:39:51.68 ID:7ZKWJsg+ [2回発言]
>>709
このサイト自体にあまり意味はないが各種サイトの物置の様なものがあった
はちま起稿の各種アイコン、
contactにyoshihira氏のサイトのリンクがあったことから
matomeja=yoshihira氏と考えられる
yoshihira氏=convey氏という可能性も有る
711 : Trackback(774) : 2011/08/02(火) 21:49:06.25 ID:ga/wsK7A [3回発言]
>>709
yoshihira=matomeja=vipzip2ch=convoy=vipper速報と思われるファイル一式が置いてあった
ちなみにこのVIPPER速報というのは、今日もやられやく乗っ取り騒動や永上裕之のハムスター速報管理人騙り騒動でも永上裕之側の人間として話題にのぼってる。
53 : Trackback(774) : 2011/08/27(土) 17:53:42.38 ID:dcCYiZQL [2回発言]
>>51
ベア速とかその周囲とか
あじゃじゃしたの最初にはてブつきだした頃の最初の3つのユーザー見てみろ
非表示が多いから
59 : Trackback(774) : 2011/08/27(土) 18:30:33.20 ID:zLprTqEW [5回発言]
>>53
はちま
VIPPER速報
妹はVIPPER
2のまとめR
まめ速
ねたAtoZ
はてブを非公開ユーザーに設定しておくと、ブックマークしているサイトに不自然な偏りがあったり、Twitter経由でのはてブ投稿でクライアントがdlvr,itやtwitterfeedといったRSSをTwitterに流すものだったりといったところから足がつく危険性がなくなるが、ブックマーク数の統計にきっちりと加算される。スパマーにとっては美味しい仕様となっている。
非公開ユーザーをブックマーク数から除外したり、dlvr.itやtwitterfeedからのTwitter経由での投稿をブックマーク数から除外するだけで、結構な量のスパムが消滅するはずなのだが…。
面白いことに、非公開ユーザーはブックマーク数の統計に加算されるだけでなく、「コメントのないブックマークもすべて見る」から見れるブックマーク数の推移の線グラフの統計にも加算されている。
非公開ユーザーを用いて3userないし5userまでブックマーク数捏造がなされている場合、ブックマーク数の推移の線グラフの左端が0userではなく3user~5userの高さで始まる(3user~5userの高さまで垂直に上がってから右に曲がる)ことになる。
ちなみに上に挙げたブログより圧倒的にアクセス数が多いであろう痛いニュースやアルファルファモザイクのグラフを見ても、非公開ユーザーによる捏造と思われるブックマーク数の急上昇は見られなかった。というより、3user~5userに達するまでは緩やかで、達してから急上昇するパターンのほうが多かった。上に挙げたブログは最初だけ勢いがよく、それから50~100userに達するまでは緩やかなグラフになっているという場合が多い。
A Beautiful Site (http://abeautifulsite.net/)さんの
jquery.fileTreeを利用させてもらった。
以下、留意点...
パスを指定しないと、もとのhtmlがあるパス(ディレクトリ)にあるものと解釈する。
(/jqueryFileTree.php と指定すると、公開しているルートディレクトリにあるjqueryFileTree.phpを探しにいく)
http://...と指定して他のサーバへ問い合わせるのも可能な模様(だが、試していない)。
root:
d:/
d:/temp/
など
hemlentries -> htmlspecialchars は必須。
http://treatment-head.blogspot.com/2008/11/jquery-file-tree_21.html
ただし、UTF-8やEUC-JPでページを記述している場合は、さらに処理が必要。
windowsでは、mbstringの設定にかかわらず、引数SJIS渡し、戻り値SJIS返しの模様。
したがってUTF-8やEUC-JPでページを記述している場合は、
その点を考慮してconnectorsフォルダにあるjqueryFileTree.phpを書き換える必要がある。
$_POST['dir'] = urldecode($_POST['dir']);
という行があるが(スーパーグローバル変数はデコード済みで、さらにデコードするのは危険とphpマニュアルに記載されている)
どのみちUnicode文字列のURLデコードはこの関数では無理なようなので、phpマニュアルのUserNoteから拝借。
http://php.net/manual/en/function.urldecode.php
こちらにズバリが掲載されているか...と試してみたが、どうも動作がうまくいかなかった
http://ameblo.jp/pushurinko/entry-10287161493.html
他、ご参考
A disk read error occurred
Press Ctrl+Alt+Del to restart
帰省中1ヶ月ほど放置し、久しぶりに電源を押すとエラーが出るようになったらしい。
変なソフトのインストールやBIOSのアップデート等はしていないとのこと。
当初はF8キーを押して[詳細ブートオプション]を開ければ、すぐに直せると思っていたけど、
ブートから進まないのだからF8キーを押しても同じエラーが出るだけ。
一応、F2キーでBIOS設定画面を開き、[Load Setup Defaults]を試すも症状変わらず。
また、VISTAにはXPの[回復コンソール]がなく、[システム回復オプション]という復旧手段が用意されている。
しかし、このマシンはプリインストール版なので、ディスクからの起動できない。
この場合はF8キーを押して[詳細ブートオプション]を開いて、そこから起動できるようだ。
その後、試行錯誤を繰り返した結果、再セットアップするしかないという結論に至った。
バックアップするにもWindowsが起動しないので、こんな時はいつもLinuxOS Knoppixに頼っている。
公式サイト(http://www.rcis.aist.go.jp/project/knoppix/)ではDVD版とCD版がiso形式で配布されており、DVDなりCDなりに焼けばOSをディスク起動できる優れもの。
さらにCD版をUSBにインストールしたUSB版も作成できるので、非常用に1つ作っておくと便利。
こちらのサイト(USB-Knoppixではじめよう http://yumenohako.jp/cgi-bin/knoppix/wiki.cgi)を参考に簡単に解説。
- 用意するもの
- 作成手順
- 前述したKNOPPIXの公式サイトからCD版のISO形式ファイルをダウンロード(現在はバージョン6.0.1)。
- 「DAEMON Tools」等の仮想ディスク作成ソフトでisoファイルをマウント。
- マウントしたディスクを開き、[KNOPPIX]フォルダを丸ごとUSB直下にコピー。
- さらに「\boot\isolinux」フォルダを開き、中のファイルを全てUSB直下にコピー。
- USB直下にコピーした[isolinux.cfg]というファイルの名前を[syslinux.cfg]に変更。
- こちらのサイト(http://www.kernel.org/pub/linux/utils/boot/syslinux/)から[syslinux.zip]をダウンロード(現在はsyslinux-4.02.zipが最新)。
- zipファイルを解凍して開き、「\win32\syslinux.exe」ファイルをCドライブ直下に移動。
- コマンドプロンプトを開き、[cd c:\]([]内のみ)と入力してEnterキーを押す。
- 次に[dir syslinux.exe]と入力してEnterキーを押す。
- さらに[syslinux.exe -ma USBドライブ名:](例:USBがEドライブなら[syslinux -ma E:]、間違ったドライブを指定すると指定先が壊れるので注意)と入力してEnterキーを押す。
- 完成!
- 使用方法
このマシンは前述の通りプリインストール版なのでインストールディスク(再セットアップディスク)が付属していない。
では、どうやって再セットアップするかというと、
しかし、今回はF11キーを押してもエラーが表示されるのみ。それにわざわざリカバリディスクを作成しているはずもなく手詰まり。
リカバリディスクはこちら(http://nx-media.ssnet.co.jp/)から購入できるけど価格は1万円。自作するしかない。
そもそも本来はリカバリディスクを作成できるのだから、HDD内のどこかにリカバリディスク用のデータが入っているはず。
そこで再びKNOPPIXを起動してみると、[NEC-RESTORE]という名前のリカバリ領域が隠しパーティションとして用意されていた。
こちらのサイト(LaVieレストア顛末記 http://deme.jp/wing/vol019/demeshin/NEC.htm)が大変参考になった。感謝。
- 用意するもの
- 作成手順
- 対象PCに接続されているUSBやLANケーブルなどはマウスとKNOPPIX以外全て外す。
- KNOPPIXで起動し、前述バックアップと同じ方法で[NEC-RESTORE]ドライブを開き、[RESTORE]フォルダを丸ごと外付けHDDにコピー(約10.3GB)。他のは不要。
- 「\RESTORE\TOOLS\IMG\winpe.iso」ファイルをISOイメージでCDに書き込む(Disk1)。
- 「\RESTORE\TOOLS」フォルダを丸ごとCDに書き込む(Disk2)。
- 「\RESTORE\BKVSTIMG.GHO」ファイルをCDに書き込む(Disk3)。
- 「\RESTORE\BKVST0**.GHS」ファイルが001から018まで18個あるので、まずは「BKVST001.GHS」から「BKVST007.GHS」まで約3.75GBをDVDに書き込む(Disk4)。
- 「BKVST008.GHS」から「BKVST014.GHS」まで約3.75GBをDVDに書き込む(Disk5)。
- 「BKVST015.GHS」から「BKVST018.GHS」まで約1.93GBをDVDに書き込む(Disk6)。
- 完成!
- 使用方法
- 対象PCの電源をつけ、Disk1を挿入。そして、電源ボタンを長押しして強制終了。
- 再度、電源をつけ、すぐにF2キーを連打してBIOS設定画面を開き、[Boot]タブから[1st Boot Device]を[CD-ROM]に変更して設定を保存。
- しばらくすると[Window Vista 再セットアップ]が起動するので、[再セットアップ]を選択(他のものを選択しても途中でエラーが出た)。
- その後[Cドライブのみの再セットアップ]など3項目が表示されたので、自分は[ハードディスクを購入時の状態に戻して再セットアップ]を選択。
- あとは「ディスク2を入れてください」等の指示に従って、Diskを入れ替えていけば、そのうちWindowsのセットアップ画面になる。
以上の作業によりHDDが故障していない限りはリカバリディスクを作成して再セットアップ可能。
ただし、当初のエラーの原因がHDDにある可能性もあるので、HDDを交換してからリカバリディスクを使用した方がいいかもしれない。
今後はCrystalDiskInfoなどのソフトを使用してHDD監視をするつもり。
再セットアップが進むと、シマンテック社の「Norton Ghost」というバックアップツールが起動し、1%2%3%...と作業が進行する。
最初にやった時は、50%ほど作業が完了したところでこんなエラーが出現。
Cannot open GHOSTERR.TXT - insert diskette (434)
File Name ? (546)
Output error file to the following location
[OK] [Cancel]
おそらくGHOSTERR.TXTというファイルの出力先が見つからないのだろうとあたりを付けて、
フォーマット済みCD-RWを挿入後、A:をCDドライブのF:に書き換えてOKを押すと
Application Error 19235
Ghost has detected corruption in the image file.
Please perform an integrity check on the image.
if this program persists, please contact Symantec support center
このイメージファイルとは、前述リカバリディスク作成手順6以降の[拡張子GHSのファイル]。GHSはGHOSTの略か?
そこで、Disk4,5,6をNERO9体験版+太陽誘電製のTHE日本製のDVD-Rを使用し、
念のためディスク1枚あたり4GBを超えないようにし、4倍速で焼き直してみたところ、今度は正常に再セットアップが完了。
最初はWindowsに標準装備されている[ディスクへの書き込み]+台湾製の安物DVD-Rを使用したのだが、
これを教訓に次からは絶対にライティングソフトと国産ディスクを使うことにしよう。
CrystalDiskInfoを使用してHDDの状態を調べたところ、案の定「注意」レベルだった。
| 注意項目 | 生の値 |
|---|---|
| 代替処理保留中のセクタ数 | B(11) |
| 回復不可能セクタ数 | 25(37) |
※[生の値]の数値はデフォルトが16進数表記。括弧内は10進数に変換した数値。
やっぱり当初のエラーはHDDの故障とまではいかなくとも寿命が近いということだったのか。
使用時間は17000時間。HDDの交換を検討した方が良いけど、一体型の交換は難しいような。
まずはWestern Digital製HDDだからData Lifeguard Diagnosticsでゼロフィルをやってみる予定。
エラーチェックで完全に逝くかもしれないけど、バックアップもしてるし、リカバリディスクもあるし。
あと、VistaのバーションはSP1だと思っていたけど、まだ更新していなかった模様。
そこで更新プログラムをインストールしてみると途中で止まってしまい、修復スタートアップする羽目に。
Vista SP1の導入に失敗し、修復スタートアップを行ったものの、12時間経っても終わらず。
そこでいっそのことHDDのデータを完全に消去して、再セットアップすることにした(7時間ほどかかる)。
方法としては先日のとおり、Western Digital製HDDの診断ツール「Data Lifeguard Diagnostics」を使用する。
このツールはFDD版とCD版しかないので、いつものようにUSB版の作成を試みる。以下作り方と使用方法。
- 用意するもの
- 作成手順
- こちら(http://files.extremeoverclocking.com/file.php?f=196)から[Windows 98 System Files]をダウンロード後、解凍しておく。
- こちら(http://files.extremeoverclocking.com/file.php?f=197)から[HP USB Disk Storage Format Tool-v2.1.8]をダウンロード後、インストール。
- [HP USB Disk Storage Format Tool]を起動し、[Device]で用意したUSBを選択。[Create a DOS startup disk]にチェックを付け、[using DOS system files located at:]のところで、先ほど解凍したフォルダ(ファイル名はwin98boot)を指定する。
- こちら(http://support.wdc.com/product/download.asp?groupid=608&sid=30&lang=jp)から[Data Lifeguard Diagnostic for DOS (CD)]のiso形式をダウンロード。
- USB内に[DLGDIAG]という名前のフォルダを作成。
- ダウンロードしたisoファイルを仮想ディスク作成ソフトでマウント。
- マウント起動したディスク内の[DLGDIAG5.EXE][DLGDIAG.txt][DLGLICE.TXT]をUSB内の[DLGDIAG]フォルダにコピー。
- 完成!
- 使用方法
- PCにUSBを挿して、起動直後にF2を連打。BIOS設定画面から[boot]→[Hard Disk Boot Priority]を選択し、USB-HDDを一番上にして設定保存。
- DOSが起動するので、[cd dlgdiag]と入力してEnter。その後、[dlgdiag5]と入力してEnter。
- [Data Lifeguard Diagnostic]が起動するので、ライセンス画面でESCキーを押す。そして承諾。
- メイン画面が開いたら、[Extended Test]を選択して、まずはHDDのチェック(結果は余裕のFail)。所要時間は容量500GBで1時間40分。
- 続いて[Write Zeros To Drive]を選択して、HDD内の全データを削除(0で埋める)。これは2時間。
- もう一度[Extended Test]を実行(1時間40分)。この時点でNO ERRORS FOUND(エラーなし)。
- BIOS設定画面を開き、デフォルト設定をロードして、あとは前述どおりに再セットアップ(1時間30分)。
再セットアップ後、CrystalDiskInfoを実行すると見事に「正常」レベルに回復。
前回注意項目だった「代替処理保留中のセクタ」と「回復不可能セクタ数」の生の値は0に変化。
なぜか使用時間が14000時間に減少していたものの、とりあえずはHDDの故障の心配はしなくていいかな。
ちなみにSP1の導入は成功。今後はCrystalDiskInfoを常駐させ、監視を続けることにする。
あれから10か月後、悪夢のブルースクリーンが降臨したので、またクリーンインストールを行った。
CrystalDiskInfoを使用してHDDの状態を調べたところ、「注意」レベルに逆戻り。
| 注意項目 | 生の値 |
|---|---|
| 代替処理保留中のセクタ数 | 2D9(729) |
| 回復不可能セクタ数 | 70(112) |
※[生の値]の数値はデフォルトが16進数表記。括弧内は10進数に変換した数値。
以前のエラー時よりさらに状況が悪化しており、HDDの寿命がかなり迫っている模様。
いつ突然死を迎えてもおかしくないので、重要なデータをバックアップのうえHDDの交換を予定。
ブログがないので、増田にログ残し。ツッコミや質問はid:frsattiまで。
たかがコピペ相手にそこまで憤慨している増田が怖すぎる。 思い込みが激しすぎるというか、独善的というか。 リアルでこんな人と関わりあいたくねえええええ. Permalink | トラックバック(0) | 23:34 はてなブックマーク このエントリーのブックマーク ...
anond.hatelabo.jp/ - キャッシュ - 類似ページ増田とは - はてなキーワード
増田 - 日本人に多い苗字 リスト::日本人の苗字 主な有名人 名前なまえ別名肩書き解説 チャンコ増田ちゃんこますだ-サークル主宰者「抱き枕製作」という同人ジャンルを成立 増田...
d.hatena.ne.jp/keyword/増田 - キャッシュ - 類似ページ増田にゃんねるβ
1 名前:以下、はてなにかわりまして元増田がお送りします。 投稿日:2010/10/14 00:47:00. 最近嫌なこと続きでむしゃくしゃして、この前つい中古でポケモンハートゴールド買ってしまった。 起動してみたら前のデータが残ってたので、めぼしいものを ...
masuda.livedoor.biz/ - キャッシュ - 類似ページ24 時間以内の結果をさらに検索
増田俊男の小冊子 Vol.17 「2010年の総決算?!」 2010年から2011年7月までをズバリ大予測! 主な解説内容: *米中間選挙の論争点と結果* ... 「増田俊男の世界」(時事直言)携帯サイト ※携帯電話のバーコードリーダーで左のQRコードを読み取り、 ...
www.chokugen.com/ - キャッシュ - 類似ページ増田貴久 - Wikipedia
増田 貴久(ますだ たかひさ、1986年7月4日 - )は、日本のタレント、歌手。男性アイドルグループ・NEWSおよびテゴマスのメンバーである。愛称はまっすー。ジャニーズ事務所所属。東京都練馬区出身。クラーク記念国際高等学校卒業。身長171cm、体重68kg。 ...
ja.wikipedia.org/wiki/増田貴久 - キャッシュ - 類似ページ場所:増田
homepage3.nifty.com/MASUDA/ - キャッシュ - 類似ページデイトレードや株価(日経平均/225先物)に強い株価チャートソフト増田足
2010年10月14日 ... 株価チャートソフトなら「トレンド」「転換点」がひと目でわかる増田足。デイトレードの基本テクニックやノウハウ、日経平均(225先物)など株価に関する情報もご提供しております。
www.masudaasi.com/ - キャッシュ - 類似ページ24 時間以内の結果をさらに検索
2010年10月14日 ... ますだおかだ増田のブログ、ますだおかだ増田ブログです。漫才師 ますだおかだ増田 公式ブログ.
ameblo.jp/msokm/ - キャッシュ - 類似ページ24 時間以内の結果をさらに検索
このコラムの上の「増田部長のめざめるパワー」の写真の背景。 そうです、NYです!! ちゃんと右端にブルックリンブリッジが写って .... 増田順一プロフィール. 株式会社ゲームフリーク取締役開発部長; 1968年1月12日生まれ; 神奈川県横浜市出身 ...
www.gamefreak.co.jp/blog/dir/ - キャッシュ - 類似ページ増田寛也 オフィシャルサイト
元総務大臣、元岩手県知事、現野村総合研究所顧問の増田寛哉のオフィシャルサイト.
www.h-masuda.net/ - キャッシュ - 類似ページ増田 のニュース検索結果
デイリースポーツ ますおか増田「―ダジャレで覚える韓国語」本を出版 - 12時間前
漫才コンビ・ますだおかだの増田英彦(40)=写真=が14日、韓国語会話本「ますだ式 ダジャレで覚える韓国語」(学研パブリッシング、税込み1000円)の出版会見を大阪市内で開いた。 3月までNHKの「テレビでハングル講座」に出演し、ダジャレ ...
スポーツ報知 - 関連記事 4 件
「全日本大学駅伝」の魅力、増田明美さんに聞きました! - 名古屋テレビ - 関連記事 2 件
増田俊樹
増田塾
増田都子
増田 b'z
10/18 改訂
なお、取得した画像の著作権はグーグル他各社が保持しています。
ご利用は計画的に私的範囲でどうぞご利用ください。
#!/usr/bin/perl use strict; use warnings; use Getopt::Long; use LWP::UserAgent; use GD; my $cmdline = join(" ", $0, @ARGV); my $usage = "usage: $0 -sx=116423 -sy=51603 -ex=116426 -ey=51605 -dx=4 -dy=3 -z=17 -size=300 -get=30 -dir=cache -output=output.jpg -nodebug"; my ($sx, $sy) = (0, 0); my ($ex, $ey) = (0, 0); my ($dx, $dy) = (4, 3); my $z = 17; my $size = 300; my $get = 30; my $dir = "cache"; my $output = "output.jpg"; my $debug = 0; GetOptions("sx=i" => \$sx, "sy=i" => \$sy, "ex=i" => \$ex, "ey=i" => \$ey, "dx=i" => \$dx, "dy=i" => \$dy, "z=i" => \$z, "size=i" => \$size, "get=i" => $get, "dir=s" => \$dir, "output=s" => \$output, "debug!" => \$debug) or die "$usage\nDied"; if ($ex == 0) { $ex = $sx + $dx; } else { $ex++; $dx = $ex - $sx; } if ($ey == 0) { $ey = $sy + $dy; } else { $ey++; $dy = $ey - $sy; } $sx>0 and $dx>0 and $sy>0 and $dy>0 and $z>0 and $dir and $output or die "$usage\nBad arguments"; $dx*$dy > $size and die "Getting too large."; $debug and print "debug: mkdir $dir\n"; mkdir $dir; -d $dir or die "can't make dir $dir: $!"; my $base = sprintf("http://khm%d.google.co.jp/kh/v=46&z=%d", int(rand(4)), $z); my $ua = LWP::UserAgent->new; printf "now get %d images...\n", $dx*$dy; for (my $x=$sx; $x < $ex; $x++) { for (my $y=$sy; $y < $ey; $y++) { my $file = sprintf("%s/%02dz%06dx%06d.jpg", $dir, $z, $x, $y); $debug and print "debug: check of $file\n"; -s $file and next; --$get < 0 and last; my $req = HTTP::Request->new(GET=>+"$base&x=$x&y=$y"); $debug and print "debug: fetch from ".$req->uri."\n"; my $res = $ua->request($req); unless ($res->is_success) { print "fail fetch from $file: ", $res->status_line, "\n"; next; } if (open(my $fh, ">", $file)) { $debug and print "debug: write of $file\n"; binmode $fh; print $fh $res->content; close $fh; } else { print "fail open in $file: $!\n"; } } } $get < 0 and print "reach the getting limit, skip after all.\n"; printf "creating %dX%d image...\n", 256*$dx, 256*$dy; my $image = new GD::Image(256*$dx, 256*$dy); for (my $x=$sx; $x < $ex; $x++) { for (my $y=$sy; $y < $ey; $y++) { my $file = sprintf("%s/%02dz%06dx%06d.jpg", $dir, $z, $x, $y); $debug and print "debug: check of $file\n"; -s $file or next; $debug and print "debug: read of $file\n"; my $part = GD::Image->newFromJpeg($file); $debug and print "debug: image copy\n"; $image->copy($part, 256*($x-$sx), 256*($y-$sy), 0, 0, 256, 256); } } #$image->string(gdSmallFont, 0, 0, $cmdline, $image->colorAllocate(255, 255, 255)); open(my $fh, ">", $output) or die "fail open $output: $!"; $debug and print "debug: write of $output\n"; binmode $fh; print $fh $image->jpeg(); close $fh;
例えば秋葉原とか
perl gmwall.pl -sx=116423 -sy=51603 -ex=116427 -ey=51606
駅だけとか
perl gmwall.pl -sx=465701 -sy=206420 -ex=465705 -ey=206423 -z=19
使う数値はfirebugなどで拾ってください。
スーパーpre記法がアレなまま直ってないわけで。
姉妹サイト(?)ができていたわけで。
なにやらcookieを食べようとした形跡があるわけで。
#!/usr/local/bin/perl -w use strict; use warnings; use Web::Scraper; use URI; use Perl6::Say; use MIME::Type; use HTTP::Cookies; use LWP::UserAgent; use Path::Class; use Data::Dumper;sub p { print Data::Dumper::Dumper(@_) }; # cookie_jar~A~T~_~H~P #my $cookie_file = "lwpcookies.txt"; #my $cookie_jar = HTTP::Cookies->new(file => $cookie_file, autosave => 1, ignore_discard => 1); my $page = shift || 10000; unless ( $page =~ /^\d+$/ ) { die 'perl 4u.pl [page as int]'; } my @files = dir('./img/')->children; my $cache = {}; my $end_file = { mtime => 0 , file => '' }; for my $file (@files) { if ( $file->basename =~ /^(.+)\.(.+)$/ ) { $cache->{$1} = $2; } if ( $end_file->{mtime} < $file->stat->mtime ) { $end_file->{mtime} = $file->stat->mtime; $end_file->{file} = $file; } } for my $i (1..$page) { my $url = sprintf 'http://nijigen.straightline.jp/?page=%s' , $i; # if ($i == 1){ # $url = sprintf 'http://4u.straightline.jp/nude?filter=off'; # my $ua = LWP::UserAgent->new; # $ua->cookie_jar($cookie_jar); # my $request = HTTP::Request->new(GET => $url); # my $res = $ua->request($request); # } say "request url>".$url; my $scrp = scraper { process '/html/body/div/div[2]/div[2]/div/div/div/div/div/a', 'link[]' => '@href'; process '/html/body/div/div[2]/div[2]/div/div/div/div[2]/div/div/p[2]/span/a', 'img[]' => '@href'; result 'link','img'; }; # $scrp->user_agent->cookie_jar($cookie_jar); my $tmp = $scrp->scrape(URI->new($url)); my $links = $tmp->{link}; my $imgs = $tmp->{img}; if ( ref $links ne 'ARRAY' ) { say "end program."; exit; } for my $link (@$links) { $link =~ m{/([^/]+)$}; my $sesid = $1; if ( $end_file->{file} &amp;&amp; $end_file->{file}->basename =~ /^$sesid\./ ) { say "file exsits end program >".$sesid; # exit; next; } if ( $cache->{$sesid} ) { say "file exsits next >".$sesid; next; } sleep 5; my $image_url = shift @$imgs || next; $image_url =~ s/^http:\/\/nijigen.straightline.jp\/user\/manage\/do_register\?src=//; $image_url =~ s/%3A/:/ig; $image_url =~ s/%2F/\//ig; say "get image url >".$image_url; my $ua = LWP::UserAgent->new; my $req = HTTP::Request->new(GET => $image_url); my $res = $ua->request($req); my $content = $res->content; my $content_type = $res->headers->header('content-type'); my $ext = MIME::Type->new( type => $content_type )->subType || 'bin'; if ( $ext eq 'plain' ) { say "not found image >".$image_url; # ~\家~A~T~C~O~A~L~H~A~H~A~A~_~B~I4U~A奴~B~R~]~X~A~Y~B~K~@~B my $image_url = 'http://nijigen.straightline.jp/html/found/static/upload/l/l_'.$sesid.'.jpg'; say "get 4u image url >".$image_url; my $req = HTTP::Request->new(GET => $image_url); my $res = $ua->request($req); $content = $res->content; $ext = 'jpeg'; } my $write_path = './img/'.$sesid.'.'.$ext; open my $FH, '>', $write_path; binmode $FH; print $FH $content; close $FH; say "write image >".$write_path; } }
と思った。
キーボードをよく見ればわかるように、様々なキーが乱立している。Shift、Ctrl、Alt、Esc、そしてWindows/Appleキーもよくみられるようになっている。
しかしShiftだのCtrlだのAltだの、機能キーがどんどん増えていてはちゃめちゃになってきているように感じる。それにしてはタイピングというものにもっと大きな可能性が残されているように感じてならなかった。何が問題なのだろうか?
今までの話はキーボードといっても汎用コンピューター入力デバイスとしてよくみられるキーボードの話であった。一方キーボードというものには楽器用のキーボードもある。同じ指で打鍵するタイプだが大きな違いがある。和音を奏でるためによく複数の箇所を同時押しをするのだ。
汎用コンピューター入力デバイスとしてのキーボードに視点を戻してみる。同時押しといってもそれはShift、Ctrl、Alt、Windows/Appleなどのキーが主体であり、例えばCとVを同時押しするとか、PとDを同時押しするとか、そういう利用法はほとんどない。というよりワープロから考えればわかるように同時押しを同時押しではなく逐次押しとして処理していくようになっている。
なんかもったいないんだよなあ。
無論アルファベットなどのキーの同時押しを別処理用途として開放することにはデメリットもある。普通に高速タイピングしていると瞬間瞬間では複数のキーが同時に押されていることは多いのだろう。例えば「dir」と打鍵する場合も詳しくみていけば「d」、「d+i」、「i」、「i+r」、「r」という状態を経ているのかもしれない。ということは普通に高速タイピングしていても思わず修飾キーとして動作されて戸惑う場面が出てしまうかもしれない。
それでもやはりこの同時押しキー空間をほぼ封印しっぱなしにするのは実に惜しいと思うのである。
----
ここみる http://d.hatena.ne.jp/h_kenan/20080717
apt-get から install Encode
svn から Encode
cd [Encode Dir] してから sudo perl Makefile.PL
モジュール一括インストール? sudo -H cpan App::Mobirc
make && make test して出てきた not installed を f**k
=> install Test::Spelling
sudo gnome-terminal
cd /home/pc/.cpan/build/HTML-DoCoMoCSS-0.01
・・・いけたか?
・・・
・・・
・・・
はいむりー
まあ、昔はUNIXって手に入りづらかったから、UNI+とかそういうのがあったわけだ。
そこには「より一般化された方法論や機能性の強力さ」への渇望があったんだと思うし、それは「Windows 上がりなんで CUI 苦手で」とか口走る人の顔に浮かぶ恥じらいのような表情にも通底しているんだと思う。
なので、
1. dir最強
(snip)
はそのとおりだと思う。いまどきLinuxでも*BSDでもOpenSolarisでも(それこそバッドエンドかもしれないがCygwinでも)行っちゃえばいい。ただで行ける。そこには特に感興はない。
元々の感想は、大元の増田が情報を一覧整理してわざわざ増田にメモしようというような人であるにも関わらず、上のような一般性への希求があまり感じられないのが興味深いというものだったのだが、よくよく読むと大元増田にとっては「ファイル一覧イコールDVD上のMP3データ整理」なのだから、「音楽データ整理TIPS」として読めばそんなに不自然ではないのかも知れん。
リストを出したいフォルダに移動(cd)して『dir /b *.* > file_list.txt』を実行
ディレクトリのファイル一覧の採取に対して、「方法」とか「Tips」とか「dir最強」といった「大仰な言い方」ができる、というのはちょっと新鮮。
昔からCUI対GUI(ファイラー)論争とかは目にすることはあったけど、あれはあくまでCUI/GUI論争の一種で、何がどうあれファイルの一覧が採取できることは双方前提の話だったと思う。どっちが便利か好みかって話で。
そこはエクセルなのかーー。
「実はコマンドってのがあって、sortとかuniqとか使うとすごいんだぜ、へへん」というわけでもないし(この方向性は食傷)、淡々と網羅性も一貫性もない方法群を書き連ねる(それをファイル一覧採取に対して!!)、という感覚がちょっと新鮮。
●便利なシチュエーション
『dir /b *.* > file_list.txt』を実行
拡張子の指定で「特定拡張子のファイルのみ」、または「拡張子は異なるが同じファイル名」の一覧も作成可能。
ソフトのインストールも不要で使用環境を選ばない。最強。ただしソートには別途エクセルが必要。
重複ファイルの検索も可能
フォルダ以下のファイル一覧が作成可能。MP3のアルバムを、ZIP圧縮ではなく1フォルダ1アルバムで管理している際に便利
YourFileHostのCAPTCHA画像をなんとかするの続きの続き。
まぁ、なんというか、一応できたので張ってみる。微妙な出来栄えだけど。
decaptcha.rbと同じディレクトリに置いて適当に動かしてみてください。
どっかにいいRSSがないかなぁ。。。
しかし、CAPTCHA画像を相手にしてた時の方が楽しかったなぁ。。。
あと、添削とかいろいろ歓迎です。
なぜか&が&amp;に置き換えられてるみたいなので、適当に&に読み替えてください。
#!/usr/local/bin/ruby $LOAD_PATH << File::dirname(File::expand_path($0)) require 'rubygems' require 'rss' require 'mechanize' require 'decaptcha' # require 'ruby-debug' # require 'pp' DESTDIR = 'files' TMPDIR = '/tmp' class Downloader COOKIE_URI = 'http://www.yourfilehost.com/media.php?cat=video&file=%s' DOWNLOAD_URI = 'http://www.yourfilehost.com/downloadlink.php?cat=video&file=%s&adult=1' VERBOSE = false DEBUG = false def self.fetch(file, destdir) puts "Fetching file: #{file}" destfile = destdir + '/' + file if test(?e, destfile) then puts ' - Already exists. skip' puts return nil end # # Initialize Mech # mech = WWW::Mechanize.new mech.user_agent_alias = 'Windows IE 6' mech.max_history = 3 mech.open_timeout = 15 mech.read_timeout = 3 # # get cookie # uri = COOKIE_URI % file page = mech.get(uri) # # Challenge against CAPTCHA # uri = DOWNLOAD_URI % file page = mech.get(uri) for i in 0...3 captcha_path = (page/'img[@height="38"]').attr(:src) captcha_uri = 'http://www.yourfilehost.com/%s' % captcha_path gif = mech.get_file(captcha_uri) open("#{TMPDIR}/captcha.gif", 'w') {|fd| fd.write(gif) } mech.back code = DeCAPTCHA.decode("#{TMPDIR}/captcha.gif") File.unlink("#{TMPDIR}/captcha.gif") if code.nil? then puts ' - CAPTCHA decode failed. retry' if VERBOSE next end form = mech.page.forms.first form.verify = code page = mech.submit(form) break unless page.links.empty? end if page.links.empty? then puts ' - Failed 3 times. Try another one.' puts return nil end # # download # puts " - Downloading: #{page.links.first.href}" if DEBUG retry_count = 0 video = nil begin video = page.links.first.click rescue Timeout::Error => evar retry_count += 1 if retry_count < 5 then puts " * Timedout, retry" if VERBOSE retry end raise evar end unless video.instance_of?(WWW::Mechanize::File) then if DEBUG then puts " - Something wrong while downloading. skip." puts end return nil end video.save(destfile) return destfile end end # # main # [DESTDIR, TMPDIR].each do |dir| if !test(?d, dir) or !test(?w, dir) then puts "#{dir}: Directory not exists or cannot write." exit end end files = [] # collect URIs from RSS RSS_URI = [ ['http://www.yourfilehost.com/make-rss.php?range=day&af=off', lambda {|rss| rss.items.map {|x| x.link }}, ], ] RSS_URI.each do |uri, preprocessor| rss = RSS::Parser.parse(uri) uris = preprocessor.call(rss) #=> Array of URI of YourFileHost uris.map {|x| /file=([^&]*)/.match(x).to_a[1] }.each do |file| # next if file !~ /\.wmv/ # uncomment it if you need only wmv files << file end end files.uniq! # download files.each do |file| begin Downloader.fetch(file, DESTDIR) rescue SystemCallError, Timeout::Error => evar puts " - error (#{evar.to_s}). skip." puts end end __END__
これでおしまいだよ
(require 'cl) ; for cl-seq (defvar sangels-movies-dir nil) (defvar sangels-player "c:/Program Files/GRETECH/GomPlayer/GOM.exe") (defvar sangels-sort-by 'sangels-sort-by-rate) (defvar sangels-rate-file "~/.emacs.d/.sangels/rate") (defvar sangels-buffer "*sangels*") (defvar sangels-thumbnail "00_thumbnail.jpg") (defvar sangels-m3u "00_movies.m3u") (defface sangels-name '((t (:family "fixed" :weight bold :height 3.0))) "") (defface sangels-rate '((t (:family "fixed" :weight bold :height 1.5))) "") (defvar sangels-mode-map (let ((map (make-sparse-keymap))) (define-key map "n" 'next-line) (define-key map "p" 'previous-line) (define-key map (kbd "RET") 'sangels-select) (define-key map (kbd "SPC") 'sangels-select) (define-key map "q" 'sangels-quit) (define-key map "+" 'sangels-rate-plus) (define-key map "-" 'sangels-rate-minus) map)) (defvar sangels-mode-hook nil) (defvar sangels-highlight-overlay nil) (defvar sangels-rate-alist nil) (defconst sangels-rate-max 6) (defun sangels-insert-movies () (save-excursion (let* ((inhibit-read-only t) (files (remove-if-not (lambda (x) (and (not (member (file-name-nondirectory x) '("." ".."))) (file-directory-p x) (member sangels-thumbnail (directory-files x)))) (directory-files sangels-movies-dir t))) (ids (mapcar 'file-name-nondirectory files))) (erase-buffer) (setq ids (sangels-sort-ids ids)) (dolist (id ids) (let ((file (expand-file-name id sangels-movies-dir)) (pos (point))) (insert-image-file (expand-file-name sangels-thumbnail file)) (end-of-line) (insert (propertize (format "%-15s " id) 'face 'sangels-name)) (sangels-insert-rate id) (insert "\n") (put-text-property pos (point) 'sangels-id id)))))) (defun sangels-sort-by-name (a b) (string< a b)) (defun sangels-sort-by-rate (a b) (or (> (sangels-rate a) (sangels-rate b)) (sangels-sort-by-name a b))) (defun sangels-sort-ids (ids) (sort ids (or sangels-sort-by 'sangels-sort-by-name))) (defun sangels-insert-rate (id) (let ((rate (sangels-rate id))) (insert (propertize (concat (make-string rate ?★) (make-string (- sangels-rate-max rate) ?☆)) 'sangels-rate t 'face 'sangels-rate)))) (defun sangels-current-id () (get-text-property (point) 'sangels-id)) (defun sangels-play-movie (movie) (let ((explicit-shell-file-name "cmdproxy") (shell-file-name "cmdproxy")) (apply 'call-process-shell-command "start" nil "*tmp*" nil (mapcar (lambda (x) (concat "\"" x "\"")) (list sangels-player (unix-to-dos-filename movie)))))) (defun sangels-select () (interactive) (let ((id (sangels-current-id))) (when id (sangels-play-movie (expand-file-name sangels-m3u (expand-file-name id sangels-movies-dir)))))) (defun sangels-quit () (interactive) (kill-buffer sangels-buffer)) (defun sangels-rate (id) (or (cdr (assoc id sangels-rate-alist)) (/ sangels-rate-max 2))) (defun sangels-rate-save () (interactive) (let ((dir (file-name-directory sangels-rate-file))) (unless (file-exists-p dir) (make-directory dir t))) (with-temp-file sangels-rate-file (insert (pp-to-string sangels-rate-alist)))) (defun sangels-rate-load () (interactive) (when (file-exists-p sangels-rate-file) (with-temp-buffer (insert-file-contents sangels-rate-file) (goto-char (point-min)) (setq sangels-rate-alist (read (current-buffer)))))) (defun sangels-rate-plus (&optional n) (interactive "p") (setq n (or n 1)) (let* ((id (sangels-current-id)) (cell (assoc id sangels-rate-alist))) (unless cell (setq cell (cons id (sangels-rate id))) (setq sangels-rate-alist (cons cell sangels-rate-alist))) (setcdr cell (+ (cdr cell) n)) (save-excursion (let ((inhibit-read-only t)) (beginning-of-line) (goto-char (next-single-property-change (point) 'sangels-rate)) (delete-region (point) (next-single-property-change (point) 'sangels-rate)) (sangels-insert-rate id))) (sangels-rate-save))) (defun sangels-rate-minus (&optional n) (interactive "p") (setq n (or n -1)) (sangels-rate-plus (- n))) (defun sangels-post-command-hook () (save-excursion (move-overlay sangels-highlight-overlay (progn (move-beginning-of-line 1) (point)) (progn (move-end-of-line 1) (forward-line) (point)) (current-buffer)))) (defun sangels-mode () (interactive) (kill-all-local-variables) (use-local-map sangels-mode-map) (setq sangels-highlight-overlay (make-overlay 0 0)) (overlay-put sangels-highlight-overlay 'face 'highlight) (overlay-put sangels-highlight-overlay 'evaporate t) (make-local-variable 'post-command-hook) (add-hook 'post-command-hook 'sangels-post-command-hook nil t) (setq major-mode 'sangels-mode) (setq mode-name "Sangels") (run-mode-hooks 'sangels-mode-hook) (set-buffer-modified-p nil) (setq buffer-read-only t)) (defun sangels (&optional arg) (interactive "P") (when (or arg (not sangels-movies-dir)) (setq sangels-movies-dir (read-directory-name "movies dir: "))) (sangels-rate-load) (switch-to-buffer (get-buffer-create sangels-buffer)) (sangels-insert-movies) (sangels-mode)) (provide 'sangels)
せっかく書いたから匿名でのせてみるよ
使い方は
必要なものを gem で取ってくるにはこうすればいいよ
長すぎてelispが消えたから続きがあるよ
@echo off setlocal set WD=%~dp0 cd /d %WD% ruby get_movies.rb ruby get_images.rb ruby create_m3u.rb
user: ユーザID password: パスワード ids_file: ids.txt done_file: ids_done.txt movies_dir: movies log4r_config: pre_config: global: INFO loggers: - name: app type: Log4r::Logger level: INFO outputters: - STDOUT - FILE outputters: - name: STDOUT type: Log4r::StdoutOutputter formatter: type: Log4r::PatternFormatter pattern: "%d [%l] %C - %M" date_pattern: "%H:%M:%S" - name: FILE type: Log4r::FileOutputter filename: "#{LOGDIR}/sangels.log" formatter: type: Log4r::PatternFormatter pattern: "%d [%l] %C - %M" date_pattern: "%Y-%m-%d %H:%M:%S"
require 'fileutils' require 'logger' require 'mechanize' BASEDIR = File.dirname($0) require "#{BASEDIR}/util" require "#{BASEDIR}/sangels" $config = load_config(BASEDIR) prepare_logger(BASEDIR) $log = new_logger("get_movies") WWW::Mechanize.log = new_logger("mechanize") WGet.log = $log class IDFile def initialize(file) @file = file unless File.exist?(@file) Fileutils.touch(@file) end end def ids(contains_comment = nil) File.open(@file) {|io| io.to_a.map {|x| x.chomp }.select {|x| if x.empty? nil elsif contains_comment true else not /^\s*\#/ =~ x end } } end def add(id) ids = ids(true) unless ids.any? {|x| x == id} write(ids + [id]) end end def delete(id) ids = ids(true) if ids.any? {|x| x == id} write(ids - [id]) end end def write(ids) File.open(@file, "w") {|io| ids.each {|x| io.puts x} } end end $log.info("BEGIN #{$0} ================") exit_code = 0 begin ids_file = IDFile.new($config.ids_file) done_file = IDFile.new($config.done_file) movies_dir = $config.movies_dir wget = WGet.new sangels = SAngels.new sangels.login($config.user, $config.password) ids_file.ids.each {|id| begin movies = sangels.movies(id) rescue SAngels::Movies::InvalidMoviesError $log.warn("invalid movie id: #{id}") next end dir = File.expand_path(id, movies_dir) movies.each {|link| wget.retrieve(link.href, dir) } expected = movies.movie_links.map{|x| File.basename(x.href)} actual = Dir.glob("#{dir}/*").map {|x| File.basename(x)} if (expected - actual).empty? done_file.add(id) ids_file.delete(id) end } rescue => e $log.error(e) exit_code = 1 end $log.info("END #{$0} (#{exit_code}) ================") exit exit_code
require 'fileutils' require 'logger' require 'mechanize' require 'ostruct' BASEDIR = File.dirname($0) require "#{BASEDIR}/util" require "#{BASEDIR}/sangels" $config = load_config(BASEDIR) prepare_logger(BASEDIR) $log = new_logger("get_images") WWW::Mechanize.log = new_logger("mechanize") WGet.log = $log $log.info("BEGIN #{$0} ================") exit_code = 0 begin movies_dir = $config.movies_dir sangels = SAngels.new sangels.login($config.user, $config.password) thumbnails = sangels.thumbnails Dir.glob("#{movies_dir}/*").each {|dir| next unless File.directory? dir id = File.basename(dir) url = thumbnails.url(id) unless url $log.warn("#{id} is not found") next end path = File.expand_path("00_thumbnail#{File.extname(url)}", dir) next if File.exist? path $log.info("retrieving #{url}") thumbnail = thumbnails.get_file(id) File.open(path, "wb") {|io| io.write(thumbnail)} } rescue => e $log.error(e) exit_code = 1 end $log.info("END #{$0} (#{exit_code}) ================") exit exit_code
BASEDIR = File.dirname($0) require "#{BASEDIR}/util" $config = load_config(BASEDIR) movies_dir = $config.movies_dir Dir.glob("#{movies_dir}/*") {|dir| next unless File.directory? dir name = File.basename(dir) files = Dir.glob("#{dir}/*.wmv").sort File.open("#{movies_dir}/#{name}.m3u", "w") {|io| files.each {|file| io.puts "#{name}/#{File.basename(file)}" } } File.open("#{dir}/00_movies.m3u", "w") {|io| files.each {|file| io.puts "#{File.basename(file)}" } } }
require 'mechanize' require 'hpricot' BASEDIR = File.dirname($0) require "#{BASEDIR}/util" class SAngels HOST = "real2.s-angels.com" LOGIN_URL = "http://#{HOST}/member/" INFO_URL = "http://#{HOST}/teigaku/item.php" THUMBNAILS_URL = "http://#{HOST}/teigaku/" THUMBNAIL_URL = "http://#{HOST}/images/default/thumb/" def initialize() @agent = WWW::Mechanize.new end def login(user, password) login_form = @agent.get(LOGIN_URL).forms.find {|form| form.fields.any? {|field| field.name == "frmLoginid"} } login_form.frmLoginid = user login_form.frmPw = password @agent.submit(login_form) end def movies(id, no_validate = nil) Movies.new(@agent, id, !no_validate) end def thumbnails Thumbnails.new(@agent) end class Thumbnails def initialize(agent) @agent = agent doc = Hpricot(@agent.get_file(THUMBNAILS_URL)) elems = doc.search("div[@class=realthum]/a") @links = Hash( elems.map {|elem| href = elem["href"] id = $1 if /ID=(.+)/ =~ href url = elem.search("img")[0]["src"] [id, url] }) end def get_file(id) @agent.get_file(url(id)) end def url(id) @links[id] end def exist?(id) url(id) end end class Movies class InvalidMoviesError < StandardError end def initialize(agent, id, no_validate) @agent = agent @id = id if !no_validate && !valid? raise InvalidMoviesError end end def info_page_url "#{INFO_URL}?ID=#{@id}" end def info_page @agent.get(info_page_url) end def movies_page @agent.click(info_page.links.find {|link| /P=10/ =~ link.href}) end def movie_links movies_page.links.select {|link| /wmv$/ =~ link.href }.sort {|a, b| File.basename(a.href) <=> File.basename(b.href) } end def valid? info_page.uri.to_s == info_page_url end def each(&block) orig_links = movie_links orig_links.each {|orig_link| link = movie_links.find {|l| File.basename(l.href) == File.basename(orig_link.href)} block.call(link) } end end end
require 'log4r' require 'log4r/yamlconfigurator' require 'singleton' require 'fileutils' require 'ostruct' def Hash(a) Hash[*a.flatten] end def load_config(basedir) OpenStruct.new(File.open("#{basedir}/config.yaml") {|io| YAML.load(io)}) end def new_logger(name) Log4r::Logger.new("app::#{name}") end def prepare_logger(basedir, logdir = nil) logdir ||= basedir Log4r::YamlConfigurator["LOGDIR"] = logdir Log4r::YamlConfigurator.load_yaml_file("#{basedir}/config.yaml") end class NullObject include Singleton def method_missing(message, *arg) NullObject.singleton end end class WGet class << self attr_accessor :log def initialize super @log = NullObject.singleton end end def log self.class.log end def retrieve(url, dir) FileUtils.mkdir_p(dir) file = File.expand_path(File.basename(url), dir) if File.exist?(file) log.info("already retrieved #{url}") return true end tmp = "#{file}.part" log.info("retrieving #{url}") ret = system("wget", "-c", "-O", tmp, url) if ret log.info("retrieving succeeded #{url}") File.rename(tmp, file) else if $? == 0x020000 # Ctrl-C exit($?) else log.error("retrieving failure #{url} (#{$?})") end end return ret end end
YourFileHostのCAPTCHA画像をなんとかするの続き。
その後、適当にいじったら、手元環境で1枚あたり25秒くらい→だいたい2.5秒くらいで判別できるようになった。このくらいなら使えるかな。
速度向上に一番効いたのは、Token#importで画像を比較しているところの修正。他は細かい手直し。
使い方は前のやつと変わってません。
あと、テストに100枚くらいCAPTCHA画像食わせてみたけど、とりあえず全部正しく判定できた。
カレントディレクトリ以下にある*.gifなCAPTCHA画像ファイルを適当に判別するスクリプト。動作確認用にどうぞ。
後述のdecaptcha.rbと同じディレクトリに適当に置いてchmod +xしてね。
#!/usr/local/bin/ruby $LOAD_PATH << File::dirname(File::expand_path($0)) require 'decaptcha' STDOUT.sync = true Dir.glob('*.gif').sort.each do |file| correct = File::basename(file, '.*') puts "Processing file: #{file}" start_time = Time.now ret = DeCAPTCHA.decode(file) elapsed = Time.now - start_time puts " Result: #{ret} (=> #{(correct == ret) ? "Ok" : "Fail"})" puts " Elapsed time: #{elapsed}" puts end
#!/usr/local/bin/ruby require 'rubygems' require 'gd2' require 'pp' # #= CAPTCHA画像解析モジュール # CAPTCHA画像ファイルを食わすとあら不思議、Stringが出てくるよ。 # YourFileHostのやつに対応。 # #== Usage # decoded_str = DeCAPTCHA.decode("some_captcha_image.gif") #=> String # 失敗したらnilが返る。 # module DeCAPTCHA DEBUG = false #=== CAPTCHA画像デコード # file:: 画像ファイル名のパス # method:: 未指定でよい。男は細かい事を気にするな。 # returns:: CAPTCHA画像解析結果(String) or nil (デコード失敗時) def self.decode(file, method = DeCAPTCHA::Site::YourFileHost) return method.new(file).decode end #= CAPTCHA画像デコード用クラス # このクラスのサブクラスはimport, tokenize, stream_parseメソッドの # 実装を含む必要がある。 class Site def initialize(file = nil) @pix = nil self.import(file) unless file.nil? end def decode return stream_parse(tokenize()) end end #= YourFileHostのCAPTCHA画像を解析するクラス class Site::YourFileHost < Site def import(file) @pix = PixelMatrix.new.import(file) return self end # importしたイメージ(PixelMatrix)から、文字と思わしきパターンを # 抽出して上下マージンを切り取ってArrayにして返す。 # returns:: Array of PixelMatrix def tokenize ret = [] state = :initial for x in 0...@pix.width case state when :initial if !@pix.vline_blank?(x) then state = :tokenize pixel = PixelMatrix.new(0, 0, true) ret << pixel redo end when :tokenize if @pix.vline_blank?(x) then state = :initial next end x0 = pixel.width for y in 0...@pix.height pixel[x0, y] = @pix[x, y] end else raise 'NOTREACHED' end end ret.map! {|token| Token.new.import(token.cutoff_vmargin!) } end # PixelMatrixのArrayを受け取り、数字を判別。 # tokens:: Array of PixelMatrix # returns:: String (判別結果) def stream_parse(tokens) rs = tokens.map {|x| x.guess.to_s }.join('') if rs.length != 4 then rs = nil if DEBUG then puts '- guess failed. dumping guess result of each token:' tokens.each_index do |i| print "##{i}:#{tokens[i].guess} " pp tokens[i].candidate end puts end end return rs end class Token @@digits = nil attr_accessor :candidate def initialize if @@digits.nil? then # 文字画像サンプルを作っておく @@digits = DIGITS_ASSOC.map {|digit| PixelMatrix.new(0, 0, true).import_array(digit) } end @candidate = Hash.new end # PixelMatrixを受け取り、文字画像サンプルと比較して # 一致率を計算しておく。 # pixel:: PixelMatrix # returns:: self def import(pixel) @@digits.each_index do |i| digit = @@digits[i] if (digit.width - pixel.width).abs > 4 or (digit.height - pixel.height).abs > 4 then @candidate[i] = -1 # サイズが違いすぎな場合、一致させない next end correct_bits = 0 enlarged_width = [digit.width, pixel.width ].max enlarged_height = [digit.height, pixel.height].max for y in 0...enlarged_height dy = (y.to_f / digit.height * enlarged_height).to_i py = (y.to_f / pixel.height * enlarged_height).to_i for x in 0...enlarged_width dx = (x.to_f / digit.width * enlarged_width).to_i px = (x.to_f / pixel.width * enlarged_width).to_i correct_bits += 1 if digit[dx, dy] == pixel[px, py] end end @candidate[i] = correct_bits * 100 / (enlarged_width * enlarged_height) end return self end # importのときの比較結果をもとに文字を推測 # returns:: Fixnum or nil(失敗時) def guess digit, ratio = @candidate.sort {|a, b| a.last <=> b.last}.last digit = nil if ratio < 0 or ratio < 65 return digit end end end #= 画素マトリックスクラス # 画像ファイルを食わせると、各ピクセル(画素)を2値(black(1) or white(0))に # 変換して、内部で保持する。 # 以後、Matrixクラスのような感じで個々の画素にアクセスできる。 class PixelMatrix BLACK = 1 WHITE = 0 attr_accessor :width attr_accessor :height # width:: 幅 # height:: 高さ # is_flexible:: 自動的に伸張するか def initialize(width = 0, height = 0, is_flexible = false) @matrix = Hash.new {|hash, key| hash[key] = Hash.new(WHITE)} @width, @height, @flexible = width, height, is_flexible end # file:: 画像ファイル名のパス # brightness_threshold:: 画素を黒とみなす閾値 (0 - 255, default: 0x40) # returns:: self (DeCAPTCHA::PixelMatrix) def import(file, brightness_threshold = 0x40) gd = GD2::Image.import(file) @width, @height = gd.width, gd.height self.each_with_axis do |x, y| color = gd[x, y] greyscale = (color.red + color.green + color.blue) / 3 self[x, y] = (greyscale > brightness_threshold) ? WHITE : BLACK end return self end def import_array(array) array.each_with_index do |str, y| str.split('').each_with_index do |c, x| self[x, y] = c.to_i end end return self end # PixelMatrixを画像ファイルとしてexport # file:: 新たに作る画像ファイル名のパス def export(file) gd = GD2::Image::IndexedColor.new(@width, @height) gd.palette << GD2::Color::WHITE gd.palette << GD2::Color::BLACK self.each_with_axis do |x, y| gd[x, y] = { WHITE => GD2::Color::WHITE, BLACK => GD2::Color::BLACK, }[self[x, y]] end gd.export(file) return self end # 指定された位置の画素を返す。 # returns:: PixelMatrix::BLACK(1) or WHITE(0) def [](x, y) if !@flexible and !in_range?(x, y) then raise RangeError end return WHITE if !@matrix.has_key?(y) # XXX: for optimize return @matrix[y][x] end # 画素に値を設定。 # returns:: PixelMatrix::BLACK(1) or WHITE(0) def []=(x, y, val) unless in_range?(x, y) then raise RangeError unless @flexible @width = (x >= @width) ? x + 1 : @width @height = (y >= @height) ? y + 1 : @height end @matrix[y][x] = val end def in_range?(x, y) ((0...@width) === x and (0...@height) === y) end # 指定された軸をもとに画素を走査し、Arrayに変換。 # 例えば、to_a(:vertical, 10) とすると、x == 10 な列を取り出して # Arrayにして返す。 # # axis:: 軸を指定 (:vertical または :horizontal) # pos:: 位置を指定。_axis_で指定した軸と直交する軸における位置を指定。 def to_a(axis, pos) {:vertical => lambda { (0...@height).map {|y| self[pos, y]} }, :horizontal => lambda { (0...@width).map {|x| self[x, pos]} }, }[axis].call end # returns:: Array def hline(y) self.to_a(:horizontal, y) end # returns:: Array def vline(x) self.to_a(:vertical, x) end # X軸方向に画素を走査。 # y:: どの位置で走査するか # returns:: 指定された軸の上にドットが存在: false, 無い: true def hline_blank?(y) return true if @matrix.has_key?(y) == false # XXX: for optimize for x in 0...@width return false if self[x, y] == BLACK end return true end # Y軸方向に画素を走査。 # x:: どの位置で走査するか # returns:: 指定された軸の上にドットが存在: false, 無い: true def vline_blank?(x) for y in 0...@height return false if self[x, y] == BLACK end return true end # 上下のマージンを削除した新しいPixelMatrixを返す。 # returns:: PixelMatrix def cutoff_vmargin pixel = PixelMatrix.new(0, 0, true) head = 0 tail = self.height - 1 head.upto(tail) do |y| if !self.hline_blank?(y) then head = y break end end tail.downto(head) do |y| if !self.hline_blank?(y) then tail = y break end end head.upto(tail) do |y| 0.upto(self.width - 1) do |x| pixel[x, y - head] = self[x, y] end end return pixel end # 自身の上下のマージンを削除する。cutoff_vmarginの破壊版。 # 速度稼ぎのために直接@matrixを触ったり、すこしずるをしている。 # 効率は、ほんの少しだけ速くなったような誤差の範囲のような感じ。 # returns:: self (PixelMatrix) def cutoff_vmargin! head = 0 tail = self.height - 1 head.upto(tail) do |y| if !self.hline_blank?(y) then head = y break end end tail.downto(head) do |y| if !self.hline_blank?(y) then tail = y break end @matrix.delete(y) if @matrix.has_key?(y) # XXX end if head > 0 then head.upto(tail) do |y| next if !@matrix.has_key?(y) # XXX @matrix[y - head] = @matrix.delete(y) # XXX end end self.height = tail - head + 1 return self end def each_with_axis for x in 0...@width for y in 0...@height yield(x, y) end end end end end class DeCAPTCHA::Site::YourFileHost::Token DIGITS_ASSOC = [ # 0 ["00000000011111110000000000", "00000001111111111110000000", "00000011111000001111000000", "00001111111100010011110000", "00011111100000110000111000", "00111111000000100001111000", "00111111110001000001111100", "01111111000010000011111110", "01111100000110000111111110", "01111111000100000111111110", "11111100001000001111111111", "11100000001000011111111111", "11111000010000011111111111", "11111000110000111111111111", "10000000100001111111111111", "01100001000001111111111110", "01100010000011111111111110", "01100010000111111111111110", "00111100000111111111111100", "00011100001111111111111000", "00001100011111111111111000", "00001111111111111111100000", "00000011111111111111000000", "00000000111111111100000000"], # 1 ["00001", "00111", "11111", "11111", "10001", "00001", "00001", "00001", "00001", "00001", "00001", "00001", "00001", "00001", "00001", "00001", "00001", "00001", "00001", "00001"], # 2 ["0000011111111110000000", "0001111111111111000000", "0011110000000010000000", "0110000000000100000000", "1100000000001100011110", "1000000000001000001111", "1000000000010000000111", "1000000000110001111111", "1000000000100001111111", "1000000001000000011111", "0100000011000001111111", "0011000010000111111110", "0011000110000001111110", "0000001100000111111100", "0000001000011111110000", "0000011000000111100000", "0000110000000000000000", "0000111111111111111111", "0001111111111111111110", "0011111111111111111100", "0011111111111111111100", "0111111111111111111000", "0111111111111111110000"], # 3 ["000000011111111110000000", "000001111111111111100000", "000011100000011111111000", "000111000000111111111000", "000110000001111111111100", "000100000001111111111100", "000100000011111111111100", "000110000111111111111000", "000010000111111111111000", "000000001111111111100000", "000000011111111111000000", "000000011111111110000000", "000000000000001100000000", "000000000000011100011100", "000000000000111000111110", "000000000000110000001110", "000000000001110001111111", "110000000011100011111111", "111000000111000000111110", "011100000110001111111100", "001111001110000111111000", "000011111100000011100000", "000000011000111000000000"], # 4 ["0000000000011", "0000000000011", "0000000000111", "0000000001111", "0000000001111", "0000000011111", "0000000111111", "0000000110111", "0000001100111", "0000011100111", "0000011000111", "0000110000111", "0001110000111", "0001100000111", "0011000000111", "0111000000111", "0111111111111", "1111111111111", "0000000000111", "0000000000111", "0000000000111", "0000000000111", "0000000000111"], # 5 ["000000001111111111111110", "000000011111111111111100", "000000111111111111111100", "000000111111111111111000", "000001111111111111110000", "000011100000000000000000", "000011011111111110000000", "000111111111111111000000", "001111100000000111000000", "001110000000000110001100", "000000000000000100011110", "000000000000001100000110", "000000000000011000011111", "000000000000011001111111", "000000000000110000011111", "000000000001100000111111", "110000000001100111111110", "011000000011000001111110", "011100000110000011111100", "001111000110011111111000", "000111111100001111110000", "000001111100000011000000", "000000001000011000000000"], # 6 ["000000000000000110000000", "000000010001111111111000", "000001110000011100111100", "000011100000011000001000", "000111000011111000000000", "001111000001110000000000", "001110000000111100000000", "011110001111111111100000", "011100000111000011110000", "011000000010000001111000", "011000011110000011111100", "010000111100000111111110", "100000001000000111111110", "100001111000001111111111", "000011110000011111111111", "000000100000011111111111", "000011100000111111111111", "001111000001111111111110", "000010000001111111111110", "001110000011111111111100", "000111000111111111111000", "000011111111111111110000", "000000111111111111000000", "000000000111111000000000"], # 7 ["0011111111111110001111", "0011111111111100000011", "0111111111111000000110", "1111111111111000111100", "1111111111110000001100", "0000000000000000011000", "0000000000000011111000", "0000000011000000110000", "0000001110000011100000", "0000011110001111100000", "0000111100000011000000", "0001111000000110000000", "0001111000111110000000", "0011110000001100000000", "0011110000001000000000", "0011100011111000000000", "0011000001110000000000", "0001000000110000000000", "0000000111100000000000", "0000000111000000000000", "0000000011000000000000", "0000001110000000000000", "0000001100000000000000"], # 8 ["0000000111111111110000000", "0000011111111111111100000", "0000001111100000011110000", "0000000001110000000111000", "0011000011111000000011100", "0011100001111100000011100", "0011110000001110000011100", "0001111000011111000111000", "0000111100000111101110000", "0000011110000001111100000", "0000001111000011111110000", "0000111111110000011111000", "0011110011111000001111100", "0111100001111100011111100", "0111000000111110000111110", "1111000000011111000000111", "1111000000001111100011111", "1111000000000011111000010", "0111100000000001111100000", "0011110000000000111110000", "0001111110000001111110000", "0000011111111111111000000", "0000000011111110000000000"], # 9 ["000000111111111110000000", "000001111111111111100000", "000111111111111001111000", "001111111111110000010000", "011111111111110000010000", "011111111111100000100000", "011111111111000001100000", "111111111110000001000111", "111111111110000010000001", "111111111100000110000111", "011111111000000100011111", "011111111000001000001111", "001111110000011000011111", "001111100000010001111110", "000111110000100000011110", "000001111111100000111110", "000000011111000111111100", "000000000010000001111100", "000000000110000001111000", "000100001100011111110000", "000111001100001111100000", "000011111000001111000000", "000000010000110000000000"], ] end __END__
そんなわけで、みんな大好きなYourFileHostだけども、最近みてみたら、なんかCAPTCHA認証がついているわけじゃないですか。
でもこれってさーCAPTCHAといっても見るからに危ういというか、見れば見るほど簡単に破れてしまいそうな気がして、どうにもむずがゆいアンニュイな気分になってしまうわけです。
そんで、このたび適当にいじってみたところ、それなりに推測できるコードが書けたので、ここに張ってみますね。
やってることは単純で、こんな感じ
使い方は、こんな感じで
require 'decaptcha.rb' captcha_string = DeCAPTCHA.decode(filename) if !captcha_string.nil? then # 判別成功時の処理 else # 判別失敗時の処理。失敗することもあるのでよしなに。 end
あ、Ruby/GD2入れといてね。sudo gem install gd2とかで入ります。多分。
判別率はそこそこ良い感じになったんだけども、富豪プログラミングがたたってか、いかんせん遅いです。
手元だと1枚判別するのに20秒くらいかかることもある。
そんなわけで誰かチューニングしてくれるとうれしい。
実行速度を上げた改良版はこっちにうpしました。以下のコードは参考程度に。
#!/usr/local/bin/ruby require 'rubygems' require 'gd2' require 'pp' # #= CAPTCHA画像解析モジュール # CAPTCHA画像ファイルを食わすとあら不思議、Stringが出てくるよ。 # YourFileHostのやつに対応。 # #== Usage # decoded_str = DeCAPTCHA.decode("some_captcha_image.gif") #=> String # 失敗したらnilが返る。 # module DeCAPTCHA DEBUG = false #=== CAPTCHA画像デコード # file:: 画像ファイル名のパス # method:: 未指定でよい。男は細かい事を気にするな。 # returns:: CAPTCHA画像解析結果(String) or nil (デコード失敗時) def self.decode(file, method = DeCAPTCHA::Site::YourFileHost) return method.new(file).decode end #= CAPTCHA画像デコード用クラス # このクラスのサブクラスはimport, tokenize, stream_parseメソッドの # 実装を含む必要がある。 class Site def initialize(file = nil) @pix = nil self.import(file) unless file.nil? end def decode return stream_parse(tokenize()) end end #= YourFileHostのCAPTCHA画像を解析するクラス class Site::YourFileHost < Site def import(file) @pix = PixelMatrix.new.import(file) return self end # importしたイメージ(PixelMatrix)から、文字と思わしきパターンを # 抽出して上下マージンを切り取ってArrayにして返す。 # returns:: Array of PixelMatrix def tokenize getter, tokenizer = lambda {|queue| [ lambda { return queue }, lambda {|x, pixel| if pixel.nil? then x, pixel = tokenizer.call(x, PixelMatrix.new(0, 0, true)) queue << pixel return x end if !@pix.in_range?(x, 0) or @pix.vline_blank?(x) then return [x, pixel] end x0 = pixel.width @pix.vline(x).inject(0) do |y, color| pixel[x0, y] = color y + 1 end return tokenizer.call(x + 1, pixel) } ] }.call([]) x = 0 while (x < @pix.width) x = @pix.vline_blank?(x) ? x + 1 : tokenizer.call(x, nil) end getter.call.map do |token| # Token.new.import(token.cutoff_vmargin.shrink) Token.new.import(token.cutoff_vmargin) end end # PixelMatrixのArrayを受け取り、数字を判別。 # tokens:: Array of PixelMatrix # returns:: String (判別結果) def stream_parse(tokens) r = [] tokens.inject(nil) do |prev, cur| r << cur.guess end rs = r.map {|x| x.to_s}.join('') if rs.length != 4 then if DEBUG then puts '- guess failed. dumping guess result of each token:' tokens.each_index do |i| print "##{i}: " pp tokens[i].candidate end puts end return nil end return rs end class Token @@digits = nil attr_accessor :candidate def initialize if @@digits.nil? then # 文字画像サンプルを作っておく @@digits = DIGITS_ASSOC.map {|assoc| PixelMatrix.new(0, 0, true).import_assoc(assoc) } end @candidate = Hash.new end # PixelMatrixを受け取り、文字画像サンプルと比較して # 一致率を計算しておく。 # pixel:: PixelMatrix # returns:: self def import(pixel) gcd = lambda {|a, b| a, b = [b, a] if a < b return a if b == 0 r = a % b return gcd.call(b, r) } lcm = lambda {|a, b| a * b / gcd.call(a, b) } mul_to_lcm = lambda {|a, b| g = gcd.call(a, b) [b / g, a / g] } 0.upto(@@digits.size - 1) do |i| if (@@digits[i].width - pixel.width).abs > 4 or (@@digits[i].height - pixel.height).abs > 4 then @candidate[i] = -1 # 比較対象とサイズが違いすぎ next end mul_ax, mul_bx = mul_to_lcm.call(@@digits[i].width, pixel.width) mul_ay, mul_by = mul_to_lcm.call(@@digits[i].height, pixel.height) enlarged_width = @@digits[i].width * mul_ax enlarged_height = @@digits[i].height * mul_ay # 文字画像サンプルと比較対象画像のサイズをあわせる # 幅・高さをそれぞれ適当に整数倍して、最小公倍数に合わせて比較 # (めんどうだから) correct_bits = 0 (0...enlarged_width).each do |x| (0...enlarged_height).each do |y| if @@digits[i][x/mul_ax, y/mul_ay] == pixel[x/mul_bx, y/mul_by] then correct_bits += 1 end end end @candidate[i] = correct_bits * 100 / (enlarged_width * enlarged_height) end return self end # importのときの比較結果をもとに文字を推測 # returns:: Fixnum or nil(失敗時) def guess digit, ratio = @candidate.sort {|a, b| a.last <=> b.last}.last digit = nil if ratio < 0 or ratio < 80 return digit end end end #= 画素マトリックスクラス # 画像ファイルを食わせると、各ピクセル(画素)を2値(black(1) or white(0))に # 変換して、内部で保持する。 # 以後、Matrixクラスのような感じで個々の画素にアクセスできる。 class PixelMatrix BLACK = 1 WHITE = 0 attr_accessor :width attr_accessor :height # width:: 幅 # height:: 高さ # is_flexible:: 自動的に伸張するか def initialize(width = 0, height = 0, is_flexible = false) @matrix = Hash.new {|hash, key| hash[key] = Hash.new(WHITE)} @width, @height, @flexible = width, height, is_flexible end # file:: 画像ファイル名のパス # brightness_threshold:: 画素を黒とみなす閾値 (0 - 255, default: 0x40) # returns:: self (DeCAPTCHA::PixelMatrix) def import(file, brightness_threshold = 0x40) gd = GD2::Image.import(file) @width, @height = gd.width, gd.height self.each_with_axis do |x, y| color = gd[x, y] greyscale = (color.red + color.green + color.blue) / 3 self[x, y] = (greyscale > brightness_threshold) ? WHITE : BLACK end return self end # reverse function of to_assoc def import_assoc(assoc) assoc.inject(0) do |y, columns| columns.inject(0) do |x, color| self[x, y] = color x + 1 end y + 1 end return self end # PixelMatrixを画像ファイルとしてexport # file:: 新たに作る画像ファイル名のパス def export(file) gd = GD2::Image::IndexedColor.new(@width, @height) gd.palette << GD2::Color::WHITE gd.palette << GD2::Color::BLACK self.each_with_axis do |x, y| gd[x, y] = { WHITE => GD2::Color::WHITE, BLACK => GD2::Color::BLACK, }[self[x, y]] end gd.export(file) return self end def to_assoc (0...@height).map do |y| (0...@width).map do |x| self[x, y] end end end # 指定された位置の画素を返す。 # returns:: PixelMatrix::BLACK(1) or WHITE(0) def [](x, y) if !@flexible and !in_range?(x, y) then raise RangeError end return @matrix[y][x] end # 画素に値を設定。 # returns:: PixelMatrix::BLACK(1) or WHITE(0) def []=(x, y, val) unless in_range?(x, y) then raise RangeError unless @flexible @width = (x >= @width) ? x + 1 : @width @height = (y >= @height) ? y + 1 : @height end @matrix[y][x] = val end def in_range?(x, y) ((0...@width) === x and (0...@height) === y) end # 指定された軸をもとに画素を走査し、Arrayに変換。 # 例えば、to_a(:vertical, 10) とすると、x == 10 な列を取り出して # Arrayにして返す。 # # axis:: 軸を指定 (:vertical または :horizontal) # pos:: 位置を指定。_axis_で指定した軸と直交する軸における位置を指定。 def to_a(axis, pos) {:vertical => lambda { (0...@height).map {|y| self[pos, y]} }, :horizontal => lambda { (0...@width).map {|x| self[x, pos]} }, }[axis].call end # returns:: Array def hline(y) self.to_a(:horizontal, y) end # returns:: Array def vline(x) self.to_a(:vertical, x) end # X軸方向に画素を走査。 # y:: どの位置で走査するか # returns:: 指定された軸の上にドットが存在: false, 無い: true def hline_blank?(y) hline(y).find {|color| color == BLACK }.nil? ? true : false end # Y軸方向に画素を走査。 # x:: どの位置で走査するか # returns:: 指定された軸の上にドットが存在: false, 無い: true def vline_blank?(x) vline(x).find {|color| color == BLACK }.nil? ? true : false end # 上下のマージンを削除した新しいPixelMatrixを返す。 # returns:: PixelMatrix def cutoff_vmargin pixel = PixelMatrix.new(0, 0, true) head = 0.upto(self.height - 1) do |y| break(y) if !self.hline_blank?(y) end tail = (self.height - 1).downto(0) do |y| break(y) if !self.hline_blank?(y) end head.upto(tail) do |y| y0 = pixel.height self.hline(y).inject(0) do |x, color| pixel[x, y0] = color x + 1 end end return pixel end def each_with_axis (0...@width).each {|x| (0...@height).each {|y| yield(x, y)}} end end end class DeCAPTCHA::Site::YourFileHost::Token DIGITS_ASSOC = [ # 0 [[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0], [0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0], [0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0], [0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0], [0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0], [0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0], [0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0], [1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0], [0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0], [0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0], [0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0], [0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0] ], # 1 [[0, 0, 0, 0, 1], [0, 0, 1, 1, 1], [1, 1, 1, 1, 1], [1, 1, 1, 1, 1], [1, 0, 0, 0, 1], [0, 0, 0, 0, 1], [0, 0, 0, 0, 1], [0, 0, 0, 0, 1], [0, 0, 0, 0, 1], [0, 0, 0, 0, 1], [0, 0, 0, 0, 1], [0, 0, 0, 0, 1], [0, 0, 0, 0, 1], [0, 0, 0, 0, 1], [0, 0, 0, 0, 1], [0, 0, 0, 0, 1], [0, 0, 0, 0, 1], [0, 0, 0, 0, 1], [0, 0, 0, 0, 1], [0, 0, 0, 0, 1]], # 2 [[0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0], [0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0], [0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1], [1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1], [0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1], [0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0], [0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0], [0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0], [0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0], [0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0], [0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0], [0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0], [0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0], [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0]], # 3 [[0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0], [0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0], [0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0], [0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0], [0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1], [1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0], [0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0], [0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0]], # 4 [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1], [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1], [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1], [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1], [0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1], [0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1], [0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1], [0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1], [0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1], [0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1], [0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1], [0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1], [0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1], [0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1], [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1]], # 5 [[0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0], [0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0], [0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0], [0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0], [0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0], [0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0], [0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1], [1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0], [0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0], [0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0], [0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0], [0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0]], # 6 [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0], [0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0], [0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0], [0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0], [0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0], [0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0], [0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0], [1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0], [1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0], [0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0], [0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0], [0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0]], # 7 [[0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1], [0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1], [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0], [0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0], [0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]], # 8 [[0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0], [0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0], [0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0], [0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0], [0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0], [0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0], [0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0], [0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0], [0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0], [0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0], [0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0], [1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1], [1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1], [1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0], [0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0], [0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0], [0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0], [0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]], # 9 [[0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0], [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0], [0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0], [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0], [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0], [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1], [0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1], [0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1], [0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1], [0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0], [0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0], [0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0], [0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0], [0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0], [0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]], ] end __END__ Dir.glob('*.gif').each do |file| puts "Processing file: #{file}" p DeCAPTCHA.decode(file) end __END__
おー、使ってくれてる奇特な奴がいるとはうれしいねぇ。
感謝の気持ちを込めて実はアレから少しバージョンアップしてるのでそれを公開しますよ!
改善点は2点。
これを修正。これ微妙なんだよね。4u.pl動かしてる最中に画像が投稿されるとページングしたときに既に取得した画像にぶつかってしまって止まっちゃうんだよねー。
なので、最後に取得した画像にぶつかったらプログラム終了するように変更した。
元のURLの画像が削除されてしまって取得できなかった場合に、今までは.plainとかいうダミーデータが保存されてしまっていたが、それを4Uの画像を取得するように変更。
これで元画像が消えてても一応4Uから取得できるので取りこぼしが無くてヤッターって感じだねー。
でわでわコードは以下。
#!/usr/local/bin/perl -w use strict; use warnings; use Web::Scraper; use URI; use Perl6::Say; use MIME::Type; use LWP::UserAgent; use Path::Class; use Data::Dumper;sub p { print Data::Dumper::Dumper(@_) }; my $page = shift || 10000; unless ( $page =~ /^\d+$/ ) { die 'perl 4u.pl [page as int]'; } my @files = dir('./img/')->children; my $cache = {}; my $end_file = { mtime => 0 , file => '' }; for my $file (@files) { if ( $file->basename =~ /^(.+)\.(.+)$/ ) { $cache->{$1} = $2; } if ( $end_file->{mtime} < $file->stat->mtime ) { $end_file->{mtime} = $file->stat->mtime; $end_file->{file} = $file; } } for my $i (1..$page) { my $url = sprintf 'http://4u.straightline.jp/?page=%s' , $i; say "request url>".$url; my $tmp = scraper { process 'ul.entry-list>li>div.entry-body>div.entry-photo>a', 'link[]' => '@href'; process 'ul.entry-list>li>div.entry-footer>div.wrapper-entry-description>div.entry-description>p.entry-img-src', 'img[]' => 'TEXT'; result 'link','img'; }->scrape(URI->new($url)); my $links = $tmp->{link}; my $imgs = $tmp->{img}; if ( ref $links ne 'ARRAY' ) { say "end program."; exit; } for my $link (@$links) { $link =~ m{/([^/]+)$}; my $sesid = $1; if ( $end_file->{file} && $end_file->{file}->basename =~ /^$sesid\./ ) { say "file exsits end program >".$sesid; exit; } if ( $cache->{$sesid} ) { say "file exsits next >".$sesid; next; } sleep 1; my $image_url = shift @$imgs || next; $image_url = 'http://'.$image_url; say "get image url >".$image_url; my $ua = LWP::UserAgent->new; my $req = HTTP::Request->new(GET => $image_url); my $res = $ua->request($req); my $content = $res->content; my $content_type = $res->headers->header('content-type'); my $ext = MIME::Type->new( type => $content_type )->subType || 'bin'; if ( $ext eq 'plain' ) { say "not found image >".$image_url; # 本家の画像が消えてたら4Uの奴を保存する。 my $image_url = 'http://www.straightline.jp/html/found/static/upload/l/l_'.$sesid.'.jpg'; say "get 4u image url >".$image_url; my $req = HTTP::Request->new(GET => $image_url); my $res = $ua->request($req); $content = $res->content; $ext = 'jpeg'; } my $write_path = './img/'.$sesid.'.'.$ext; open my $FH, '>', $write_path; binmode $FH; print $FH $content; close $FH; say "write image >".$write_path; } }
#! /bin/csh -f ##処理選択 echo "処理を選んでください" echo "1 Dir生成" echo "2 Dir削除" echo " " echo -n "No入力 1 or 2 :" set num <$ ##入力エラー処理 ##1でない or 2でない場合はエラー出してシェル再読み込み if [ $num != 1 -a $num != 2 ] ; then echo "入力エラー。1か2を入力してください" select.csh fi ##以下numは1か2 ##実行許可入力 if [ $num = 1 ] ; then echo "1 Dir生成を実行します Y or N" echo -n "Y or N を入力してください" set Ans <$ fi if [ $num = 2 ] ; then echo "2 Dir削除を実行します Y or N" echo -n "Y or N を入力してください" set Ans <$ fi ##入力エラー処理 ##Yでない or Nでない場合はエラーを出してシェル再読み込み if [ $Ans != Y -a $Ans != N ] ; then echo "入力エラー。YかNを入力してください" select.csh fi ##以下AnsはYかN ##シェル選択&実行 if [$num =1 -a Ans = Y] ; then source kadai2.csh echo "Dir生成が終了しました" fi if [$num =2 -a Ans = Y] ; then source del.csh echo "Dir削除が終了しました" fi
71 フジTV JAL/ANA(パイロット) モルガンスタンレー BCG
70日テレ講談社野村證券(IB/リサーチ)MRINRI(コンサル)メリルリンチJPモルガン
69 TBS 三菱商事小学館三井不動産三菱地所DIR(リサーチ)
68 電通 テレ朝 朝日新聞集英社JBICDPKDBJ三井物産リーマンUBS 日興citi
67 JAICA テレ東博報堂読売新聞共同通信準キーJR東海日本郵船みずほ(GCF/証券)東証アクセンチュア(戦)P&G(マーケ)
66 東電 NHK 住友商事時事通信毎日新聞新日鐵ANAソニー旭硝子 新日石農中味の素
65 JAL 本田技研商船三井任天堂東急不関電東京ガス新潮社産経麒麟麦酒松下電器信越ソニーMEドコモ富士フイルム
64 JETRO 東京建物伊藤忠JASRAC地方電力JR東大ガス住友不三菱重工旭化成サントリーJFE大和SMBC東京海上
63P&G(非マーケ)三菱化学丸紅シェルオラクル三菱UFJ信託新生銀(IB) 東宝JRA日本IBMシャープキヤノン日産 DI
62 JR西メトロ川崎重工アサヒ信金中金日本生命松竹NTTデータリクルート日立富士ゼロリコー三井化学住友化学
61 森ビル ADK東芝マイクロソフト住友信託地方局IBCS日本HP NRI(SE)
60 住友金属神戸製鋼みずほ信託鹿島三菱電機豊田通商東レコニミノコマツニコン
59 NTTコム大成豊田織機資生堂マツダ住友電工オリンパス松下電工三菱東京UFJ
58 MS海上新政府系金融日東電工帝人三菱マテリアル住友3MNTT東西KDDI 清水