凍結! Nov 15

WordPressのメンテとか、多機能さが面倒くさくなったのでこちらは更新を停止する。 ドメインもaerial.stからarchive.aerial.stに移して、記事個別のURLに関してはリダイレクトもかけたので大きな問題はないはず。

05年から7年以上使ってきたWordPressともさようなら。

ちなみに細かい技術的メモははてなブログのほうに書いている。殴り書きが多いので、とてもQiitaには載せられないレベル。でもちょこちょこ投稿できる場所を作ったおかげでまた更新頻度が上がってきた(どうも独自ドメインを使っているとクオリティを気にして数書けなくなる…)。

二代目MacBook Airの11.6インチを購入 Oct 16

初代を買ってからもうすぐで2年が経とうとしてる今日この頃、SSDの容量不足に加え動作が緩慢になってきたので買い換えることにした。

オプションは付けられるだけ付けて、

という感じ。

先日「2台のノートはいらないなぁ」と思ってMacBook Proの15inchを下取りに出したので、今後はこいつがメインとして活躍する。コンピュータ名はなににしようかなぁ。

[embed size=m]http://instagram.com/p/Q0y8IInh8g/[/embed]

Qiita/Kobito.app便利ですよ Jul 23

最近はすっかり更新しなくなってしまったこのブログだけど、技術的なメモに関してはQiitaに残すようにしている。

というのも、Markdownが使えるKobito.appがとても便利なので。

オススメです。

ikm-opengraph.gemをリリースしてみた Jul 23

リリースしてみた。初gem。forkだけど。

opengraphという、HTMLのヘッダに埋め込まれたOGPの情報を抜き出すgemがあるんだけど、内部で使用しているRESTClientがUTF-8固定で処理をするためにそれ以外のエンコーディングだと文字化けしてしまうという問題があった。

代わりにFaradayを使ってみたらASCII-8BITで処理をしてくれたのでこれまた内部のNokogiriがcharsetからうまくエンコーディングを判定してくれるようになった。なのでまぁ試しにリリースしてみた。

ソースはgithubに上げている。元のopengraphはrspecのバージョンが古かったりしたのでging-opengraphからフォークして、テストも書いてみた。

ただ世の中にはcharsetにEUC-JPと書いてあるけど実際はUTF-8で記述されているページがあったりしたので、結局手元ではrchardet19を使って判定するようにした。重いのが玉に瑕。

MySQL 5.5でのスローログ Feb 16

Homebrewで入れたMySQL 5.5.10のスローログの設定。

$ sudo vim /etc/my.cnf

[mysqld]
(いろいろ)
slow_query_log=1
long_query_time=0.02
slow_query_log_file=slow.log

$ mysql.server restart
$ tail -f /usr/local/var/mysql/slow.log

Rack::Profilerを使う Jan 16

Rack::Profilerを使うのに少し躓いたのでメモ。

Gemfile:

gem "ruby-prof"
gem "rack-contrib", :require => "rack/contrib"

app.rbのconfigureブロックあたり:

require "rack/contrib/profiler"
Rack::RubyProf = RubyProf
use Rack::Profiler

Rack::RubyProf = RubyProfをしているのはエラーが出るから。

アクセスする際にURL末尾に

?profile=process_time

を付けるとプロファイル結果がダウンロードできる。

あとはKCacheGrindとかQCacheGrindで解析する、らしい。 (qtのビルドで時間がかかってるのでまだできていない…)

参考

Node.js(V8)は4バイトのUTF-8に未対応 Jan 2

現状、Node.js(V8)は4バイトのUTF-8に対応していない。

$ node
> code = 0x1F614
128532
> char = String.fromCharCode(code)
''
> char.charCodeAt(0).toString(16)
'f614'

先頭の1が削られてしまっている。

ちなみにV8コミッタの@koichikさんから直接リプライをもらった

RestClientの返り値はStringとちょっと違う Dec 27

インターフェースが簡潔で使いやすいRestClientだけれども、各種HTTPメソッドの返り値をto_iするとステータスコードを返すみたいだ。

たとえば次のようなSinatraアプリが起動していたとする。

get '/' do
  "1"
end

このgetルーティングに対してRestClientでアクセスすると、次のような結果が得られる。

require "rest_client"

res = RestClient.get("http://localhost:9292/")
#=> "1"

# Stringなのにto_iはステータスコード200を返す
res.class #=> String
res.to_i  #=> 200

