<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>#8 &#187; Tech</title>
	<atom:link href="http://jinim.jp/topics/tech/feed" rel="self" type="application/rss+xml" />
	<link>http://jinim.jp</link>
	<description>from Tokyo</description>
	<lastBuildDate>Tue, 15 May 2012 08:08:21 +0000</lastBuildDate>
	<language>ja</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.2</generator>
		<item>
		<title>WordPressテーマ Codium Extend の日本語翻訳ファイル</title>
		<link>http://jinim.jp/archives/2343</link>
		<comments>http://jinim.jp/archives/2343#comments</comments>
		<pubDate>Fri, 09 Sep 2011 03:04:12 +0000</pubDate>
		<dc:creator>eight</dc:creator>
				<category><![CDATA[Tech]]></category>
		<category><![CDATA[WordPress]]></category>

		<guid isPermaLink="false">http://jinim.jp/?p=2343</guid>
		<description><![CDATA[頼まれてセットアップしたサイトで使ったCodium Extendテーマがシンプルでいいなあと思ったので、ここでも使ってみることにしました。 そのサイトではできるだけ英語は出てきて欲しなくて、日本語の翻訳ファイルを作ったの &#8230; <a href="http://jinim.jp/archives/2343">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>頼まれてセットアップしたサイトで使った<a href="http://wordpress.org/extend/themes/codium-extend" title="Codium Extend">Codium Extend</a>テーマがシンプルでいいなあと思ったので、ここでも使ってみることにしました。</p>
<p>そのサイトではできるだけ英語は出てきて欲しなくて、日本語の翻訳ファイルを作ったのでここで公開しておきます。</p>
<p>   Codium Extend ver.1.0.9用の日本語翻訳ファイル： <a href='http://jinim.jp/wp-content/uploads/2011/09/codium-extend_ja.zip'>codium-extend_ja.zip</a></p>
<p>このzipファイルを解凍して、ja.moファイルをwp-content/themes/codium-extend/languages/に置けば使えるはずです。ja.poファイルの最新版は<a href="https://gist.github.com/1205390">Gist:1205390</a>で公開しておきます。どうぞ自由にお使い下さい。</p>
<p>バージョンアップに追随できるかどうか心配なのでこのサイトは英語にするかも。</p>
<div style='clear:both'></div>]]></content:encoded>
			<wfw:commentRss>http://jinim.jp/archives/2343/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Linodeからさくらインターネットへ（一部）移行した理由</title>
		<link>http://jinim.jp/archives/2308</link>
		<comments>http://jinim.jp/archives/2308#comments</comments>
		<pubDate>Tue, 12 Oct 2010 09:01:24 +0000</pubDate>
		<dc:creator>eight</dc:creator>
				<category><![CDATA[Tech]]></category>
		<category><![CDATA[Linode]]></category>
		<category><![CDATA[さくらインターネット]]></category>

		<guid isPermaLink="false">http://jinim.jp/?p=2308</guid>
		<description><![CDATA[今年の3月にさくらインターネットからLinodeへ移行した理由というエントリを書いた。内容は専用サーバを解約してLinodeにすべてのサイトを移行した理由を連ねたもの。このエントリでは半年後の9月に一部のサイトをさくら（ &#8230; <a href="http://jinim.jp/archives/2308">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>今年の3月に<a href="http://jinim.jp/archives/1829">さくらインターネットからLinodeへ移行した理由</a>というエントリを書いた。内容は専用サーバを解約してLinodeにすべてのサイトを移行した理由を連ねたもの。このエントリでは半年後の9月に一部のサイトをさくら（のVPS）に戻した理由を書いておくことにした。次に何か別のサービスが出てきたときに見返すためにも。<br />
<span id="more-2308"></span><br />
<a href="http://www.linode.com/?r=e9b1eb595b0c21f969438f1efb5e862df08d5f7f">Linode</a>は管理するための機能が洗練されていてとても使いやすい。<a href="http://itunes.apple.com/jp/app/linode-manager/id352861751">iPhone/iPod Touch用の管理ツール</a>まであってこの出来もすばらしい。</p>
<p>が、日本に一番近いデータセンターでもやはり遅延が気になる。AdSenseで稼ぎ頭のサイトが4月以降20％ほど稼ぎが減ったのは、遅延が理由じゃないかと推測している。特にたくさんのアクセスがあるサイトほど（＝稼ぎのいいサイトほど）、遅延が影響しているように感じる。感じる、気になるばかりだけれど、ちゃんと計測したわけではないので。<br />
将来Linodeが日本にデータセンターを設置することも考えにくい。</p>
<p>7月にさくらインターネットがVPSサービスのベータテストを始めたときに、すぐに申し込んだ。一番アクセスの多いサイトのシステムをセットアップして、負荷テストをしてみたところかなり速いことがわかった。特にネットワークはさすがに速い。移行に乗り気になっていたのだけれど、この時点では価格が公表されていなかったので様子見。</p>
<p>その後、サービス名がVPS980ということがわかって、一気に乗り気になる。だって980円/月ってことだよね。サービスはこの円高の中でもLinodeの一番安いメモリ、ディスクが同程度のサービスのだいたい半額かあ。9月の正式発表を待って移行決定。</p>
<p>結局、</p>
<ul>
<li>Linodeに移行したサイトのうち一番稼いでいるサイトだけをさくらのVPSに移行。</li>
<li>Linodeで借りていたメモリ2GBのコースを1GBのコースに変更。</li>
</ul>
<p>という構成に落ち着き、9月4日にはさくらのVPSで本番稼働をはじめた。</p>
<p>この移行作業で、</p>
<ul>
<li>月々の支払いは約8千円弱から約5千円弱に圧縮できた。</li>
<li>某サイトのアクセスが8月よりも30％ほど伸びた＝今年最高（季節要因もある）。</li>
<li>某サイトの9月のAdSenseの稼ぎが今年最高を記録した（季節要因もある）。</li>
</ul>
<p>という成績。概ね移行は成功だった模様。</p>
<p>さくらのVPSに全部移行していないのは、</p>
<ul>
<li>LinodeのDNS Manager（とDNSサーバの管理）が秀逸で千円/月ぐらいはこのシステムの使用料のつもり。</li>
<li>他にも6つ運用しているサイトは遅延がそれほど問題にはならない（そんなにAdSenseにもアクセス数にも影響していない）。</li>
<li>VPS980では全部のサイトを動かすにはメモリが足りない。VPSを分けると増えすぎて今度は管理が面倒。</li>
<li>今後さくらのVPSで別メニューがでてきたら、再考すればいいよね。</li>
</ul>
<p>といった感じ。</p>
<p>先のエントリにも書いたけれど、そもそも、VPSの利点を生かせないこととコストの問題を除けば、さくらインターネットの品質、サービスには満足していた。さくらのVPSのサービス開始で先のエントリに書いた僕の不満はほぼ解消された。管理インターフェースのブラッシュアップと、早期の上位サービスの提供は期待したいところだけれど。</p>
<div style='clear:both'></div>]]></content:encoded>
			<wfw:commentRss>http://jinim.jp/archives/2308/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>-（ハイフン）で始まるファイルがrmで消せない</title>
		<link>http://jinim.jp/archives/2255</link>
		<comments>http://jinim.jp/archives/2255#comments</comments>
		<pubDate>Fri, 17 Sep 2010 00:21:13 +0000</pubDate>
		<dc:creator>eight</dc:creator>
				<category><![CDATA[Tech]]></category>
		<category><![CDATA[Tips]]></category>

		<guid isPermaLink="false">http://jinim.jp/?p=2255</guid>
		<description><![CDATA[ちゃちゃっとWEBサーバの出力を確認しようとしてwgetの出力を標準出力にするつもりを、手が滑って”&#8211;”としてしまった。結果、”&#8211;”というファイルができてしまった。 $ wget http://l &#8230; <a href="http://jinim.jp/archives/2255">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>ちゃちゃっとWEBサーバの出力を確認しようとしてwgetの出力を標準出力にするつもりを、手が滑って”&#8211;”としてしまった。結果、”&#8211;”というファイルができてしまった。<br />
$ wget http://localhost/ -O &#8211;<br />
削除しようにも、rm &#8211;ではシェルがオプションと解釈してしまって削除できない。<br />
どうすべぇと調べてみたら、”&#8211;”の後にファイル名(&#8211;)を指定するといいみたい。</p>
<pre class="brush:bash">
$ touch -- -cantremove
$ ls
-cantremove
$ rm -cantremove
rm: invalid option -- 'c'
Try `rm ./-cantremove' to remove the file `-cantremove'.
Try `rm --help' for more information.
$ rm *
rm: invalid option -- 'c'
Try `rm ./-cantremove' to remove the file `-cantremove'.
Try `rm --help' for more information.
$ rm -- -cantremove
$ ls
$
</pre>
<p>を、rmのメッセージによると、「rm ./- 」でも良かったんだ。<br />
まだまだ知らないことがたくさんある。</p>
<div style='clear:both'></div>]]></content:encoded>
			<wfw:commentRss>http://jinim.jp/archives/2255/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Ubuntu 10.04にaptでRedmineをセットアップ</title>
		<link>http://jinim.jp/archives/2242</link>
		<comments>http://jinim.jp/archives/2242#comments</comments>
		<pubDate>Fri, 10 Sep 2010 04:03:19 +0000</pubDate>
		<dc:creator>eight</dc:creator>
				<category><![CDATA[Tech]]></category>

		<guid isPermaLink="false">http://jinim.jp/?p=2242</guid>
		<description><![CDATA[管理しているリポジトリをささっと見渡したり、プロジェクトのタスク管理にRedmineはとても便利。しばらくサーバの移転やなんやかんやでちゃんと動く自前のRedmineを持っていなかった。 今回、Linodeで借りているU &#8230; <a href="http://jinim.jp/archives/2242">Continue reading <span class="meta-nav">&#8594;</span></a>
Related posts:<ol>
<li><a href='http://jinim.jp/archives/1646' rel='bookmark' title='Ubuntu 9.04 serverを9.10へアップグレード'>Ubuntu 9.04 serverを9.10へアップグレード</a></li>
</ol>]]></description>
			<content:encoded><![CDATA[<p>管理しているリポジトリをささっと見渡したり、プロジェクトのタスク管理に<a href="http://www.redmine.org/" target="_blank">Redmine</a>はとても便利。しばらくサーバの移転やなんやかんやでちゃんと動く自前のRedmineを持っていなかった。<br />
今回、<a href="http://www.linode.com/?r=e9b1eb595b0c21f969438f1efb5e862df08d5f7f">Linode</a>で借りているUbuntuにRedmineをセットアップすることにした。<br />
一人で使うのであんまり凝ったこともしたくないので、aptでさくっといれよう。&#8230;が、２０分ぐらいハマった。<br />
ソースから最新版を入れる手順はあちこちで見つかるのだけど、aptでUbuntuのパッケージからMySQLの環境に入れるときの注意点としてメモ。<br />
<span id="more-2242"></span></p>
<ul>
<li>MySQLの照合順序がデフォルトではlatin1_swedish_ciになる。</li>
<li>aptのRedmine設定ではMySQLの照合順序を意識していない。</li>
<li>latin1_swedish_ciのデータベースにテープルを作るので、テーブルの照合順序もlatin1_swedish_ciになる。</li>
<li>データベース作成、テーブル作成が済んだ後で、初期投入されるトラッカーやロールの日本語文字が化ける。</li>
</ul>
<p>ということらしい。</p>
<p>結局、以下の手順でなんとかなった。</p>
<ol>
<li>apt-get install redmineで一旦最後まで導入。次にテーブルを全部削除。データベースは削除しない。（あるいはデータベース毎削除しておいてCREATE DATABASEしてもいいと思う。）</li>
<li>データベースの照合順序をutf8_general_ciに変更する。
<pre>
ALTER DATABASE  `redmine_default` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
</pre>
</li>
<li>dpkg-reconfigure redmine を実施。データベースの作成の処理はすでに存在しているので、スキップされ、テーブルが作成される。このとき、先に指定したデーベースの照合順序utf8_general_ciが使われる。</li>
<li>reconfigureによって正しい照合順序が設定されたテーブルに初期データが投入される。</li>
</ol>
<p>aptのMySQLのデータベース作成、テーブル作成スクリプト部分に照合順序をutf8_general_ciにするように書いといてもらうことはできないものかな。<br />
latin1で問題がでる場合はあっても、utf8で問題がでる場合はほとんどないような気がするのだけど。なんか理由があるのかもしれない。</p>
<div style='clear:both'></div><p>Related posts:</p><ol>
<li><a href='http://jinim.jp/archives/1646' rel='bookmark' title='Ubuntu 9.04 serverを9.10へアップグレード'>Ubuntu 9.04 serverを9.10へアップグレード</a></li>
</ol>]]></content:encoded>
			<wfw:commentRss>http://jinim.jp/archives/2242/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Xperiaは見送り。iPod Touch + WiMAXルータでiPad待ち？</title>
		<link>http://jinim.jp/archives/2163</link>
		<comments>http://jinim.jp/archives/2163#comments</comments>
		<pubDate>Mon, 05 Apr 2010 02:51:12 +0000</pubDate>
		<dc:creator>eight</dc:creator>
				<category><![CDATA[Life]]></category>
		<category><![CDATA[Tech]]></category>
		<category><![CDATA[Apple]]></category>
		<category><![CDATA[WiMAX]]></category>

		<guid isPermaLink="false">http://jinim.jp/?p=2163</guid>
		<description><![CDATA[43歳の誕生日。自分プレゼント、どうしようかなあ。 Xperiaは見送り決めたし、iPhoneはいまさら感もあってのれないし。 それなら、iPod Touch + WiMAXルータで、iPadが出てくるのを待ってみるのは &#8230; <a href="http://jinim.jp/archives/2163">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>43歳の誕生日。自分プレゼント、どうしようかなあ。<br />
Xperiaは見送り決めたし、iPhoneはいまさら感もあってのれないし。<br />
それなら、iPod Touch + WiMAXルータで、iPadが出てくるのを待ってみるのはどうだ。<br />
時々持ち出すMacBookでも使えるじゃないか。<br />
僕の使い方ならWiMAXはとてもいいのは、もうすでに<a href="http://jinim.jp/archives/1357">Try WiMAX</a>で経験済みなんだから。<br />
ちょっと書き出してみよう。<br />
<span id="more-2163"></span><br />
初期： 18,810円 iPod Touch + 16,749円 AtermWM3300R = 35,559円<br />
月額： 4,480円 UQ WiMAX</p>
<p>月額でマイナスできるのは、ドコモの基本料、通話料以外の約5,400円 （パケホーダイダブル4,200円 + Ｕスタンダードプラン500円 + その他 700円）。<br />
単純に月々の通信費は1,000円ぐらいマイナスにできるな。ワイヤレスゲート（380円/月）もあった。</p>
<p>この分をSkypeにまわせるなあ。アレ、ドコモは止めてもいいのかも。通話料が毎月200円以下なんて。ああ、待ち受け時間の問題が残るか。WiMAXルータにケータイみたいなバッテリの持ちは期待できないなあ。なんかしらケータイはもっとかないとダメか。<br />
あとカメラは&#8230;WiFiカメラっ。<br />
そうだ、GPSが使えないか。ってことは、GoogleマップとGPSの連動したやつも使えないのか。ちょっと残念。<br />
あと、荷物増えるな。</p>
<p>持ち運ぶデバイスと回線を分離できるのは、エンジニアとしては良い感じがするなあ。心地よい。<br />
Kindleが欲しくなっても、iPadにしても、ほかのAndroid端末でも追加できるもんなあ。<br />
でも、やっぱりいろいろひっかかるところも多い。どうしたものか。</p>
<p>p.s.<br />
今ふと、はっ、僕はこんなにがんばってネット接続が必要なのか？これはなんだかがんばりすぎじゃないか？と思った。</p>
<table style="border:0;">
<tr>
<td>
<iframe src="http://rcm-jp.amazon.co.jp/e/cm?t=jinim-22&#038;o=9&#038;p=8&#038;l=as1&#038;asins=B002OB3FJQ&#038;fc1=000000&#038;IS2=1&#038;lt1=_blank&#038;m=amazon&#038;lc1=0000FF&#038;bc1=000000&#038;bg1=FFFFFF&#038;f=ifr" style="width:120px;height:240px;" scrolling="no" marginwidth="0" marginheight="0" frameborder="0"></iframe>
</td>
<td>
<iframe src="http://rcm-jp.amazon.co.jp/e/cm?t=jinim-22&#038;o=9&#038;p=8&#038;l=as1&#038;asins=B002UUQ8B8&#038;fc1=000000&#038;IS2=1&#038;lt1=_blank&#038;m=amazon&#038;lc1=0000FF&#038;bc1=000000&#038;bg1=FFFFFF&#038;f=ifr" style="width:120px;height:240px;" scrolling="no" marginwidth="0" marginheight="0" frameborder="0"></iframe>
</td>
</tr>
</table>
<div style='clear:both'></div>]]></content:encoded>
			<wfw:commentRss>http://jinim.jp/archives/2163/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Simple HTTP Checker &#8211; シンプルなHTTPサーバの監視ツール</title>
		<link>http://jinim.jp/archives/2136</link>
		<comments>http://jinim.jp/archives/2136#comments</comments>
		<pubDate>Thu, 25 Mar 2010 06:33:38 +0000</pubDate>
		<dc:creator>eight</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[Tech]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://jinim.jp/?p=2136</guid>
		<description><![CDATA[WEBサイトの死活監視のサービスはいろいろあるけれど、どれも監視できるURL数に制限があったり、制限を解除してもらうには費用がかかるわけなのだけれど求める以上の機能があってちょっと高くついたり。なかなかピッタリこない。  &#8230; <a href="http://jinim.jp/archives/2136">Continue reading <span class="meta-nav">&#8594;</span></a>
Related posts:<ol>
<li><a href='http://jinim.jp/archives/511' rel='bookmark' title='urllib2でプロキシを参照しないようにする'>urllib2でプロキシを参照しないようにする</a></li>
<li><a href='http://jinim.jp/archives/519' rel='bookmark' title='urllib2.quote()ってアリなんだ'>urllib2.quote()ってアリなんだ</a></li>
<li><a href='http://jinim.jp/archives/1527' rel='bookmark' title='Flickrから自分のアップロードした写真を全部ダウンロードする'>Flickrから自分のアップロードした写真を全部ダウンロードする</a></li>
</ol>]]></description>
			<content:encoded><![CDATA[<p>WEBサイトの死活監視のサービスはいろいろあるけれど、どれも監視できるURL数に制限があったり、制限を解除してもらうには費用がかかるわけなのだけれど求める以上の機能があってちょっと高くついたり。なかなかピッタリこない。</p>
<p>仕方がない、さくらのレンタルサーバが1つあるのでそこで監視するようにしてみよう。社内のサーバ監視をしているNagiosは便利なんだけれど、さくらの500円/月のレンタルサーバに入れるのはちょっとアレだし、必要最小限のスクリプトをPythonで書くことにする。</p>
<p>求めた要件としては、</p>
<ul>
<li>HTTPで接続できなかったらメールでお知らせが届く。</li>
<li>一回メールを送ったら、しばらくはメールしないで欲しい。</li>
<li>HEADとGETとPOSTに対応。</li>
<li>HTTPステータスコードだけをチェックする（レスポンスに含まれるコンテンツのチェックは不要）。</li>
<li>設定ファイルで複数のURLをまとめてチェックして欲しい。</li>
<li>（さくらなので）常駐するデーモンではなくて、単独のコマンドで実行できる（cronで繰り返し実行）。</li>
<li>お知らせメールはcrontabのMAILTOで送るからstderrに出力してくれればいい。</li>
<li>OKだったときのログはstdoutに出力してくれればいい。</li>
<li>スクリプトは1ファイルで完結させる。</li>
<li>Python2.4以降、標準ライブラリだけで動く。</li>
</ul>
<p><span id="more-2136"></span><br />
使い方は、<br />
1. python htpchk.py URL<br />
とURLを引数に指定する方法。これだと細かい設定はできませんが、HEADでチェック、お知らせメールは多くて10分に1回、となります。</p>
<p>2. python htpchk.py htpchk.conf<br />
と引数に設定ファイルを指定する（あるいは引数指定を省略して、htpchk.pyと同じディレクトリにhtpchk.confという設定ファイルを置いておく）と、複数のURLを一括してチェックできるようになります。<br />
設定ファイルは、Windowsのiniファイルに良く似た書き方です。DEFAULTセクションは全セクションのデフォルト値として使われます。あとはチェックするURL毎にセクションを作ってurlパラメータを書いておくだけで1と同様にチェックはできます。セクション毎にDEFAULTセクションの値を上書きできるので、細かい変更がしたい場合はセクションに値を書きます。詳しい設定ファイルの書き方は後の方のサンプルをご覧ください。</p>
<p>cronにこのスクリプトを実行するように登録しておく（さくらのレンタルサーバではこんな感じ）。<br />
/home/example/bin/にhtpchk.pyとhtpchk.confを置いたとするとこんな感じ。</p>
<pre>
MAILTO=alert@example.com, mobile@example.com
# NAME: htpchck
*/5     *       *       *       *       /usr/local/bin/python /home/example/bin/htpchk.py >/dev/null
</pre>
<p>これで、5分に一回htpchk.confに書いてあるサイトをチェックして、HTTPステータスが200じゃなければ、標準エラーにメッセージが出力されて、そのメッセージはMAILTOに書いたメールアドレスに送られます。標準出力は/dev/nullに向けてあるので捨てられます。</p>
<p>手元では47のURLをチェックする設定ファイルを書いて運用中。概ね良好なんだけれど、まだチェックするURLを増やしたいのでもう少しチェックにかかる時間を短縮したい。HTTPのリクエストを送る部分をスレッドにして同時実行すれば速くなるのはわかっているので、困ったらスレッド化するかも。</p>
<p>以下はスクリプト本体（htpchk.py）と設定ファイル（htpchk.conf）のサンプルです。最新版は<a href="http://gist.github.com/343248">Gist:343248</a>に置いてあります。</p>
<p><strong>htpchk.py</strong></p>
<pre class="brush:python">
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""#8 Simple HTTP Checker
  Usage:
       htpchk (htpchk.conf is needed at same directory.)
       htpchk URL
       htpchk config-file
"""
__NAME__ = '#8 Simple HTTP Checker'
__VERSION__ = '1.0'
__ABOUT__ = 'http://jinim.jp/archives/2136'
__USER_AGENT__ = 'Mozilla/5.0 (compatible; %s/%s; +%s)' % (__NAME__, __VERSION__, __ABOUT__)
DATETIME_FORMAT = "%Y-%m-%d %H:%M:%S"

import os
import sys
import time
import urllib2
from urllib2 import HTTPError
import urlparse
import tempfile
from ConfigParser import ConfigParser

#url to filename with sha hash.
try:
    import hashlib
    def _urlhash_filename(url): return hashlib.sha224(url).hexdigest()
except:
    import sha
    def _urlhash_filename(url): return sha.new(url).hexdigest()

opener = urllib2.build_opener()
opener.addheaders = [('User-agent', __USER_AGENT__)]
urllib2.install_opener(opener)

class ParamError(Exception): pass

class HeadRequest(urllib2.Request):
    def get_method(self): return "HEAD"

class Site(object):
    def __init__(self, name, url, notify_interval=60*10, method="HEAD", data=None, wait_seconds=0):
        """When medhod is POST, data is requred."""
        self.name = name
        self.url = url
        self.method = method
        self.data = data
        self.notify_interval = notify_interval
        self.wait_seconds = wait_seconds
        self.notified = os.path.join(tempfile.gettempdir(), "htpcheck-%s" % _urlhash_filename(self.url))

    def check(self):
        if self.method=="HEAD":
            u = urllib2.urlopen(HeadRequest(self.url))
        elif self.method=="POST":
            u = urllib2.urlopen(self.url, data=self.data)
        elif self.method=="GET":
            u = urllib2.urlopen(self.url)
        else:
            raise ParamError, "method: %s not supported. Supported methods are (HEAD,GET,POST)." % self.method
        return u.info()

    def recovered(self):
        os.rename(self.notified, os.path.join(os.path.dirname(self.notified), os.path.basename(self.notified) + time.strftime("-recovered.%Y%m%d%H%M%S")))

    def notify(self, err):
        msg = log_message(self, err)
        last_notified = 0
        if os.path.exists(self.notified):
            try:
                last_notified = time.mktime(time.strptime(file(self.notified).readlines()[-1].split("\t")[0], DATETIME_FORMAT))
            except ValueError:
                last_notified = 0
        if time.time() > (last_notified + self.notify_interval):
            sys.stderr.write(msg)
            file(self.notified, 'a').write("%s\tnotified\n" % msg[:-1])
        else:
             sys.stdout.write(log_message(self, "[SUPPRESSED] %s" % err))

def log_message(site, msg=None):
    """if msg is not None, message means error.
    """
    if msg:
        format = '%s\tNG\t%s\t%s\t%s\t%s\n'
        return format % (time.strftime(DATETIME_FORMAT), site.name, site.method, site.url, msg)
    else:
        format = '%s\tOK\t%s\t%s\t%s\n'
        return format % (time.strftime(DATETIME_FORMAT), site.name, site.method, site.url)

def config_parse(conf):
    parser = ConfigParser()
    parser.readfp(open(conf))
    sites = list()
    for section in parser.sections():
        url = parser.get(section, 'url')
        method = parser.get(section, 'method')
        if method=="POST":
            data = parser.get(section, 'data')
        else:
            data = None
        notify_interval = parser.getfloat(section, 'notify_interval')
        wait_seconds = parser.getfloat(section, 'wait_seconds')
        sites.append(Site(section, url, notify_interval, method, data, wait_seconds))
    return sites

def main(sites):
    for site in sites:
        try:
            site.check()
            sys.stdout.write(log_message(site))
            if os.path.exists(site.notified):
                site.recovered()
        except HTTPError, err:
            site.notify(err)
        if site.wait_seconds>0: time.sleep(site.wait_seconds)

if __name__=='__main__':
    if len(sys.argv)>1: config = sys.argv[1]
    else: config = os.path.splitext(__file__)[0]+'.conf'

    if not os.path.exists(config):
        if config.startswith('http://') or config.startswith('https://'):
            name = urlparse.urlparse(config)[1].split(':')[0]
            sites = (Site(name, config), )
        else:
            raise ParamError, "config file %s not found." % config
    else:
        sites = config_parse(config)

    main(sites)
</pre>
<p><strong>htpchk.conf</strong></p>
<pre class="brush:plain">
[test_HEAD]
url: http://example.com/

[test_GET]
url: http://example.com/
method: GET

[test_POST]
url: http://example.com/
method: POST
data: Hello World

[test_notfound]
url: http://example.com/notfound.html
notify_interval: 10

[DEFAULT]
#************************************************
;  DEFAULT values
#************************************************

#Target URL.
#url=http://example.com/

#HTTP method
method: HEAD

#POST data
#data: Hello World

#When HTTP error occuered, repeatedly notified with interval seconds.
notify_interval: 600

#after checking, wait bellow seconds.
wait_seconds: 0
</pre>
<div style='clear:both'></div><p>Related posts:</p><ol>
<li><a href='http://jinim.jp/archives/511' rel='bookmark' title='urllib2でプロキシを参照しないようにする'>urllib2でプロキシを参照しないようにする</a></li>
<li><a href='http://jinim.jp/archives/519' rel='bookmark' title='urllib2.quote()ってアリなんだ'>urllib2.quote()ってアリなんだ</a></li>
<li><a href='http://jinim.jp/archives/1527' rel='bookmark' title='Flickrから自分のアップロードした写真を全部ダウンロードする'>Flickrから自分のアップロードした写真を全部ダウンロードする</a></li>
</ol>]]></content:encoded>
			<wfw:commentRss>http://jinim.jp/archives/2136/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>さくらインターネットからLinodeへ移行した理由</title>
		<link>http://jinim.jp/archives/1829</link>
		<comments>http://jinim.jp/archives/1829#comments</comments>
		<pubDate>Tue, 02 Mar 2010 07:10:03 +0000</pubDate>
		<dc:creator>eight</dc:creator>
				<category><![CDATA[Tech]]></category>
		<category><![CDATA[Linode]]></category>

		<guid isPermaLink="false">http://jinim.jp/?p=1829</guid>
		<description><![CDATA[さくらインターネットで借りている専用サーバからLinodeへ移行した。 現時点ではDNSの浸透待ちで一部のサイトは両方のサーバにアクセスがあるけれど、移行作業自体は全て完了した。 さくらの専用サーバは、約4年間順調に稼動 &#8230; <a href="http://jinim.jp/archives/1829">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>さくらインターネットで借りている専用サーバから<a href="http://www.linode.com/?r=e9b1eb595b0c21f969438f1efb5e862df08d5f7f">Linode</a>へ移行した。<br />
現時点ではDNSの浸透待ちで一部のサイトは両方のサーバにアクセスがあるけれど、移行作業自体は全て完了した。</p>
<p>さくらの専用サーバは、約4年間順調に稼動している。でもいろいろ不都合も出てきた。</p>
<ul>
<li>ロードアベレージが高い状態がずっと続いている（原因はWEBサイトへのアクセスが増えているから）。</li>
<li>4年経ったマシンのハードウエア障害がそろそろ心配。</li>
<li>管理するドメインの数が専用サーバに付いているDNSサービスの制限10件を超えた（DNSは自前で運用したくないのに仕方なく）。</li>
</ul>
<p>といった感じの不満と不安があった。そろそろ仮想マシンベースの安いサービスが出ないものかと半年ほどウォッチしたけれど&#8230;<br />
<span id="more-1829"></span><br />
実はLinodeのサービスは<a href="http://j.mp/98k0i0">UML</a>の頃にしばらく使ったことがある。当時から管理システムがとても良くできていて気に入っていたのだけど、遅延が大きいのとパフォーマンスの問題で、さくらに乗り換えた経緯がある。</p>
<p>でも、LinodeがXenベースに変ってパフォーマンスが向上していることが期待できるし、当時とはインターネットの状況も変っている。何よりハードウエア進化の恩恵を受けられるはず。さくらに比べれば遅延はあるだろうけれど、どうなってるだろう？という気になって、一番安いLinode360を借りて1週間ほどテストした。乗換えを決めた。</p>
<ul>
<li>うちの専用サーバに比べてCPUに負荷のかかる処理が劇的に速くなること（数倍から20倍ぐらい）。</li>
<li>以前のようには（7、8年前か？）遅延が気にならなくなった。</li>
<li><a href="http://library.linode.com/linode-manager/configuring-dns-with-the-linode-manager">DNS Manager</a>で無制限にドメインを管理できること。</li>
<li>ハードウエア障害の不安を実質的には解消できる。</li>
<li>安い。今回はデータベース用とフロント用に2台の構成にしても専用サーバ1台の半分程度。円高も効いている。</li>
<li>拡張性。数分で新たに仮想マシンを増やすことができるし、メモリ、ディスクの増設も対話的に完了する。専用サーバではこうはいかない。</li>
<li>さくらインターネットもサポート体制は良い会社だけれども、Linodeはもっと良いこと（英語だけど&#8230;）。</li>
<li>何より、妙な制限をしない。公開できる情報はすべて公開する。といった運営体質が気に入っている。</li>
</ul>
<p>実は、<a href="http://www.webfaction.com/">WebFaction</a>も実際に契約して試してみた。運用を任せられるのは安心できるし、サポートもとてもいい。が、WebFaction専用の知識がいろいろ必要なのが痛い。<br />
さくらの専用サーバからLinodeへの移行は通常のLinux管理の知識でいける。Linodeだから必要な知識というのがとても少ない。<br />
WebFactionへの移行となると、たくさんの英語のドキュメントを読んで使い方を理解しないといけない。良いサービスだと思うけど今回は断念した。</p>
<p>少なくとも1年（たぶんもっと）使うことになるだろうサービス。これからも折に触れてメモしておくつもり。<a href="http://www.linode.com/?r=e9b1eb595b0c21f969438f1efb5e862df08d5f7f">Linode</a>、おすすめです。</p>
<div style='clear:both'></div>]]></content:encoded>
			<wfw:commentRss>http://jinim.jp/archives/1829/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>営業日を判断するOracle PL/SQLパッケージ</title>
		<link>http://jinim.jp/archives/1715</link>
		<comments>http://jinim.jp/archives/1715#comments</comments>
		<pubDate>Thu, 04 Feb 2010 01:52:07 +0000</pubDate>
		<dc:creator>eight</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[Tech]]></category>
		<category><![CDATA[Oracle]]></category>

		<guid isPermaLink="false">http://jinim.jp/?p=1715</guid>
		<description><![CDATA[現実逃避から少しでもエンジンがかかるように、コードを公開してみよう。 OracleのPL/SQLで書いた営業日/稼働日判定用のストアード・パッケージ。いろいろと調べてみたのだけれど、ぴったりくるものが見当たらなくて書いて &#8230; <a href="http://jinim.jp/archives/1715">Continue reading <span class="meta-nav">&#8594;</span></a>
Related posts:<ol>
<li><a href='http://jinim.jp/archives/378' rel='bookmark' title='消費税を計算するOracle PL/SQLパッケージ'>消費税を計算するOracle PL/SQLパッケージ</a></li>
<li><a href='http://jinim.jp/archives/515' rel='bookmark' title='OracleでFIRST_DAY'>OracleでFIRST_DAY</a></li>
<li><a href='http://jinim.jp/archives/379' rel='bookmark' title='Oracle PL/SQLとUNIXタイムスタンプ'>Oracle PL/SQLとUNIXタイムスタンプ</a></li>
</ol>]]></description>
			<content:encoded><![CDATA[<p>現実逃避から少しでもエンジンがかかるように、コードを公開してみよう。</p>
<p>OracleのPL/SQLで書いた営業日/稼働日判定用のストアード・パッケージ。いろいろと調べてみたのだけれど、ぴったりくるものが見当たらなくて書いてみたもの。まだリリースまで時間があって、それほどテストされていないけれど、そんなに複雑でもないので大丈夫ではないかと。IS_WORKDAYがCHARを返すのはカッコ悪いけれど、いろいろあってこういう仕様。直すのは簡単なので気になる人は直してください。</p>
<p>仕様としては、１）土曜日と日曜日は営業日じゃない、２）休日テーブル（holidays）に日付があったらそれは休日。wkd_pkg.is_workdayを直すことで、土曜日は営業日にしたり、水曜日を休日にしたりできるので、その辺りは適当に。仕様はExcelにあるworkdayとnetworkdayを参考にしているけれど、厳密には一緒じゃない（と思う）。</p>
<p>このパッケージには4つの関数があります。1つはオーバーロードしたものなので、実質的には３つ。</p>
<p>1. FUNCTION WORKDAY( i_startdate IN date, i_days IN number) RETURN DATE;<br />
  開始日からi_days営業日後の日付を返す、 i_daysが正数なら未来、負数なら過去、開始日は数えない。</p>
<p>2. FUNCTION IS_WORKDAY( i_date IN date) RETURN CHAR;<br />
  指定した日付が営業日ならYを返す。営業日じゃなければNを返す。</p>
<p>3. FUNCTION NETWORKDAY( i_startdate IN date, i_enddate IN date) RETURN NUMBER;<br />
  開始日と終了日の間に含まれる営業日の日数を返す。日数には開始日と終了日も含まれる。<br />
<span id="more-1715"></span><br />
コードはGistにおいてあります。 <a href="http://gist.github.com/294489">Gist: 294489</a></p>
<pre class="brush:sql">
CREATE OR REPLACE PACKAGE WKD_PKG AS
/*
 営業日パッケージ

 ※土曜、日曜が営業日の場合は、IS_WORKDAYを直す
 ※国民の祝日が営業日の場合は、休日テーブルを直す

-- 休日テーブル（祝祭日、お盆とか、都民の日とかも）
create table holidays (
    holiday date,
    primary key(holiday)
);
-- 2010年の国民の祝日を入れておく
-- ここが便利 http://cbdb.cybozu.co.jp/cgi-bin/db.cgi?page=DBView&#038;did=690
insert into holidays values(to_date('2010-01-01','YYYY-MM-DD')); --元日
insert into holidays values(to_date('2010-01-11','YYYY-MM-DD')); --成人の日
insert into holidays values(to_date('2010-02-11','YYYY-MM-DD')); --建国記念の日
insert into holidays values(to_date('2010-03-21','YYYY-MM-DD')); --春分の日
insert into holidays values(to_date('2010-03-22','YYYY-MM-DD')); --振替休日
insert into holidays values(to_date('2010-04-29','YYYY-MM-DD')); --昭和の日
insert into holidays values(to_date('2010-05-03','YYYY-MM-DD')); --憲法記念日
insert into holidays values(to_date('2010-05-04','YYYY-MM-DD')); --みどりの日
insert into holidays values(to_date('2010-05-05','YYYY-MM-DD')); --こどもの日
insert into holidays values(to_date('2010-07-19','YYYY-MM-DD')); --海の日
insert into holidays values(to_date('2010-09-20','YYYY-MM-DD')); --敬老の日
insert into holidays values(to_date('2010-09-23','YYYY-MM-DD')); --秋分の日
insert into holidays values(to_date('2010-10-11','YYYY-MM-DD')); --体育の日
insert into holidays values(to_date('2010-11-03','YYYY-MM-DD')); --文化の日
insert into holidays values(to_date('2010-11-23','YYYY-MM-DD')); --勤労感謝の日
insert into holidays values(to_date('2010-12-23','YYYY-MM-DD')); --天皇誕生日

*/

/*
|| 開始日からi_days営業日後の日付を返す
|| i_daysが正数なら未来、負数なら過去
|| ※開始日は数えない
*/
 FUNCTION WORKDAY( i_startdate IN date, i_days IN number) RETURN DATE;

/*
|| 指定した日付が営業日ならYを返す。営業日じゃなければNを返す。
*/
 FUNCTION IS_WORKDAY( i_date IN date) RETURN CHAR;
 -- 今日が営業日かどうか
 FUNCTION IS_WORKDAY RETURN CHAR;

/*
|| 開始日と終了日の間に含まれる営業日の日数を返す。
|| 日数には開始日と終了日も含まれる。
*/
 FUNCTION NETWORKDAY( i_startdate IN date, i_enddate IN date) RETURN NUMBER;
END WKD_PKG;
/

----------------------------------------------------------
--    PACKAGE BODY
----------------------------------------------------------
CREATE OR REPLACE PACKAGE BODY WKD_PKG AS

FUNCTION WORKDAY( i_startdate IN date, i_days IN number) RETURN DATE
IS
  i   NUMBER := 0;
  work_days NUMBER := 0;
BEGIN
  IF i_days = 0 THEN
     RETURN i_startdate;
  END IF;

  WHILE true LOOP
    IF i_days > 0 THEN
       i := i + 1;
    ELSE
       i := i - 1;
    END IF;

    IF IS_WORKDAY(i_startdate + i) = 'Y' THEN
      work_days := work_days + 1;
    END IF;

    IF abs(work_days) = abs(i_days) THEN
       exit;
    END IF;
  END LOOP;

  RETURN i_startdate + i;
END;

FUNCTION IS_WORKDAY(i_date IN date) RETURN CHAR
IS
  hol NUMBER := 0;
BEGIN
  -- 日曜日:1と土曜日:7に含まれない
  IF TO_CHAR(i_date, 'D') NOT IN ('1', '7') THEN
     -- 土日以外でholidaysに存在しなければ営業日
     SELECT COUNT(*) INTO hol FROM holidays WHERE holiday=trunc(i_date);
     IF hol = 0 THEN
        RETURN 'Y';
     END IF;
  END IF;
  RETURN 'N';
END;

FUNCTION IS_WORKDAY RETURN CHAR
IS
BEGIN
  RETURN IS_WORKDAY(SYSDATE);
END;

FUNCTION NETWORKDAY( i_startdate IN date, i_enddate IN date) RETURN NUMBER
IS
  i number := 0;
  diff number := 0;
  days number := 0;
BEGIN
  diff := trunc(i_enddate) - trunc(i_startdate);
  FOR i IN 0..diff LOOP
      IF IS_WORKDAY(i_startdate + i) = 'Y' THEN
        days := days + 1;
      END IF;
  END LOOP;
  RETURN days;
END;

END WKD_PKG;
/

/*
-- テスト

-- 適当に
SELECT to_char(WKD_PKG.workday(to_date('2010-01-09','YYYY-MM-DD'), 2),'YYYY-MM-DD') FROM dual;
SELECT to_char(WKD_PKG.workday(to_date('2010-01-08','YYYY-MM-DD'), 4),'YYYY-MM-DD') FROM dual;
SELECT to_char(WKD_PKG.workday(to_date('2010-01-07','YYYY-MM-DD'), 4),'YYYY-MM-DD') FROM dual;
SELECT to_char(WKD_PKG.workday(to_date('2010-01-07','YYYY-MM-DD'), -4),'YYYY-MM-DD') FROM dual;

-- 全部6のはず。9,10が土日。11日が祝日。
SELECT WKD_PKG.NETWORKDAY(to_date('2010-01-07','YYYY-MM-DD'),to_date('2010-01-15','YYYY-MM-DD')) FROM dual;
SELECT WKD_PKG.NETWORKDAY(to_date('2010-01-07','YYYY-MM-DD'),to_date('2010-01-16','YYYY-MM-DD')) FROM dual;
SELECT WKD_PKG.NETWORKDAY(to_date('2010-01-07','YYYY-MM-DD'),to_date('2010-01-17','YYYY-MM-DD')) FROM dual;
-- 7のはず。9,10が土日。11日が祝日。
SELECT WKD_PKG.NETWORKDAY(to_date('2010-01-07','YYYY-MM-DD'),to_date('2010-01-18','YYYY-MM-DD')) FROM dual;

*/
</pre>
<p>追記：GitHubがトラブってた。なんだかAnonymousのGistになっていたのでForkしたGistに変えました。</p>
<div style='clear:both'></div><p>Related posts:</p><ol>
<li><a href='http://jinim.jp/archives/378' rel='bookmark' title='消費税を計算するOracle PL/SQLパッケージ'>消費税を計算するOracle PL/SQLパッケージ</a></li>
<li><a href='http://jinim.jp/archives/515' rel='bookmark' title='OracleでFIRST_DAY'>OracleでFIRST_DAY</a></li>
<li><a href='http://jinim.jp/archives/379' rel='bookmark' title='Oracle PL/SQLとUNIXタイムスタンプ'>Oracle PL/SQLとUNIXタイムスタンプ</a></li>
</ol>]]></content:encoded>
			<wfw:commentRss>http://jinim.jp/archives/1715/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Twitterがクラックされてダウン</title>
		<link>http://jinim.jp/archives/1668</link>
		<comments>http://jinim.jp/archives/1668#comments</comments>
		<pubDate>Fri, 18 Dec 2009 07:03:39 +0000</pubDate>
		<dc:creator>eight</dc:creator>
				<category><![CDATA[Tech]]></category>
		<category><![CDATA[Twitter]]></category>

		<guid isPermaLink="false">http://jinim.jp/?p=1668</guid>
		<description><![CDATA[今回のダウンはいつもの、過負荷でダウンとは違う模様。 TechCrunchのこの記事 Twitter Hacked, Defaced By “Iranian Cyber Army” (Developing)が詳しい。 つ &#8230; <a href="http://jinim.jp/archives/1668">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>今回のダウンはいつもの、過負荷でダウンとは違う模様。<br />
TechCrunchの<a href="http://j.mp/77ngqg">この記事 Twitter Hacked, Defaced By “Iranian Cyber Army” (Developing)</a>が詳しい。</p>
<p>つぶやきたいのにつぶやけないときはどうするかなあと、<a href="http://friendfeed.com/jinim8">FriendFeed</a>で、つぶやいてみたら、こっちはサクサク動いて気持ちいい。</p>
<p>ダウン直前に、Twitterで新しいアカウントをとったのだけれど、14:57にそのアカウントのWelcomeメールが来て、さあ、つぶやこうかと思ったら全然つながらず。15時ちょうど？時限装置か。<br />
まあ、もう少しいろいろ決まってからまたこの件はつぶやけってことか。</p>
<p>ところで、何をクラックされたのかまだわからないからあれだけれど、Twitterで使っているパスワードを他のサイトのと使いまわしているんだったら、Twitter以外の他のサイトのパスワードは、すぐに変えておいたほうが良さそう。DNSだけだったりすれば心配ないかもしれないけれど、まあこうなるとしばらくは何も信用できないな。</p>
<p>とにかくTwitterはなかなか楽しいけど、けっこう危ういサービスだなあというのが実感。</p>
<div style='clear:both'></div>]]></content:encoded>
			<wfw:commentRss>http://jinim.jp/archives/1668/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Ubuntu 9.04 serverを9.10へアップグレード</title>
		<link>http://jinim.jp/archives/1646</link>
		<comments>http://jinim.jp/archives/1646#comments</comments>
		<pubDate>Fri, 04 Dec 2009 06:02:27 +0000</pubDate>
		<dc:creator>eight</dc:creator>
				<category><![CDATA[Tech]]></category>
		<category><![CDATA[Linux]]></category>

		<guid isPermaLink="false">http://jinim.jp/?p=1646</guid>
		<description><![CDATA[そろそろ、9.10も落ち着いてきたかなということで、Ubuntuサーバを9.04から9,10へアップグレードしてみる。 アップグレード方法は、Debianみたいにsources.listを書き換えるんじゃなくて、do-r &#8230; <a href="http://jinim.jp/archives/1646">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>そろそろ、9.10も落ち着いてきたかなということで、Ubuntuサーバを9.04から9,10へアップグレードしてみる。<br />
アップグレード方法は、Debianみたいにsources.listを書き換えるんじゃなくて、do-release-upgradeコマンドで実施（Debianも最近は違うんだろうか？もしかして）。</p>
<p>コマンド実行から、アップグレード、再起動まで概ね20分ぐらい。まあ簡単だったんだが、キーボードの選択画面がヒドい。ずらずらとメーカー名とキーボードタイプのリストが表示されて、その中から選べとでる。まあ、サーバ版なんだから、管理者はそのくらいわかるだろっ？ってところか。<br />
僕にはわからず、結局、”Do not configure keyboard; keep kernel keymap”を選択してインストールを完了後に、dpkg-reconfigure console-setupでJapanに再設定。これをやらないと、コンソールで使うときになんだかおかしなことになっていた。USキーボードになってるのかな。そこまでは調べていない。</p>
<p>このUbuntuサーバは、VMware上で動いている仮想マシン。NagiosとMRTGを使って他のホストを監視している。NagiosもMRTGも設定をいろいろ書き換えているので、アップグレード中の設定を新しく書き換えるか？という質問には、既存の設定を使うと選択。これで、NagiosもMRTGもApacheも特に設定を直す必要もなく、動いている模様。これでとりあえず、完了。</p>
<p>あと、この、do-release-upgrade（update-manager-coreパッケージに含まれる）を見つけるのに、30分ぐらいかかった。Googleで検索しても、Desktop版のアップグレード方法ばかりがヒットする。<br />
結局、<a href="https://help.ubuntu.com/9.10/serverguide/C/installing-upgrading.html">Ubuntu Server Guide</a>で見つける。これは、まあ、当たり前といえば、当たり前で、誰も悪くない。僕が悪い。最初にさがすべきところ。なんでも検索するんじゃないってことだな。</p>
<p>そうそう、一つ追記。<br />
アップグレード後に、_netdev付きでnfsマウントしているボリュームをマウントしてくれなくなった。ネットワーク接続とマウントのタイミングがおかしいのかなんなのか詳しくは調べていないけれど、どうも不具合のように見える。とりあえずは、/etc/rc.localにmount -aを書いている。そのうち、アップデートで治るのかもしれない。</p>
<div style='clear:both'></div>]]></content:encoded>
			<wfw:commentRss>http://jinim.jp/archives/1646/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Flickrから自分のアップロードした写真を全部ダウンロードする</title>
		<link>http://jinim.jp/archives/1527</link>
		<comments>http://jinim.jp/archives/1527#comments</comments>
		<pubDate>Wed, 18 Nov 2009 01:13:02 +0000</pubDate>
		<dc:creator>eight</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[Tech]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://jinim.jp/?p=1527</guid>
		<description><![CDATA[ふと思い立ってやってみようとしたけれど、これが結構大変。一括してダウンロードする方法がFlickrの機能としては見当たらない。 誰か他の人の写真じゃなくて自分のアップロードした写真ぐらい、機能があってもよさそうだけれど。 &#8230; <a href="http://jinim.jp/archives/1527">Continue reading <span class="meta-nav">&#8594;</span></a>
Related posts:<ol>
<li><a href='http://jinim.jp/archives/856' rel='bookmark' title='Appleストアにアウトレットがあったのか'>Appleストアにアウトレットがあったのか</a></li>
<li><a href='http://jinim.jp/archives/519' rel='bookmark' title='urllib2.quote()ってアリなんだ'>urllib2.quote()ってアリなんだ</a></li>
<li><a href='http://jinim.jp/archives/517' rel='bookmark' title='cx_Oracleが見つけるOracleクライアントライブラリを変えたい'>cx_Oracleが見つけるOracleクライアントライブラリを変えたい</a></li>
</ol>]]></description>
			<content:encoded><![CDATA[<p>ふと思い立ってやってみようとしたけれど、これが結構大変。一括してダウンロードする方法がFlickrの機能としては見当たらない。<br />
誰か他の人の写真じゃなくて自分のアップロードした写真ぐらい、機能があってもよさそうだけれど。<br />
検索してみると、いくつかソフトウエアがあって、２つ試してみたけれど、認証に失敗して先に進めないのがひとつと、そもそもインストールできないのがひとつ（.Net Frameworkを使うやつ）。<br />
意地になってしまって、<a href="http://flickrpy.googlecode.com/svn/trunk/flickr.py">flickr.py</a>を使ったPythonスクリプトを書いてみた。<br />
Pythonとflickr.pyがあれば使えます。ユーザID（ユーザ名じゃない）、API KeyとかSecretとか難しいのが必要。やっぱり、Flickr自身で実装しないと普通の人には難しいんじゃないか。</p>
<p>下のスクリプトをローカルに保存して、設定を3ヶ所書き換えて（ユーザID、API Key、API Secret）、flickr.pyを同じディレクトリにおいて、実行するとサブディレクトリを作成してその中にズンズンダウンロードします。<br />
<span id="more-1527"></span></p>
<pre class="brush:python">
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""flickr.pyの利用サンプル。 http://code.google.com/p/flickrpy/
Flickrから指定したユーザの全ての写真を取得してローカルディスクに保存する。
自分の写真をダウンロードするために作ったので、他人の写真でも使えるかどうかは未確認。
"""
import os
import time
import flickr
import urllib

#######################################################
# ここから設定変更
#######################################################

#ユーザID
#これ変更必須。自分のアカウントページでURLをひょいと見ると書いてあった。@を含んだ12文字。
user_id = "XXXXXXXX@YYY"

#Flickr API Key + Secret
#これ必須。自分のアカウントのページで確認。
flickr.API_KEY = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
flickr.API_SECRET = "XXXXXXXXXXXXXXXX"

#これはオプション。
#取得する画像のサイズ。Large=オリジナル。 http://www.flickr.com/services/api/flickr.photos.getSizes.html
#Originalでもいけそうだけど、何故かダメだった。
size = 'Large'

#######################################################
# ここまで設定変更
#######################################################

#ダウンロード写真を保持するディレクトリの作成
MY_DIR = os.path.dirname(os.path.abspath(__file__))
IMAGE_DIR = os.path.join(MY_DIR, 'image_%s' % size)
if os.path.exists(IMAGE_DIR):
    os.rename(IMAGE_DIR, "%s.bak-%s" % (IMAGE_DIR, time.strftime('%Y%m%d%H%M%S')))
os.makedirs(IMAGE_DIR)

if __name__=='__main__':
    user = flickr.User(user_id)
    photo_count = int(user.photos_count)
    print("%s has %d photos." % (user.username, photo_count))

    retr_count = 0
    page = 1

    while retr_count < photo_count:
        photos = flickr.people_getPublicPhotos(user_id, per_page = 500, page = page)
        for photo in photos:
            url = photo.getURL(size = size, urlType = 'source')
            filename = os.path.join(IMAGE_DIR, '%s.jpg' % (photo.title))
            file(filename, "wb+").write(urllib.urlopen(url).read())
            retr_count += 1
            print("%d/%d: %s retrieved." % (retr_count, photo_count, os.path.basename(filename)))
        page += 1
</pre>
<p>スクリプトはGistにも置いてあります。 <a href="http://gist.github.com/237451">Gist:237451</a></p>
<div style='clear:both'></div><p>Related posts:</p><ol>
<li><a href='http://jinim.jp/archives/856' rel='bookmark' title='Appleストアにアウトレットがあったのか'>Appleストアにアウトレットがあったのか</a></li>
<li><a href='http://jinim.jp/archives/519' rel='bookmark' title='urllib2.quote()ってアリなんだ'>urllib2.quote()ってアリなんだ</a></li>
<li><a href='http://jinim.jp/archives/517' rel='bookmark' title='cx_Oracleが見つけるOracleクライアントライブラリを変えたい'>cx_Oracleが見つけるOracleクライアントライブラリを変えたい</a></li>
</ol>]]></content:encoded>
			<wfw:commentRss>http://jinim.jp/archives/1527/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>FeinCMSメモ#1</title>
		<link>http://jinim.jp/archives/1500</link>
		<comments>http://jinim.jp/archives/1500#comments</comments>
		<pubDate>Thu, 12 Nov 2009 08:28:45 +0000</pubDate>
		<dc:creator>eight</dc:creator>
				<category><![CDATA[Tech]]></category>
		<category><![CDATA[django]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://jinim.jp/?p=1500</guid>
		<description><![CDATA[予定しているちっちゃなサイトに使えないかとFeinCMSを試してみている。 Django CMS 2と比較するとシンプルで始める為の敷居が低い。 一通りexampleにあるものが動くようになって、テンプレートをカスタマイ &#8230; <a href="http://jinim.jp/archives/1500">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>予定しているちっちゃなサイトに使えないかと<a href="http://spinlock.ch/pub/feincms/html/">FeinCMS</a>を試してみている。<br />
Django CMS 2と比較するとシンプルで始める為の敷居が低い。</p>
<p>一通りexampleにあるものが動くようになって、テンプレートをカスタマイズして見映えを変えてみたりして、これいいかも、という感じになってきたので、まずはexampleが動くためにやることをメモしておく。<br />
ドキュメントのinstallの通りにやってもちゃんと動かないのよこれが。次のリリースぐらいで直りそうだけれど。<br />
<span id="more-1500"></span><br />
ソースをgithubから持ってくるのが前提。easy_installだとexampleが入らないので。</p>
<blockquote><p>git clone git://github.com/matthiask/feincms.git </p></blockquote>
<ul>
<li>Djangoの1.0以降を使うなら、まあ今から使うならたいてい1.1以降だと思うので、とにかくdjango-mpttはtrunkを持ってくる必要がある。とりあえず動かしたいなら、feincms/quickstart.shを実行するのが簡単。Djangoとdjango-mpttを入れてくれる。</li>
<li>ドキュメントには見当たらないけれど、PILが必要なので、インストールしておく。</li>
<li>example/urls.pyの修正が必要。&#8221;from example import models&#8221;という1行をadmin.autodiscover()の前に挿入。</li>
<li>example/example.dbは削除して、python manage.py syncdbしたほうが良さそう。しなくても概ね動くけれど、管理画面でblog/entryデータを保存しようとするとエラーになったりする。サンプルデータが入っているので、これはこれで感覚をつかむにはいいけれど、これにこだわると進まない。</li>
</ul>
<p>これで、</p>
<blockquote><p>cd example<br />
python manage.py runserver
</p></blockquote>
<p>で動く。</p>
<p>最初のdjango-mpttの問題は、django-mpttが最近はあまりメンテナンスされていないから、<a href="http://groups.google.com/group/django-feincms/browse_thread/thread/b57752ca8bee10c7?pli=1">自前でメンテしていく方針</a>だそうなので、そのうちドキュメントに反映されるか、パッケージに含まれるのか、何かしら対処されるだろう。</p>
<p>urls.pyの問題はどうかな。初期化コードの実行順の問題に見える。<br />
これで解決はするけれど、そもそもここに書いていいのかどうかがよくわかっていない（まだDjango勉強中）。<br />
一応、githubでfolkしてこの修正を<a href="http://github.com/eight/feincms/commit/972aa579d816236b24f77cbdde8cb60bdcc042e4">コミットしてみた</a>。gitもgithubもまだよくわかっていないからなんかおかしいかも。あ、example.db含めてしまったかも&#8230;<br />
まだまだ、勉強。<br />
FeinCMS結構気に入ったので、引き続きいろいろ調べてみることにする。#2以降に続く。のか。</p>
<div style='clear:both'></div>]]></content:encoded>
			<wfw:commentRss>http://jinim.jp/archives/1500/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

