しょ〜うぃん広場

おもにTech系なブログ、ときどき個人的なブログ

MacでVPNを繋ぎっぱなしにするAppleScript

MacVPNを繋ぎっぱなしにするAppleScript を90%コピペで作成した。 中国にいるときはTwitter,Facebookとか見るために常時VPN使ってるし、 べつにVPN繋ぎっぱなしでもデメリットないから、ずっと繋げておくことにした。 (国内にいても、家からニコ動に繋ぐと途中の回線がどこか細いらしくてかなりプツプツするので、VPN使ったりする。)

VPN AppleScript」とかググると下のようなコードがいくつか出てくるんだけど、 2箇所だけ変更した。

on idle
  tell application "System Events"
    tell current location of network preferences
      set myConnection to the service "My VPN"
       if myConnection is not null then
        if current configuration of myConnection is not connected then
          display notification "Connecting VPN..."
          connect myConnection
        end if
      end if
    end tell
    return 15
  end tell
end idle

変更したのは7行目と12行目。

7行目で画面右上にNotificationを出してる。 再接続するときに"Connecting VPN..."と表示するようにした。 「気づかないうちに接続切れてて、知らないうちにに再接続される。」 みたいなことされると、気づかないうちにSSHのパイプ切れたりするから 一応繋ぎますよ〜って通知出すようにした。

12行目はVPNが繋がってるかどうかを確認する周期を15秒にしてる。 「ん?なんかサーバーからのレスポンスない!?」と思ってリロードするまでにだいたい15秒ぐらいな気がしたから、15秒以内に再接続されるようにしておくと、いいかなと思った。

あ、そうそう。 使うときには4行目の"My VPN"をここの名前に変えてね。
Screen Shot 2014-07-30 at 10.56.10

上のAppleScriptを使ってアプリケーションを作成する方法は Mac OS X起動時にVPNで自動接続&途切れても再接続するように設定できる を参考に。

参考サイトに書かれているように、アプリアイコンをDockに表示させないようにすると "VPN Auto Connect" のアプリを終了することができなくなる。

どうしても終了したいときにはターミナルで

$ kill -9 `ps -ax | grep '[V]PN Auto Connect' | awk '{print $1}'`

とやってあげると終了できる。

  へへへ、これで中国でのネット生活も充実するぜ

【Rails】GitHub Webhooks + Sinatraで自動デプロイ環境を作った

今までRailsWebサービス開発するときには、
1. ローカルで開発
2. GitHubにPush
3. サーバーにSSH
4. サーバーでGitHubからPull
5. Apacheの再起動

とかかなり原始的な方法をやってたんだけど、さすがに面倒に感じてきたので 3~5の手順を自動化しようと思って、やってみた。

Railsでデプロイ自動化といえばCapistranoが定石っぽいけど、 なんか設定めんどくさそうだし、バージョン管理しようとすると $ git push $ cap deploy とか2つコマンド実行しないといけなさそうだし、 Capistrano複数個のサーバーにデプロイできるけど、 そんな機能はぼくにとってオーバースペックだし… ってな感じで、Capistranoはパス。

最近は「GitHub 時代のデプロイ戦略」に書かれているみたいに、CIを使うのがナウいらしいけど、個人でそこまでやるのは… ってな感じで、CIはパス。

まぁ若いうちはできあいのものに頼るなってのもあるし(適当) WebHookしてみたい!って憧れもあったので、今回はGitHub Webhooks + Sinatraという形で作ってみた。

 

ここから本題

作成したコードはGitHubにおいてあるので、適当にcloneして、適宜書き換えてください。 GitHub: Automatic-Deploy-Tool-for-Rails

今回はhttp://example.comRails appが動いてるとして、http://deploy.example.comGitHubからPOSTリクエストを投げてもらうことにしました。 Apatcheの場合は/etc/httpd/conf/httpd.confをこんなふうにすればいいと思います。 Passengerの方の設定は変更の必要はありませんでした。

<virtualhost *:80>
 servername example.com
 serveralias www.example.com
 documentroot /var/www/example/public
 railsbaseuri /
 <directory /var/www/example/public>
   allowoverride all
   order allow,deny
   allow from all
   options -multiviews
 </directory>
</virtualhost>
 
<virtualhost *:80>
 servername deploy.example.com
 serveralias deploy.example.com
 documentroot /var/www/deploy/public
 RackEnv production
 <directory /var/www/deploy/public> 
   allowoverride all
   order allow,deny
   allow from all
   options -multiviews
 </directory>
</virtualhost>