# to_strしても変わらない
str = res.to_str  #=> "1"
str.to_i          #=> 200
res.class         #=> String

# 期待される値はと言うと
"1".to_i  #=> 1

内部でどうやっているかまでは確認できていないけど、 このようにRestClientの返り値のto_iはステータスコードを返す。

で、具体的にどんなときに不具合があるかというと、

ではどうやっていつものStringとして扱うのかというと、Stringで包みなおせばいい。

res = RestClient("http://localhost:9292")
str = String.new(res)
str.to_i              #=> 1
str.class             #=> String

なんでこんな変な仕様になってるんだろう。 せめて返り値には別のクラスを使用して欲しかった。

そんな感じで、RestClientは変なところではまるので要注意。

LionでPostfix+Gmail Dec 8

OSX LionにはPostfixがインストールされているんだけど、これを使ってgmail経由で送信する際に一筋縄では行かなかったのでメモ。

まず /etc/postfix/main.cf に以下を追記して、gmailの587番ポートに接続するよう設定する。

relayhost = [smtp.gmail.com]:587
smtp_use_tls = yes
smtp_sasl_auth_enable = yes
smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd
smtp_sasl_tls_security_options = noanonymous
smtp_sasl_mechanism_filter = plain
smtp_tls_security_level = secure
smtp_tls_CApath = /etc/postfix/certs

次に /etc/postfix/sasl_passwd にgmailアカウントの情報を記述する(YOUR.ACCOUNTとYOUR_PASSWORD部分は自分のものに書き換える)。

[smtp.gmail.com]:587 YOUR.ACCOUNT@gmail.com:YOUR_PASSWORD

そしてpostmapでデータベースを作成し、元のファイルは削除する。

# postmap /etc/postfix/sasl_passwd
# rm /etc/postfix/sasl_passwd

次に、GmailのSSL証明書を取得する。下記がコマンドの出力結果(+注釈)だけど、 注釈の通り証明書の鍵部分を /etc/postfix/certs/gmail.pem と /etc/postfix/certs/equifax.pem に保存する。

$ openssl s_client -connect pop.gmail.com:995 -showcerts
CONNECTED(00000003)
depth=1 /C=US/O=Google Inc/CN=Google Internet Authority
verify error:num=20:unable to get local issuer certificate
verify return:0
---
Certificate chain
 0 s:/C=US/ST=California/L=Mountain View/O=Google Inc/CN=pop.gmail.com
   i:/C=US/O=Google Inc/CN=Google Internet Authority
### ここから
-----BEGIN CERTIFICATE-----
MIIDWjCCAsOgAwIBAgIKaNGwUQADAAAirzANBgkqhkiG9w0BAQUFADBGMQswCQYD
VQQGEwJVUzETMBEGA1UEChMKR29vZ2xlIEluYzEiMCAGA1UEAxMZR29vZ2xlIElu
dGVybmV0IEF1dGhvcml0eTAeFw0xMTAyMTYwNDQwMzdaFw0xMjAyMTYwNDUwMzda
MGcxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1N
b3VudGFpbiBWaWV3MRMwEQYDVQQKEwpHb29nbGUgSW5jMRYwFAYDVQQDEw1wb3Au
Z21haWwuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCc8H+gCR0/95Tb
Lkj7jdj0oXmfGzsSswdSjo6yWdcHpjv6cbaakHakclxBs47M8Gs3fJxuNqVMpt2Q
YorJuoBuVZjM59/rIeJwmOwSlzf1POxpEFUvm1ASAeBnBheBt0Fv+BCfI8DjZKgn
SvHCqQJfNgxpJBXOLbFVjBsPqF8w6wIDAQABo4IBLDCCASgwHQYDVR0OBBYEFHzY
GJFnJ+gmONoIX6cyTAEl9ePYMB8GA1UdIwQYMBaAFL/AMOv1QxE+Z7qekfv8atrj
axIkMFsGA1UdHwRUMFIwUKBOoEyGSmh0dHA6Ly93d3cuZ3N0YXRpYy5jb20vR29v
Z2xlSW50ZXJuZXRBdXRob3JpdHkvR29vZ2xlSW50ZXJuZXRBdXRob3JpdHkuY3Js
MGYGCCsGAQUFBwEBBFowWDBWBggrBgEFBQcwAoZKaHR0cDovL3d3dy5nc3RhdGlj
LmNvbS9Hb29nbGVJbnRlcm5ldEF1dGhvcml0eS9Hb29nbGVJbnRlcm5ldEF1dGhv
cml0eS5jcnQwIQYJKwYBBAGCNxQCBBQeEgBXAGUAYgBTAGUAcgB2AGUAcjANBgkq
hkiG9w0BAQUFAAOBgQB0GTFAoMNxCFJ3aVMzvrZgCD9hG2Ee3Sx5GMQ0yDjcFvzS
ZIci9Gr18HMVBusIuFLw8TvBD7PEXtZLhh6hbj+Xdg9CIqlIjdqJFRixJU06xqKH
akIhNBDxy5ky3VugqlGdysbMjo/aXCFdl42GproXdUPH24Erljur885LklMk/g==
-----END CERTIFICATE-----
### ここまでを /etc/postfix/certs/gmail.pem に保存
 1 s:/C=US/O=Google Inc/CN=Google Internet Authority
   i:/C=US/O=Equifax/OU=Equifax Secure Certificate Authority
