少し前にGoogle Cloud Messaging for Chrome が発表されました。 Android向けに提供されていた Push 通信の仕組みである GCM の Chrome 版です。 ちょうど GCM for Android に触っていたところだったので、 for Chrome のほうも試してみることにしました。
拡張機能の登録 公式ページの説明にしたがって、 APIを使えるようにします。 GCMはOAuth2.0で認証を行うので、
クライアントIDを作る Refresh Token を作る という2ステップが必要。
クライアントIDを作る まず、新しい OAuth2.0 のアプリを作成。 拡張機能をアップロードする予定のGoogleアカウントで以下の作業して Client IDを作ります。
Google APIs Console にログインする ** Create… ** メニューから新しいプロジェクトを作成 “Services” を開いて ** Google Cloud Messaging for Chrome API ** を有効化 “API Access” を開いて ** Create an OAuth 2.0 cliend ID… ** というボタンをクリック branding information を適当に入力 “Application Type” という項目の “Web application” を選択 “Create client ID”!! Client ID と Client Secret が表示されるのでメモしておきましょう。
RaspberryPi に cron を仕込んで定期実行をやってみようと考えました。 cron の設定自体は crontab -e コマンドを実行すれば簡単にできます。 ただ、これだけだとちゃんと動いているか少し心配なので、 エラーが起きた時に何か通知して欲しい。 普通なら設定ファイルに MAILTO=hogehoge@example.com と書いておくと メールが送られるはずなのですが、 メールサーバが動いてないのでうまくいかない・・・。
そういうわけで、RaspberryPiからメールを送るための設定をしたのでメモ。
MTAをインストールする Raspberry Pi には標準でMTA(Message Transfer Agent)が入ってないようなのでインストール。 今回はPostfixを採用
sudo apt-get install postfix 最初、Sendmailも試してみたんだけど、送信者マスカレードがなぜかうまく行かなったので断念。 後述するように、この設定がないとスパムフィルタに引っかかってしまうのです。
プロバイダのSMTPにリレーしてもらう 実際にメールを送りには以下の条件を満たす必要があるようです。
送信元のドメインを引ける 固定IPからのアクセス 固定IPなんて自前で持ってないし、 cron からのメールは送信元が pi@raspberrypi になってしまいドメインを引けません。 そのためそのままではスパムメールとして扱われてしまい、メールが届きません。
そこで、プロバイダが提供しているSMTPサーバにメールをリレーしてもらいます。 /etc/postfix/main.cfに以下の行を追加します。
sender_canonical_maps = regexp:/etc/postfix/canonical relayhost = [smtp.example.com]:587 smtp_sasl_auth_enable = yes smtp_sasl_password_maps = hash:/etc/postfix/relay_password smtp_sasl_security_options = noanonymous プロバイダにリレーしてもらうには SMTP-Auth で認証する必要があるので、 ユーザ名とパスワードを設定しておきます。
smtp.example.com hogehoge:your-password postmapコマンドを使って、Postfixから扱える形式に変換します。
$ postmap hash:/etc/postfix/relay_password さらに、エンベロープのFromがプロバイダから提供されたメールアドレスでないと メールをリレーしてくれないので、 すべてのメールのFromをすべて書き換えるよう設定します。
RaspberryPiをネットつないでみたので、PythonからいろんなURLを叩いて遊んでいたんだけど、 一部のhttps通信が Connection Timed Out で失敗しちゃう。 プログラムの問題かと思ったけど、curlで叩いてもやっぱりタイムアウト。 Macで全く同じ事をするとうまくいく・・・。 いろいろ調べて、何とかしてみたお話。
原因 接続先がTLSv1にしか対応していないのにSSLv3でアクセスしようとしていたことが問題だったらしい。 明示的にTLSv1を使うように指定して curl を叩いてみるとうまくいった。
$ curl --tlsv3 https://hogehoge なぜRaspberryPiではダメで Macでは成功するのか、という根本的な原因はよくわからなかった。 SSLv3に対応していないなら自動的にフォールバックしてくれてもよさそうなものだけど、 なぜうまく行かないんだろう・・・?
Pythonでの対処 PythonでもTLSv3を使えばうまくいくはずなんだけど、 暗号化方式を指定するオプションは見当たらない(2.7での話)。 どうやら標準ライブラリのファイルを直接書き換えるか、 実行時に中身を入れ替えるかしないとできないみたいだ。 この問題普通のUbuntuでも起こるらしく、 そのフォーラムで置き換えコードを見つけた。
import httplib from httplib import HTTPConnection, HTTPS_PORT import ssl class HTTPSConnection(HTTPConnection): "This class allows communication via SSL." default_port = HTTPS_PORT def __init__(self, host, port=None, key_file=None, cert_file=None, strict=None, timeout=socket._GLOBAL_DEFAULT_TIMEOUT, source_address=None): HTTPConnection.__init__(self, host, port, strict, timeout, source_address) self.key_file = key_file self.cert_file = cert_file def connect(self): "Connect to a host on a given (SSL) port.
Twitter の API リファレンスを久しぶりに見たら、 Application-only authenticationとかいうのを発見。 特定のユーザと関連付けられない代わりに、普通に認証するより制限が緩いみたい。 3月に追加されてたらしい。
知らなかった・・・。 最近API叩いてなかったからな・・・。
便利そうなので、Python用のTwitterライブラリであるTweepyから使ってみた。
AuthHandler Tweepy用のAuthHandler。 認証部分は TwitterのApplication-only authenticationを試してみた のページからほぼコピペ。
import tweepy import urllib import urllib2 import base64 import json class AppAuthHandler(tweepy.auth.AuthHandler): TOKEN_URL = 'https://api.twitter.com/oauth2/token' def __init__(self, consumer_key, consumer_secret): token_credential = urllib.quote(consumer_key) + ':' + urllib.quote(consumer_secret) credential = base64.b64encode(token_credential) value = {'grant_type': 'client_credentials'} data = urllib.urlencode(value) req = urllib2.Request(self.TOKEN_URL) req.add_header('Authorization', 'Basic ' + credential) req.add_header('Content-Type', 'application/x-www-form-urlencoded;charset=UTF-8') response = urllib2.urlopen(req, data) json_response = json.loads(response.read()) self.
先日、社内 ISUCON(良い感じにスピードアップコンテスト) に参加してきました。 Livedoorで開催されたISUCONのミニ版で、 Webアプリをひたすら高速化するコンテストです。
高速化の対象はNoPaste。 テキストを共有するWebアプリです。 テキストの投稿・投稿の閲覧・投稿にスターをつける の3つの動作ができる簡単なアプリです。
新卒 vs 先輩ということで、それぞれ4チームが参戦。 チームは二人一組で僕は @Maco_Tasu くんと一緒でした。 @Maco_Tasuくんのブログも参照。
Recent Posts 生成クエリの高速化 高速化前のアプリのベンチマークの結果、スコアは77(≒1分あたりの捌いたリクエスト数)。 何も考えずにデータベースの全行を舐めるクエリを書いていたので、まあ、妥当なスコアですね。
重いのはサイドバーに表示される Recent Posts。 Recent Posts は表示回数が多く、 複数の行、複数のテーブルへのアクセスが発生するため、 きっとここがボトルネックになるだろうと予測してました。 そこで最初にこの部分を解決することにしました。
とりあえずインデックスを張る クエリを修正してアクセスする行を最小化 スターのカウントした結果をテーブルに格納 オリジナルのデータベース構成では、スターした回数だけ行が増えてました 必要なのは投稿ごとのスター数なので、独立したテーブルに この時点で早くも重大なバグを組み込んでしまったことに、この時はまだ気がついていなかった・・・ nginxによる静的ファイル配信 僕がクエリをいじっている間、@Maco_Tasuくんには サーバの設定をお願いしました。
ログの様子を眺めてみると、cssとかjsとかの静的ファイルが結構な量ありました。 最初のスクリプトでは静的ファイルの配信もアプリでやってたので、 これをnginxを使って配信するように変更。 その他のリクエストはリバースプロキシを設定してアプリに投げます。
Starlet と Server::Starter リバースプロキシを設定する際にアプリの起動スクリプトを編集する必要があったので、 ついでに起動時の設定を色々変更。 PSGI実行のStarletというのが速いと聞いてこれを採用。 Starlet使い方調べてたら、Server::Starterを使った例が出てきたので一緒にインストール。 ワーカーの数の数は適当に10個にしました。
ここで2回目のベンチマークを実行。 スコア1300程度で、その時点のトップ!
SSIを使ったサイドバーの埋め込み お昼を挟んで、さらなる高速化を目指します。
topコマンドを眺めているとPerlで作ったアプリの負荷が大きい。 ほとんどテンプレートエンジンを呼び出しているだけの単純なコードなので、 ここを高速化するのは面倒くさい。 そこで、前段のnginxでキャッシュする作戦を採用することにしました。
もっともキャッシュが有効なのはサイドバーだろうと予想。 クエリの最適化をしたとは言え、サイドバーには100件程度の投稿が表示されるので、 クエリ実行にもレンダリングにも時間がかかるはず。 さらにすべてのページでサイドバーは共有できるので、大幅な高速化が期待できるはずです。
過去のISUCONの記事にSSI(Server Side Include)を使った例があったのを思い出し、 これを使ってサイドバーのみキャッシュ、nginx内でサイドバーを埋め込むように。
僕が SSIのタグ埋め込み、 @Maco_Tasu くんにnginxのキャッシュ設定を行ってもらうという役割分担で作業を再開しました。
emacsを使って編集している最中にシェル操作をしたくなって, C-z を押してバックグラウンドにしてシェル操作. その後,emacsに戻ってくるには fg コマンドを打つ必要があるんだけど, 間違えてもう一回 emacs を新しく立ち上げるというミスを何度もやってしまう・・・.
これに対し,猫型さんが複数起動しようとすると警告を出してくれるようにしてくれました. (出、出〜〜〜〜wwww emacsをふたつ以上実行奴〜〜〜〜www)
警告してくれるのはありがたいんだけど, これだとシェル操作中に別のファイルの編集をしたいと思っても,警告が返ってくるだけ. emacs をフォアグラウンドに出して,ファイルの指定をやり直さなきゃいけない. 僕はファイルの編集をしたいんだ!! わかったから早く編集させろ!!!
emacsclient 単なる警告じゃなくて, 「裏で動いていたemacsを復帰させ,新しいバッファを開く」 ところまで自動的にやってくれると嬉しいですね.
まず,emacs をデーモンモードで起動しておきます.
emacs --daemon emacsclient コマンドでファイルを開くと, emacs デーモンさんが新しいバッファで開いてくれます. オプションに -nw を指定しておくと現在の端末で閲覧編集することができます.
emacsclient -nw hoge.txt 終了するにはC-x 5 0. C-x C-cでも終了できるけど, デーモンにバッファが残ってしまうみたい.
aオプションでemacs デーモンが起動してないときに 編集に使うエディタを指定できる. 空っぽにしておくと,emacs をデーモンモードで起動してくれる.
emacsclient -nw -a '' hoge.txt emacs デーモンを終了させるのは以下のコマンド.
emacsclient -e '(kill-emacs)' emacsclient に対して alias を作っておけば, 複数起動かどうか意識せずに使えますね.
alias emacs='emacsclient -nw -a ""' 参考 emacsclientを使おう emacsclient の使い方の種類と、便利な使い方 emacsclientを終了する方法
LaTeXで書いた文章を電子書籍にしたくなったので, LaTeX2EPUBを使ってみました.
LaTeX2EPUBはLaTeXMLとReVIEWに依存しているようなので, それぞれインストールしていきます. あと,数式の変換とかにLaTeXを使っているので別途用意する必要あり. いろんなディストリビューションがあるけど, ここでは TeX Live 2012 を使いました.
LaTeXML のインストール LaTeXMLはLaTeXの文章をXML形式に変換するソフト. そこからさらにXSLTを使ってXHTMLへ変換できる. ドキュメントに従って 依存するライブラリをインストール.
perl -MCPAN -e shell cpan> install DB_File, Parse::RecDescent, File::Which cpan> install XML::LibXML, XML::LibXSLT ドキュメントが少し古いらしく,これだけでは不十分だった. 追加でParse::RecDescentとImage::Magickもインストールしておく.
cpan> install Parse::RecDescent cpan> quit yum install ImageMagick-perl 後はソースを取ってきてmakeするだけ. 現時点での最新版0.7.0をインストールした.
wget http://dlmf.nist.gov/LaTeXML/releases/LaTeXML-0.7.0.tar.gz tar zxvf LaTeXML-0.7.0.tar.gz cd LaTeXML-0.7.0 perl Makefile.PL make make test make install ReVIEW のインストール ReVIEWは簡単なマークアップ言語で書かれたテキストから PDFやEPUBを作成するためのスクリプトです. このなかのEPUB作成機能に依存しているようなのでインストールしておきます. ReVIEWはgemで簡単インストール.
gem install review LaTeX2EPUB のインストール LaTeX2EPUB本体をインストール. 本家の日本語化対応が少し不十分だったので 改造版を上げといた. これをダウンロードしてパスの通ったところに置けばインストール完了.
Amazon Web Services(AWS)でEC2でも使ってみようかと, 登録を試みました.
が,しかし,電話認証の段階で何度やってもシステムエラー・・・.
An Error Has Occured システムエラー 電話確認要求を処理できません。後でもう一度お試しください。
こういう時は,とりあえずエラーメッセージでググってみましょう. なんだかそれっぽい記事が見つかりました.
AWSアカウント開設で”電話確認要求を処理できません。後でもう一度お試しください。”と怒られ続けた Amazon Developer Forums: 電話による身元確認でエラー発生 どうやら,登録時に入力した「支払い方法」と「アドレス情報」が正しく反映されていないことが原因のようです.
アカウントの管理 画面から,「支払い方法」を選び,クレジットカードや請求先を記入します. アドレス情報は「登録内容の変更」から変更可能です.
AWSをはじめてみたというエントリだけど, 実はじょりぼっとの「買うべき?」機能を実装するために, AWSのProduct Advertising APIを前々から使っていたのでした. このAPI使うだけなら支払い方法などの入力は不要だったので, 必要最低限の情報しか入力していませんでした. 住所とかの入力もしなかったのですが, 自分が確認したときはアドレス情報の国設定が何故かアメリカになってました. これのせいですかね?
詳しい原因はよくわかりませんが,とりあえず,「支払い方法」と「登録内容の変更」の全項目を正しく入力したら認証が出来ました. 1年は無料でいろいろ遊べるらしいので,何か動かして遊んでみましょう.
じょりぼっとが初めてつぶやいてから 今日でちょうど一年となりました.
突然の凍結,74回にも及ぶバルスなどなどを乗り越え, 今日まで生き延びられたことを嬉しく思います.
ちなみに一番最初のツイートはこんなのでした.
自分の教科にしましたというわけで終わりー。どっちも一部の断面図
— 狼とボット (@JO_RI_bot) 2012年1月22日 学食メニュー じょりぼっとが一周年を迎えるということは, 起動当初から続けてきた学食メニュー表示機能も一周年ということです. 一年分のメニューはこちらにストックしてあります. どんなメニューが出されることが多いのか,簡単な統計を取って見ました.
1食昼食A定 回鍋肉 13 鶏肉と味噌漬け焼き 9 チキン唐揚げ 8 豚肉キムチ炒め 7 ちきんカツ 7 チキン唐揚げ<スパイシーカレー> 7 豚肉朝鮮焼き 7 焼肉とピーマン肉詰めフライ 7 チキンソテーさわやかソース 7 チキンマスタード焼き 7 鶏肉キムチ焼き 7 チキンピザソース焼 7 1食夕食A定 チキンピザソース焼 13 酢豚 11 豚カツ 9 チキンソテーさわやかソース 9 グリルドチキンイタリア風 9 鶏肉と味噌漬け焼き 8 エッグ焼肉 8 Bigメンチ 8 焼肉と春巻き 8 チキンステーキタルタルソース 8 1食昼食B定 筑前煮 16 いりどり 13 八宝菜 12 白身魚フライの卵とじ 11 白身魚のピリピリ漬け 10 鯖の生姜焼き 9 白身魚フライチーズ焼き 9 うずら卵と野菜の五目煮 8 鶏肉の酢豚風 8 シューマイの中華風旨煮 8 チキンブラウンソース煮 8 サーモンシチュー 8 アジフライとツナサラダ 8 白身魚の磯辺揚げ 8 1食夕食B定 すき焼き風旨煮 19 うずら卵と野菜の五目煮 13 スペイン風オムレツとコロッケ 13 ピザ卵とコロッケ 12 鶏肉と野菜の七味炒め 12 鮭の野菜あんかけ 11 鶏肉とヤングコーンの豆板醤炒め 10 アジフライとツナサラダ 9 チキンブラウンソース煮 9 白身魚のピリピリ漬け 9 1食昼食セット オムライス 16 五目あんかけ焼きそば 13 鮭チャーハン 12 ねぎトロ丼 12 鶏肉ときのこのチャーハン 11 トルコライス 11 三色丼 9 鶏の照り焼き丼 9 ビビンバ丼 9 親子丼 9 麻婆丼 9 1食夕食セット キーマカレー 13 ビビンバ丼 10 肉たれうどんとぶっ玉丼 10 海の幸うどん 9 すき焼き丼 8 肉うどんとカレーライス 8 ねぎトロ丼 8 イタリア風チキンカツ丼 8 鶏の照り焼き丼 6 とろろそばとミニカツ丼 6 鮭茶漬け 6 1食昼食単品 鶏肉とブロッコリー炒め 16 さつま汁 15 揚ギョーザ 13 のっぺ 13 イカ野菜カツ 13 揚げ豆腐の旨煮 13 かぼちゃのそぼろあんかけ 12 ハムチーズサンドフライ 12 エビ風味グラタンコロッケ 12 鶏肉とタケノコの旨煮 12 ブロッコリーとカリフラワーの炒め 12 茄子の中華風旨煮 12 豚肉と野菜の煮込み 12 卵と玉ねぎのソテー 12 1食夕食単品 鶏肉とチーズ焼き 17 レバニラ炒め 15 豆腐きのこあんかけ 13 ゆで卵 13 ちくわの二色揚げ 12 鶏肉と里芋の煮物 11 蒸シューマイ 11 けんちん汁 11 五目金平 11 五目肉じゃが 10 シューマイのカレー揚げ 10 ブロッコリーとカリフラワーの炒め 10 2食お昼ごはん定食 ピーマン肉詰めフライ 13 ちきんチーズ焼き 13 ハッシュドビーフ 12 鶏肉のピリカラ味噌焼き 10 カレーコロッケ 8 春巻き 7 野菜コロッケ 7 鰹の刺し丼 7 ちきんカツ 7 豚玉丼 7 レッドホットチキン 7 きじ焼き丼 7 ちきん南蛮漬け 7 ハンバーグ 7 海老グラタンコロッケ 7 2食晩御飯定食 545円定食 34 545円丼 16 フライアンドフライ 13 ちきん南蛮 11 新潟タレカツどん 11 中華角煮丼 10 ねぎトロ丼 9 スパイシードライカレー 9 レッドほっとマヨ 9 545丼 8 2食に関しては,集計か3月からなのでまだ一年たっていません. それにしても圧倒的な545円定食の出現頻度. 結局何が食べられるのか全くわからないのですが・・・.
SSHには標準でTCPのトンネリング機能は付いているのですが, UDPはトンネリングしてくれません. なんとかできないものかと試行錯誤してみました.
TCP をトンネル TCPのトンネリングの復習から. 以下のコマンドでクライアントの8080番ポートを,リモートの80番ポートに転送することができます.
ssh -L 8080:localhost:80 remote SOCKS proxyとして動作させることも出来ます. ブラウザのプロキシとして設定すれば,リモートのサーバがすべての通信を中継してくれます.
ssh -D 8080 remote UDP をトンネル NetCatを使うと TCP/UDP の通信内容と標準入出力をつなげることが出来るらしいです. これを使って,クライアント側で UDP サーバを立て,その通信内容をSSH経由でリモートの UDP クライアントに送ってあげます. 最後にリモートからクライアント側へのパケットを名前付きパイプで転送してあげればトンネル完成です.
mkfifo tunnel nc -ul 8080 < tunnel | ssh remote nc -u localhost 8080 > tunnel Mosh をトンネル なんでこんなことをしようと思ったかというと,Moshをファイヤーウォール越しに使いたかったから. MoshはUDPで通信しているので,SSHしか通らない環境では使えません. そこでUDPをSSHでトンネリングしてできないかとやって見ました. セッションの確立にSSHも使っているので,以下のようにして Mosh用のUDPトンネルと SSH用のTCPトンネルを作ります.
mkfifo tunnel nc -ul 60000 < tunnel | ssh -L 10000:localhost:22 remote nc -u localhost 60000 > tunnel & mosh -p 60000 --ssh="ssh -p 10000" localhost 外部からのSSH通信が遅かったので,Moshのローカルエコーでなんとかならないかと挑戦してみました. 実際の効果は未確認.またあとで試してみます.