/var/www/deployのところにAutomatic-Deploy-Tool-for-Railsを配置します。

$ cd /var/www/
$ git clone https://github.com/showwin/Automatic-Deploy-Tool-for-Rails.git
$ mv Automatic-Deploy-Tool-for-Rails deploy
$ cd deploy/
$ echo '<Rails-app path> <root-user password>' >> pathpass.txt
$ touch log.txt

[Rails-app path]はデプロイしたいディレクトリのパス、今回だと/var/www/exampleになります。 [root-user password]はApacheを再起動する際($ sudo service httpd restart)に使うものです。

 

最後にGitHub WebHooksの設定。 管理したいレポジトリのページに行って、 画面右側メニューの「Settings」→「Webhooks & Services」→「Add Webhook」 でPOSTリクエストを送りたいURLを指定できます。 今回であればhttp://deploy.example.comを指定します。

以上!

完成

これでGitHubにPushすると以下の4つのコマンドを行ってくれます。

$ git pull origin master
$ rake assets:precompile RAILS_ENV=production
$ rake db:migrate RAILS_ENV=production
$ sudo service httpd restart

かんたんだな〜 (いろいろハマってこれ作るのに4時間かかったけど…)


なんか手順書き忘れてる気がしないでもないので、うまくいかなかったら @showwinに連絡ください。

GitHub Webhooks + Sinatra のJSON Parseでハマった

題名のとおりです。

いろんなサイトを見ていると GitHubのサイトに以下のようなSinatra向けのサンプルがあって…

post '/' do
  push = JSON.parse(params[:payload])
  "I got some JSON: #{push.inspect}"
end

とか書かれてたから、そのままやってみたんだけど どうもJSON.parseの部分で引っかかってうまくいかない。

と思ってGitHubのWebHookの説明サイトに行ったら、サンプルコードが変わっていた!!

post '/payload' do
  push = JSON.parse(request.body.read)
  puts "I got some JSON: #{push.inspect}"
end

JSON.parse(params[:payload])JSON.parse(request.body.read)に変えたらイケた。

Sinatra詳しくないし、JSONも詳しくないから、 どこのバージョン変更で動かなくなったのかよくわからないけど、 ここで2時間ぐらいハマったので、一応備忘録として残しておく。

MacでSSL証明書を復元する

すみません、タイトルは誤りです。