### ここから
-----BEGIN CERTIFICATE-----
MIICsDCCAhmgAwIBAgIDC2dxMA0GCSqGSIb3DQEBBQUAME4xCzAJBgNVBAYTAlVT
MRAwDgYDVQQKEwdFcXVpZmF4MS0wKwYDVQQLEyRFcXVpZmF4IFNlY3VyZSBDZXJ0
aWZpY2F0ZSBBdXRob3JpdHkwHhcNMDkwNjA4MjA0MzI3WhcNMTMwNjA3MTk0MzI3
WjBGMQswCQYDVQQGEwJVUzETMBEGA1UEChMKR29vZ2xlIEluYzEiMCAGA1UEAxMZ
R29vZ2xlIEludGVybmV0IEF1dGhvcml0eTCBnzANBgkqhkiG9w0BAQEFAAOBjQAw
gYkCgYEAye23pIucV+eEPkB9hPSP0XFjU5nneXQUr0SZMyCSjXvlKAy6rWxJfoNf
NFlOCnowzdDXxFdF7dWq1nMmzq0yE7jXDx07393cCDaob1FEm8rWIFJztyaHNWrb
qeXUWaUr/GcZOfqTGBhs3t0lig4zFEfC7wFQeeT9adGnwKziV28CAwEAAaOBozCB
oDAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFL/AMOv1QxE+Z7qekfv8atrjaxIk
MB8GA1UdIwQYMBaAFEjmaPkr0rKV10fYIyAQTzOYkJ/UMBIGA1UdEwEB/wQIMAYB
Af8CAQAwOgYDVR0fBDMwMTAvoC2gK4YpaHR0cDovL2NybC5nZW90cnVzdC5jb20v
Y3Jscy9zZWN1cmVjYS5jcmwwDQYJKoZIhvcNAQEFBQADgYEAuIojxkiWsRF8YHde
BZqrocb6ghwYB8TrgbCoZutJqOkM0ymt9e8kTP3kS8p/XmOrmSfLnzYhLLkQYGfN
0rTw8Ktx5YtaiScRhKqOv5nwnQkhClIZmloJ0pC3+gz4fniisIWvXEyZ2VxVKfml
UUIuOss4jHg7y/j7lYe8vJD5UDI=
-----END CERTIFICATE-----
### ここまでを /etc/postfix/certs/equifax.pem に保存
---
Server certificate
subject=/C=US/ST=California/L=Mountain View/O=Google Inc/CN=pop.gmail.com
issuer=/C=US/O=Google Inc/CN=Google Internet Authority
---
No client certificate CA names sent
---
SSL handshake has read 1714 bytes and written 316 bytes
---
New, TLSv1/SSLv3, Cipher is RC4-SHA
Server public key is 1024 bit
Secure Renegotiation IS supported
Compression: NONE
Expansion: NONE
SSL-Session:
    Protocol  : TLSv1
    Cipher    : RC4-SHA
    Session-ID: 763AA8A1EF5D5DDDF4C2B21BFBFF07D9F823908254EB257FA06E9B90A64F7199
    Session-ID-ctx: 
    Master-Key: 903CDFFC9EE4A6ACDC636BE72F8A82AFE7E088DA74918789653DC25978D4123F9333E2C6DE8F42A913C9A9CFE66857A3
    Key-Arg   : None
    Start Time: 1323177726
    Timeout   : 300 (sec)
    Verify return code: 0 (ok)
---
+OK Gpop ready for requests from 113.197.147.115 o7pf55469179pbh.0

c_rehashでエイリアスを作成。

# c_rehash /etc/postfix/certs

次に /etc/postfix/submit.cred を作成する。

# vim /etc/postfix/submit.cred

submitcred version 1
hostname|username|password

# chmod 600 /etc/postfix/submit.cred

以上で設定は終わったので、launchctlに登録する。

# vim /System/Library/LaunchDaemons/org.postfix.master.plist

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <key>Label</key>
  <string>org.postfix.master</string>
  <key>OnDemand</key>
  <false/>
  <key>Program</key>
  <string>/usr/libexec/postfix/master</string>
  <key>ProgramArguments</key>
  <array>
    <string>master</string>
  </array>
  <key>QueueDirectories</key>
  <array>
    <string>/var/spool/postfix/maildrop</string>
  </array>
  <key>KeepAlive</key>
  <true/>
  <key>RunAtLoad</key>
  <true/>
</dict>
</plist>

# launchctl unload -w /System/Library/LaunchDaemons/org.postfix.master.plist
# launchctl load -w /System/Library/LaunchDaemons/org.postfix.master.plist

これでメールが送信できるようになったはずなので、mailコマンドで送信してみる。

$ date | mail -s "Hello" "test.to@example.com"

ログは /var/logs/mail.log に吐かれる。

$ tail -f /var/logs/mail.log

キューはmailqで確認。

$ mailq

キューに溜まっているメールが削除したければpostsuper -dを実行。

# postsuper -d ALL

certificate verification failed が出たら

上記のようにSSLの設定をしても、次のようなエラーが出るかもしれない(実際自分は出た)。

certificate verification failed for smtp.gmail.com[74.125.53.109]:587: untrusted issuer /C=US/O=Equifax/OU=Equifax Secure Certificate Authority
1DD8918C646A: Server certificate not trusted
certificate verification failed for smtp.gmail.com[74.125.53.108]:587: untrusted issuer /C=US/O=Equifax/OU=Equifax Secure Certificate Authority
1DD8918C646A: to=<test.to@example.com>, relay=smtp.gmail.com[74.125.53.108]:587, delay=380, delays=363/0.07/17/0, dsn=4.7.5, status=deferred (Server certificate not trusted)

その場合は Fixing Postfix “certificate verification failed for gmail untrusted issuer” Error Message に書かれているEquifaxとThawteの2つの証明書をコピーしてくる。

# vim /etc/postfix/certs/equifax.pem

-----BEGIN CERTIFICATE-----
MIIDIDCCAomgAwIBAgIENd70zzANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJVUzEQMA4GA1UE
ChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2VydGlmaWNhdGUgQXV0aG9yaXR5
MB4XDTk4MDgyMjE2NDE1MVoXDTE4MDgyMjE2NDE1MVowTjELMAkGA1UEBhMCVVMxEDAOBgNVBAoT
B0VxdWlmYXgxLTArBgNVBAsTJEVxdWlmYXggU2VjdXJlIENlcnRpZmljYXRlIEF1dGhvcml0eTCB
nzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwV2xWGcIYu6gmi0fCG2RFGiYCh7+2gRvE4RiIcPR
fM6fBeC4AfBONOziipUEZKzxa1NfBbPLZ4C/QgKO/t0BCezhABRP/PvwDN1Dulsr4R+AcJkVV5MW
8Q+XarfCaCMczE1ZMKxRHjuvK9buY0V7xdlfUNLjUA86iOe/FP3gx7kCAwEAAaOCAQkwggEFMHAG
A1UdHwRpMGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEQMA4GA1UEChMHRXF1aWZheDEtMCsGA1UE
CxMkRXF1aWZheCBTZWN1cmUgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMBoG
A1UdEAQTMBGBDzIwMTgwODIyMTY0MTUxWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUSOZo+SvS
spXXR9gjIBBPM5iQn9QwHQYDVR0OBBYEFEjmaPkr0rKV10fYIyAQTzOYkJ/UMAwGA1UdEwQFMAMB
Af8wGgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUAA4GBAFjOKer89961
zgK5F7WF0bnj4JXMJTENAKaSbn+2kmOeUJXRmm/kEd5jhW6Y7qj/WsjTVbJmcVfewCHrPSqnI0kB
BIZCe/zuf6IWUrVnZ9NA2zsmWLIodz2uFHdh1voqZiegDfqnc1zqcPGUIWVEX/r87yloqaKHee95
70+sB3c4
-----END CERTIFICATE-----