自分が困ったときに「Mac SSL証明書 復元」とかググったので、タイトルこの方がみんな来るかなーとか(笑

あれですよね、OS X 10.9.2になってからGitHubにアクセスするときにSSLの証明書がどーとかこーとかで、上手くアクセスできないから、あるSSL証明書を削除しましょう! みたいなことがあるじゃないですか。

[参考]http://orangain.hatenablog.com/entry/2014/03/01/mavericks-ssl-certificate

で、ぼくもそれと同じことをやるんですけど、今回のこの作業をやるのが3回目で、

「あぁ、またこれか、"DigiCert ..."とかいうやつ消せばいいんでしょ」

と思って、一番最初に見えた"DigiCert"なんとかってやつを消しちゃったんですよ。

そうしたら、本当は必要だったSSL証明書を削除してしまったみたいで、 もちろんGitHubは見れないままだし、Twitterとかその他サイトも見れなくなってしまって…

あ、これ間違ったわ。復元しよう!と思ったんですけど、

上の参考をページ見るとこう書いてあるんですよね。

注意:証明書の削除は間違って行うと、正常なWebサイトにアクセスした時にも警告が出るようになり、元に戻せません。自己責任で行ってください。

はい、事実です。Keychainの初期化とかしても証明書は消えたまま… ググっても解決方法出てこない。(他にこんなバカな事する人いないのかな…) もしかして、、、OSクリーンインストール…(泣)

とか思ったんですけど、そんな事する必要ありませんでした。 というお話。

前置き長いですね。

 

結論

DigiCertの証明書を消してしまったなら http://www.digicert.ne.jp/howto/basis/digicert-root-certificates.html からダウンロードしろ!

 

SSLの仕組みを理解しないといけませんでした。

そもそももとからMacに入っているSSLサーバ証明書はなんのために使われているのか。 (以下間違っていたらすみません)

SSL通信するサイトにアクセスするときに、そのサーバが持っているSSLサーバ証明書が本当に信用できる証明書かどうかをまず判断するようです。 そこで、その判断に使われるのが、最初からOSに入っている証明書。(正式名称:クライアント証明書)

クライアント証明書によって「あぁ、このサーバの証明書信用できるよ!」ってわかると、そこのサーバーから公開鍵をもらって、セキュアな通信をするようですね。

 

それで、そのクライアント証明書はSSLサーバ証明書を発行している機関からダウンロードできるみたいです。 今回僕はDigiCertのクライアント証明書を消してしまったので、公式HPからダウンロードしてきて、Macに適用(インストール?)しました。

インストールするには、ダウンロードしてきたファイルをダブルクリックするだけです。 「証明書を追加しますか?」 みたいなことを聞かれるだけなので、Yes!したらすぐに完了しました。

おしまい。

 

いやぁ、あの時本当に焦ったけど。直ってよかった。

中国で2ヶ月半インターンをしてきた

2月17日からおととい(4月30日)まで約2ヶ月半中国でインターンをしてた。

中国でインターンをやることになった経緯とか、インターンの内容とかいろいろまとめて書こうと思う。

なぜ中国でインターン

僕は4月から大学4年生になって、大学院には行かずに中国で就職しようと思っている。 大学院に行かずに、中国で就職する理由は簡単に書くと ・成長率が高いうちに中国で仕事/生活をしてみたい ・(年配者と比べて)グローバル意識の高い若者がそろそろ社会の中心になって、ネット規制が強い中国で大きな変化が起きると思ってる ・彼女が中国人 ・若い時にしかいろいろな経験ができないから、とりあえず海外で苦労してみる とか、そんなもん。

それで、中国で就職するのに、中国に留学したこともないし、中国の仕事文化も知らないし… じゃちょっとヤバそうだから、とりあえずインターンしとこうか! みたいな流れ。

どうやってインターン先が決まったの?

基本的には中国人向けのサイトで適当に探して、適当に応募した。 (日本で言うリクナビ的なやつ? 日本でマジメに就活してないからよくわからないけど…)

あとは、彼女の知り合いが勤めてる会社を紹介してもらったり。

結果的に彼女の知り合いつながりで今回のインターン先は決まった。 インターン先はソフトウェア開発会社で、日本のグループ企業が受注した案件をこっちで開発するという、要は下請け企業。

  インターンまでの選考は
1. 履歴書(中国語)提出
  ↓
2. Skypeで面接 (口頭で問題を出されることもある)
  ↓
3. 合格

中国の企業は選考の途中で落とされると、その後全く連絡が来なくて 落とされたのか、まだ選考途中なのかわかりにくい。。。 企業と就活生が対等に扱われていない感じ。(企業>>就活生)

インターンどうだった?

7:30 起床 8:30 出発 10:00 会社到着 午前 自分のやりたいことやる(基本的に自分のWebサービスの開発) 午後 会社の仕事 18:00 退社 20:00 帰宅

という生活をしてた。 他のインターン生は午前中に日本語の授業があるんだけど、ぼくはそんな授業受ける意味はないから、自分でやりたいことやってた。 同じ部屋で作業してたから、日本語の授業も耳には入ってきていて、日本語ってこうやって教えるんだ〜とか、先生の発音違うな〜とか、この日本語はこういう中国語の表現なのかとかいろいろ勉強になった。

午後はプログラミング演習的な感じ。 基本的にJavaSAStrutsってフレームワークを使って、開発をしているから、そのフレームワークの使い方とか、ユニットテストの仕方とかを勉強した。 周りのインターン生は(おそらく)中堅大学以下(Dラン大学?)ぐらいのレベルで、あまり頭が良くないのはインターンが始まってすぐに分かった。 だから、開発速度とかもちょっと遅くて、僕がコミットしたコードをそのままコピーして使っているらしかった。 (みんなで似たような機能を開発していたんだけど、「ちょっと助けて〜」って呼ばれて行くと、自分のコードがそのままコピペされてた) (しかも後半に開発していたものは全員が同じ機能を作るものだったから、「伊藤くんが作ってくれるから、それコピーしようぜ!」とか言ってて、おいおいって感じだった。だから完成するまでぼくはワザと1回もコミットしなかった。笑)

通勤時間が毎日3時間あって、大変といえば大変だけど、それなりに価値のあることができた。 通勤に3時間もかかるのは、会社の近くに家を借りて住んでいたわけじゃなくて、彼女の家に住ませてもらっていたから。彼女の両親に感謝。 それで、通勤時間は ・技術系のPodcast(rebuild.fm)を聞く(35%) ・中国語の勉強(25%) ・ゲーム(25%) ・音楽を聞く(15%) をやっていた。

rebuild.fmは結構オススメで、このPodcastの影響で技術への関心が高まった。 ゲームはiPhoneドラクエ4とか、ゲームボーイアドバンスのソフトをエミュレータで動かしたりして遊んでた。

  肝心の給料は、時給144.5円(JPY)だった。毎月2万円程度。 この値段は杭州市のインターン最低賃金。 ちなみにこの会社の初任給は6万円らしい。 この会社は日本と取引してるのに、社内に日本人がいないらしく、どうしても僕に働いて欲しいらしい。 だから、毎月20万円くれたら、あんたの会社で働くよ。ってマネージャに伝えてみたら、「それは僕と同じぐらいの給料ですよ〜」って言われて、これはヤバイと思った。 (ちなみに、中国の東大、京大レベルの大学の卒業生(理系)の初任給は15万円前後) まぁあんまりお金なくて、資金繰り大変そうだなーというのはインターンをしていても感じるところがあって、(働いている人のレベルも低いし)、給料高く貰えないならこの会社ではちょっと働きたくないかなぁという感じ。

集合写真 集合写真 (真ん中右に写ってて、社員証の紐の色が違うのがマネージャ。僕がどれかは秘密!笑)

帰国後

明後日(5月4日)のフライトで帰国する。 1週間前ぐらいから大学の研究室の課題が出てたり、帰ってから健康診断の申し込みとか事務的な事もしないといけなくて、忙しくなりそう。

秋にまた中国に行って就活するから、論文も夏休みにかなり進めないといけないし、今年度はそれなりに頑張らないといけないらしい。 まぁわざと忙しくさせるために、大変そうな研究室選んだんだけども…笑

大学院には行かないから、4年生の1年間のうちに1.5~2年間分ぐらい頑張りたいなと思ってる。

さくらVPSにBitTorrent Syncを導入した

1ヶ月前ぐらいからRebuild.fmの存在を知って、#1から順に気になるもの(全体の7割ぐらい)を聞いている。

#30BitTorrent Syncの話をしてて、これは使えそうだなーと思ったから環境構築をしてみる。 BitTorrent Syncというのは、DropBoxP2Pバージョンみたいなやつで、つながっている端末同士でファイルを同期することができる。 要は ・高速 ・メインサーバーなし(全てが同等の扱い) ・容量無制限 なDropBoxだと思ったらいい。 しかもReadOnlyの設定とかできて、共有した相手に消されないようにもできたりするから優秀。 悪い点は、電源が入っていないと同期が取られないという点。

どうやって使うかはまだ決めてないけど、とりあえず常に電源が入っているサーバーをP2Pネットワークに含めると随分と使いやすくなるから(弱点克服)、まずはさくらVPSに入れる。

下の2つのサイトを参考にして導入した。
[参考]CentOSにBittorrent Syncを導入する
[参考]How to install and configure a BitTorrent Sync server

まず、どちらともroot権限で実行したと書いているけど、別にroot権限にしなくても問題なくできた。

$ cd 
$ mkdir btsync
$ cd btsync
$ wget http://btsync.s3-website-us-east-1.amazonaws.com/btsync_x64.tar.gz
$ tar -xvzf btsync_x64.tar.gz

HOME以下にbtsyncディレクトリを作って、そこにBitTorrent Syncを持ってくる。そして解凍。 さくらVPSの場合には64bitなので上のURLから。 32bitの場合にはhttp://btsync.s3-website-us-east-1.amazonaws.com/btsync_i386.tar.gzから持ってくるらしい。 (32bitの方は試してないので、間違っていたらゴメンナサイ)

$ ./btsync --dump-sample-config > btsync.conf

このコマンドでbtsync.confにサンプルの設定を書き込む。 コマンドの説明をしておくと、[./btsync --dump-sample-config]のコマンドを打つとサンプル設定がダラダラ流れてくるから、それをbtsync.confに書き込むというコマンド。

設定ファイルの中身を書き直す btsync.conf

{
   "device_name": "showwin VPS in Japan",
   "listening_port" : 55555,  // 0にするとランダムになる。固定したかったので適当な値を決めた

   "storage_path" : "/home/showwin/.sync",  //ログとかがたまるらしい。よく分かってない…笑

   "check_for_updates" : true,
   "use_upnp" : true,

   "download_limit" : 0,     //ダウンロード時の回線速度制限。0なら無制限
   "upload_limit" : 0,       //アップロード時の回線速度制限。0なら無制限

   "webui" :          //WebUIの設定
   {
     "listen" : "0.0.0.0:8888",  //8888ポートで使えるようにする。適当な値でOK
     "login" : "********",        //ページにアクセスした際の認証に必要
     "password" : "********"      //同上
   }
 }

こんな感じ。 どんなオプションがあるのか、まだよく分かってないから、これからもうちょっと調べてみる。

あとはiptablesの設定。 /etc/sysconfig/iptables

# BitTorrent Sync 
-A OUTPUT -p tcp --dport 55555 -j ACCEPT
-A OUTPUT -p udp --dport 55555 -j ACCEPT
-A INPUT -p tcp --dport 55555 -j ACCEPT 
-A INPUT -p udp --dport 55555 -j ACCEPT 
-A INPUT -p tcp -m state --state NEW -m tcp --dport 8888 -j ACCEPT

を追加した。

$ /etc/init.d/iptables restart

iptablesを再起動。

$ ./btsync --config btsync.conf

最後にbtsync.confの設定でbtsyncを起動させればOK! これでxxx.xxx.xxx.xxx:8888にアクセスすればGUIのコントロールパネルが見れるはず。

Screen Shot 2014-04-29 at 13.51.17 (クリックで拡大)

次は使ってみた感想を書くつもり。

Ruby-OpenCVを使って顔認識をしてみた

昨日から個人的に始めたあるプロジェクトのために、まずは顔認識をしてみた。 (プロジェクトに関しては、ネット上を漁ればどこかに見つかるはずです…笑)

はじめに

OpenCVというのはOpen Source Computer Vision Libraryの略称らしくて、 インテルが開発したものらしい。(via Wikipedia)

それをRubyで扱えるようにするのがRuby-OpenCV

・(前半) インストール ・(後半) 顔認識 の二本立てで行きます。

(前半)インストール

下のページを参考にしながら顔認識していきます。 [参考]ruby-opencvをインストールして顔認識した

まずはOpenCVをインストールして、その後にRuby-Open

$ brew tap homebrew/science

$ brew info opencv
> opencv: stable 2.4.8.2

$ brew install opencv
# opencvのインストール完了

$ gem install ruby-opencv

ってやるだけなんだけど、 OpenCVのインストールでコケた。

$ brew install opencv
> ...
> undefined method `[]' for Formula:Class

解決方法

$ brew update
$ brew install opencv

イケた homebrewの問題だった。

 

(後半)顔認識

続いて顔認識の部分

画像を読み込んで、顔が見つかれば赤い四角で囲って出力するようにした。

分類器は

/usr/local/share/OpenCV/haarcascades/haarcascade_frontalface_****.xml

にあるものを持ってきて使う。 ****の部分には ・default ・alt ・alt2 ・alt_tree の4種類があったので、それぞれ使ってみてどれが優秀なのか調べてみた。

それぞれがどういう特徴をもった分類器なのかわからないけど、 2種類の画像を使って性能を比較してみた。

※もちろん、モザイクは顔認識をした後にかけています。 ※画像はクリックで拡大できます

 

・default

かなりミスが多い。多く間違えてもいいけど、顔を逃したくない時に有効? (と思ったけど、左側の写真の右側の顔を捕らえてなかった。。) test3_default test2_default 

 

・alt

これが一番精度が高かった。完全に捕らえられてる。 test3_alt test2_alt 

 

・alt2

左側の写真の左下に余分な"顔"が捕らえられてる。 test3_alt2 test2_alt 2 

 

・alt_tree

左側の画像では顔を捕らえられていなかったり、右側の画像では余分な部分まで検知していたり。。。 test3_tree test2_tree 

結論&実装

ということで、とりあえずaltが良さそうだった。

画像サンプル3つでやったから、信頼できるかは別だけど… これから大量の画像に対して顔認識させる予定だから、 またその時にも、どの分類器が適しているのか実験してみよう。

以下コード。 コメントを書いてあるので、詳しい説明はいらないですね。

require 'opencv'
include OpenCV

if ARGV.size < 2
  puts "Usage: ruby #{$0} input.jpg output.jpg"
  exit 1
end

input_file = ARGV.shift #一つ目の引数がinput
output_file = ARGV.shift #二つ目の引数がoutput

image = nil
begin
  image = IplImage.load input_file, 1  #インプットファイルを読み込む
rescue
  puts 'Could not open or find the image.'
  exit
end

#分類器の指定
detector = CvHaarClassifierCascade::load './detector/haarcascade_frontalface_alt.xml'

#検出された顔に対してどんな処理を行うか
detector.detect_objects(image).each do |region|
  image.rectangle! region.top_left, region.bottom_right, :color => OpenCV::CvColor::Red
end

image.save output_file

ブログのために写真のサイズ変更したり、モザイクかけたり大変だったわ…