# vim /etc/postfix/certs/thawte.pem

-----BEGIN CERTIFICATE-----
MIIDJzCCApCgAwIBAgIBATANBgkqhkiG9w0BAQQFADCBzjELMAkGA1UEBhMCWkExFTATBgNVBAgT
DFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYDVQQKExRUaGF3dGUgQ29uc3Vs
dGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEhMB8GA1UE
AxMYVGhhd3RlIFByZW1pdW0gU2VydmVyIENBMSgwJgYJKoZIhvcNAQkBFhlwcmVtaXVtLXNlcnZl
ckB0aGF3dGUuY29tMB4XDTk2MDgwMTAwMDAwMFoXDTIwMTIzMTIzNTk1OVowgc4xCzAJBgNVBAYT
AlpBMRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQBgNVBAcTCUNhcGUgVG93bjEdMBsGA1UEChMU
VGhhd3RlIENvbnN1bHRpbmcgY2MxKDAmBgNVBAsTH0NlcnRpZmljYXRpb24gU2VydmljZXMgRGl2
aXNpb24xITAfBgNVBAMTGFRoYXd0ZSBQcmVtaXVtIFNlcnZlciBDQTEoMCYGCSqGSIb3DQEJARYZ
cHJlbWl1bS1zZXJ2ZXJAdGhhd3RlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA0jY2
aovXwlue2oFBYo847kkEVdbQ7xwblRZH7xhINTpS9CtqBo87L+pW46+GjZ4X9560ZXUCTe/LCaIh
Udib0GfQug2SBhRz1JPLlyoAnFxODLz6FVL88kRu2hFKbgifLy3j+ao6hnO2RlNYyIkFvYMRuHM/
qgeN9EJN50CdHDcCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQQFAAOBgQAm
SCwWwlj66BZ0DKqqX1Q/8tfJeGBeXm43YyJ3Nn6yF8Q0ufUIhfzJATj/Tb7yFkJD57taRvvBxhEf
8UqwKEbJw8RCfbz6q1lu1bdRiBHjpIUZa4JMpAwSremkrj/xw0llmozFyD4lt5SZu5IycQfwhl7t
UCemDaYj+bvLpgcUQg==
-----END CERTIFICATE-----

もう一度c_rehashでエイリアスを作成してpostfixを再起動する。

# c_rehash /etc/postfix/certs
# launchctl unload -w /System/Library/LaunchDaemons/org.postfix.master.plist
# launchctl load -w /System/Library/LaunchDaemons/org.postfix.master.plist

equifax.pemは前述の通り最新の情報で作成したけど、なぜか内容が異なっている。でもこれで動いている。Thawteはもう使えなくなったというから使われないはずだし…。ちょっとよくわかっていない。

参考

ActiveRecord3.1/mysql2でTRUNCATE Dec 7

DatabaseCleanerを使うと 複数データベース(各種RDBMSやMongoDB、CouchDBなどなど)に対応した方法でデータを削除できるんだけど、複数のDBにコネクションをはっている場合にはうまく動いてくれないことがあるらしい

でも自分の場合、mysql2でうまく動いてくれればそれでいいし、わざわざDatabaseCleanerを使う必要はないよなぁ…。ということで、ActiveRecord::ConnectionAdapters::Mysql2AdapterにTRUNCATEを発行してくれるメソッドを生やしてみた。実質DatabaseCleanerのコピペ。

module ActiveRecord
  module ConnectionAdapters
    class Mysql2Adapter < AbstractAdapter
      def truncate_tables
        tables_to_truncate.each do |table_name|
          truncate_table(table_name)
        end
      end
      def truncate_table(table_name)
        execute("TRUNCATE TABLE #{quote_table_name(table_name)};")
      end
      private
        def tables_to_truncate
          tables - views - ["schema_migrations"]
        end
        def views
          @views ||= select_values("select table_name from information_schema.views where table_schema = '#{current_database}'") rescue []
        end
    end
  end
end

次のようにtruncate_tablesを呼ぶと、ビューとschema_migrations以外に対してTRUNCATEを発行してくれる。

ActiveRecord::Base.connection.truncate_tables