技術メモの最近のブログ記事

今や会社でもドキュメントをGoogle Docsで作成してメンバー間で共有することは珍しくないと思うのですけど、これをやると、メンバー管理問題が発生します。
「もぎゃさーん、Aのドキュメント見えないので権限追加してください」「はいはい」
「Bさんが、ホゲホゲのドキュメントに対する編集権限をリクエストしています」
「ぼく総務部じゃないんだけど!」


ダイナミックに人が増えたり減ったりする組織になると、ドキュメント一個一個に対して共有なんてしてられないのですよね。

一般にこういう問題に対してはGoogle Apps For Workを使うことが勧められているのですけど、これだと自社ドメインのメールアドレスを持った人しか管理できないのですよね。

で、Googleグループ。実はGoogle DocsにはGoogleグループを指定して共有する機能があります。

tmp_txt_-_Google_ドキュメント_15_33_45.png

こうしておくと、Googleグループに参加している人に対してまとめて権限を付与できるようになるので、新しいメンバーが参加した時も、誰かいなくなった時も、Googleグループのメンバー管理機能を使って管理することが出来るようになります。
自社ドメインじゃないgmail.comのユーザーも追加できるし、いまやGoogleアカウントはgmail以外でも使うことができるので、実質的にどんなメールアドレスでも管理することができるのがメリットですね。

Google_グループ.png


「sar -r」でメモリと一緒に把握するように書いている記事が多いけど、それはsysstat7までの話で、sysstat8からはスワップメモリについて出力する"sar -S"というmetricsが追加されている。近年のlinuxマシンだったら、ほとんどは"sar -S"を使うことになるはず。
$ sar -r
Linux 3.12.9-x86-linode56 (linode6.mogya.com) 02/16/14 _i686_ (8 CPU)

00:00:02 kbmemfree kbmemused %memused kbbuffers kbcached kbcommit %commit
00:10:01 28284 998736 97.25 90452 435064 582540 45.19
00:20:01 27424 999596 97.33 90720 435080 582388 45.18
00:30:01 25792 1001228 97.49 90920 435264 584120 45.31
00:40:01 60456 966564 94.11 93360 400776 582312 45.17
00:50:01 60024 966996 94.16 93560 400812 582492 45.18
$ sar -S
Linux 3.12.9-x86-linode56 (linode6.mogya.com) 02/16/14 _i686_ (8 CPU)

00:00:02 kbswpfree kbswpused %swpused kbswpcad %swpcad
00:10:01 254208 7932 3.03 2496 31.47
00:20:01 254208 7932 3.03 2496 31.47
00:30:01 254208 7932 3.03 2496 31.47
00:40:01 253928 8212 3.13 2492 30.35
00:50:01 253928 8212 3.13 2492 30.35
SYSSTAT Features
man SYSSTAT


Preferences.sublime-settings.png

Sublime Text 2で以前から気になっていた問題。command+Fで検索パネルが開くのだけれど、カーソルで文字列を選択した状態でcommand+Fしたら選択された単語を検索してほしい。
秀丸エディタがそういう挙動だったので、これがないととっても不便。

機能としてはslurp_find_stringというコマンドがあるみたいなので、いっそプラグインを書くか、と思って色々調べていたのだけれど、設定一発でできることが判明しました。command+,で設定画面を開いたら

"find_selected_text": true

を追加するだけ。

関連する不満だった、検索パネルを開いた時カーソルが検索後の後ろにいる(そのまま文字を入力したら以前の検索語の後ろに入力される!)という謎仕様も、この設定で改善されます。検索パネルを開いたら検索語が選択された状態で開くから、command+aで単語を上書きしなくても、そのまま検索語を入力することが出来ます。




gmap.jpg

四隅の緯度経度を渡したら範囲内のスポット情報が得られる、というAPIは最近そこら中にあって、 これとGoogleMapsAPIを組み合わせて地図上に何らかのスポットを表示する、というのもそこら中で行われています。

こういうサービスを実現するためには、ユーザーが地図の表示位置を変更した時、新しい位置のスポット情報を取得して表示するためにAPI呼び出しをする必要があります。
この実装例をググると、bounds_changed(領域が変化した時)やdragned(ドラッグが終了した時)イベントのタイミングでAPIを呼び出すようにしている実装が多いのですけど、idleイベントを使うとすごい綺麗に実装することが出来ます。
以下、bounds_changedやdragnedを使った場合に発生する問題と、idleイベントだと何がうれしいのかをまとめました。

bounds_changedを使った時の問題

bounds_changedイベントは、「This event is fired when the viewport bounds have changed.」と定義されていて、地図の表示領域が変更になった場合に発生するイベントです。
このタイミングでAPIを呼び出すようにすれば、ユーザーが地図をドラッグした時も、ズームが変更された時もイベントが発生するので、わりといい感じに動くように思えます。

bounds_changedイベントの問題は、発生頻度が多すぎることです。bounds_changedは領域が変わるたびに呼ばれるので、ユーザーが地図をドラッグすると、一秒に数回の勢いでbounds_changedイベントが発生し続けます。
つまり、単純に実装すると、秒間数回のペースでAPIを呼び出し続けることになります。サーバ負荷の観点から絶対止めてほしいですし、ブラウザ側だって、そんな頻度で結果が帰ってきたら処理しきれなくてブラウザが固まってしまうことが予想されます。
カウンタをもうけて10回に一回だけAPIを呼び出すとか、タイマーを使って何秒に一回だけAPIを呼び出すとか、やってやれないことはないのですが、ずいぶん複雑なコードになってしまいます。

dragendを使った場合の問題

dragendイベントでAPIを呼び出すという実装も考えられます。ドラッグ終了時に一回だけ発生するので、その点はいいのですけど、今度はイベントの発生が少なすぎて弊害が発生します。
ズーム変更の時スポットが更新されない

さすがにこれは誰でも気づくので、dragendとzoom_changedでAPIを呼び出す実装にする人が多いと思います。

ドラッグが終わるまでAPIが呼び出せない

dragnedイベントはマウスを放すまで発生しないので、地図をドラッグしながら「この辺かなー?」って考えてもスポットが更新されません。ダメじゃないですけど、ユーザーフレンドリーじゃないですよね。

キーボードで地図を移動させた時APIが呼び出せない

そんな人はあまりいないと思うけど、GoogleMapsはキーボードでも操作ができるようになっています。この場合dragendイベントは発生しません。
また、最近のGoogleMapsは駅などをクリックするとその部分が中央に移動して詳細がポップアップするようになっていますが、この移動の場合もdragendイベントは発生しません。

自分でsetCenterイベントを呼んだ時も発生しない

これが最大の問題で、例えば検索フィールドを作って入力された住所の位置に移動するような実装をする場合、ジオコーディングして得られた緯度経度にmap.setCenterすることになると思うのですけど、この場合もdragendイベントは発生しません。 setCenterを呼び出す時は自前でAPI呼び出しをするコードを追加して・・・(後日APIが変更になった時、片方だけ変更しわすれてバグを埋め込むパターン)

dragendを使った場合の問題

こんな具合にして、起こりうる各種問題に場当たりの対応を繰り返すと、複数のイベントを組み合わせてフラグ管理をすることになったり、コード中のあちこちからAPIを呼び出すことになったり、どうしても複雑なコードになってしまいます。
実際僕もそうやって書いていたのですけど、ある時、idleイベントで全部カバーできることに気づきました。

idleイベントは「This event is fired when the map becomes idle after panning or zooming.」と定義されています。

実際ログを入れて試してみるとわかりますが、
  • Mapをnewすると、地図の表示が終わった時点で一回発生します。つまりここで、最初の一回目のAPI呼び出しを行うことが出来ます
  • 地図をドラッグしおわった時に一回発生。ドラッグ中も、ちょっと手を止めるとそこで発生。idleにならないと発生しないので、API呼び出しが多くなりすぎる心配がありません。
  • ズーム変更の時も発生
  • キーボードで地図を動かした時も発生
  • setCenterやsetZoomを呼び出した時も移動直後に発生
と、理想的な挙動を示します。つまり、HTML表示直後の一回もマップ移動時のAPI呼び出しも、全部まとめて
      google.maps.event.addListener(self.gmap, 'idle', function() {
        //ここでAPI呼び出し
      });
としておくだけで意図した動作をさせることが出来ます。


経路探索

iPhone上で、
http://maps.google.com/maps?saddr=My%20Location&daddr=[title]@[lat],[lng]&z=15
という具合に、「My Location」から目的地までの経路を探索させると、GPSで現在位置を取得して現在位置から目的地までの経路を示してくれる、という小ネタがあります。例えば電源検索では、この挙動を利用して現在位置からカフェまでの経路を表示してもらっています。

iOS6でMapsアプリはAppleMapに置き換わってしまいましたが、この機能自体はブラウザ版のGoogleMapsでも動作するので、iPhone5でも使うことが出来ます。

ところが最近、なんか仕様変更があったらしく、「My Location」が現在位置に置き換わらなくなってしまいました。健気に「My Location」という地名を検索して無意味な経路を表示しようとしてしまいます。 mylocation.png
ドキュメントに明示されていた機能じゃないので、なくなってもしょうがないのですが、同等の機能はどうにかして実現したいところです。

いろいろ試した結果、こうやると実現できるっぽいことがわかってきました。
http://maps.google.com/maps?daddr=[title]@[lat],[lng]&z=15
saddr(出発地点)の指定を省略すると、勝手に現在位置で補完してくれるみたいです。

これもドキュメントに明示されていない挙動なのでいつまで動くか怪しいのですが、「My Location」を置き換えるよりは筋がいい動きだと思うので、自分のアプリに関しては、当面これで実装しておこうかなーと思っています。


sxc_hu_738173_map_money.jpg

ブログやWEBサイトに地図を表示することが出来て大変便利なGoogleMapsAPIに関して、Googleが有料化を発表したのでビックリしました。

 Googleは、Google Maps APIの利用規約を今年4月に改定し、10月1日から同APIの利用上限を定めることを発表していた。
 現時点で利用上限を超過しても、即座に課金されることはない。利用者には、APIの利用状況を確認する期間が与えられる。その上で、利用上限を超えている場合には「2012年初めごろ」から強制的に課金されるとしている。その場合は、最低30日前に通知されるとしている。
(Google Maps API有料化の詳細発表、該当ユーザーは2012年初めに強制課金開始 -INTERNET Watch)

今一番知りたいことは「どれくらい使ったら課金されるようになるのか」だと思うのですが、自分が調べた範囲では、あまり気にしなくてよさそうです。根拠はこれだ!

maps_limit1.png
(FAQ - Google Maps API Family - Google Code)

Styled Maps というのは最近出来た機能で、GoogleMapsから線路を消したり海の色を変えたりといったデザイン変更が出来る機能です。こちらを使っている場合はちょっと厳しいのですけど、そうでない場合は 25,000 map loads / Day。1ページに大量の地図を埋め込むことは普通ないので、つまり実質25,000 PV/Day ≒ 75万PV/月ということになります。
モバイラーズオアシスが10万PV程度なので、食べログさんとか、大手不動産業者さんレベルにならない限りは課金されないんじゃないかと。30min.さんあたりが微妙なラインかなぁ。

さらに上記ページを見ると、越えた場合の課金金額も書かれています。

maps_limit2.png
(FAQ - Google Maps API Family - Google Code)

25,000を越えたあと、1,000usageごとに4$だそうです。例えば100万PV/月のサイトがあったとすると、約3万3千アクセス/Dayなので超過部分が8300usage=$32。$960/月なので、76,800円/月ということになりますね。
ちなみに、Google Maps API Premier、お値段を公開している代理店を見つけました。85万円/年~だそうです。
GOGA - Google Maps API

追記:Google Maps API Expertの方からコメントがいただけました。
回数は、APIライブラリの読込回数です。
ANN:Google Maps APIへの使用制限の導入について - Google-Maps-API-Japan | Google グループ
ということは、iPhoneアプリなんかは、アプリを起動して地図を表示するごとに1回と考えれば良さそうですね。


sxchu_785076_small.png

待って待って待って~!
今日は AV女優.com で行っているサーバ監視を魚に、 小規模ウェブサービス向けのサーバ監視 についてまとめます。
(中略)
監視サーバと呼べるのは1台のみで、その上にZabbix-Serverが走っています。
小規模ウェブサービス向け、サーバ監視入門

それは小規模ウェブサービスとは呼ばないと思いません?複数台構成で小規模?

AV女優.comの方がzabbixを使われることは全然かまわないし、むしろ良くがんばっておられると思うのですけど、この構成を小規模と認めてしまうと、「ウェブサービスを作ってみたよ!」という人の立場がなくなってしまいます。複数台のサーバを使い始めた時点で「小規模」と名乗るのは卒業していただきたいのです。
ということで、僭越ながら、サーバ一台で全てをまかなう、本当の小規模ウェブサービス開発者さんのためのサーバ監視記事を書いてみました。

小規模っていうのはこういうのを言うんだ!

サーバは一台。さくらのVPSか、Linode.comの一番安いのが一台。これより高いサーバは認めない。
データベースとWEBでサーバを分けているとかありえない。監視用サーバなど論外!
この記事で紹介している方法は、そういう安価なサーバ一台で運営されている方のためのサーバ監視の方法です。

そもそもサーバ監視って何?

自分の提供しているウェブサービスが落ちている時、ユーザーさんから「なんか動かないんですけど」といわれるより先に開発者がそれに気づける状態にすることです。
気づいたからといってすぐ復旧に着手できるとは限らないのですけど、それでも、早く気づくことによって、「今日は早く帰れるように手配しよう」とか、「とりあえず通知だけ出しておこう」とか、そういう対応をとることが出来ます。
ユーザーさんから直接連絡をもらって、「わー!なんとかしなくちゃ」とパニックになってしまっては、とるべき対応もとれなくなってしまいますよね。

落ちた原因を究明するためにメモリやHDDの残り容量推移を記録しておいたり、ログを定期的にウオッチしたりする機能も便利ではあるけど、小規模ウェブサービスでまずやるべきは「生きているか死んでいるか」の監視です。片肺飛行であろうがメモリがリークしていようが、動いていりゃいいんです!どうせユーザーさんには出力されたページしか見えないんだから!

で、どうやんの?

mon.itor.usを使います。定期的にHTTPアクセスして、返事がなくなったらメールを送ってくれるサービスです。
有料版で高機能なmonitisというのがあって、今自分はこっちを使っているのですけど、無料版でも小規模ウェブサービスには十分な能力を持っています。

monitorus.png これがmon.itor.usの管理画面。自分の管理しているサーバがどれくらいで応答したかがグラフになっています。

moni.tor.usを使おう!

mon.itor.usにアクセスして...

monitorus0.png
ここの「SignUp」から登録します。

monitorus1.png
メールアドレスとパスワードを入力。Phoneは入れなくてOKです。確認メールとか来ることもなく、SIGN UPを押したら登録完了の簡単登録。

monitorus2.png
登録ウイザード。見ての通りHTTP以外にも、POPとかSSH、MYSQLの生存確認もやってくれますが、まずはHTTPでやってみましょう。

monitorus3.png
監視対象のURLを入れます。まずはトップページを。

monitorus31.png
どこから監視するか、どのくらいの間隔で監視するかの設定ですが、無料版だと30分に一回、USとEUからの監視に限られています。監視間隔がちょっと長いのですけど、まずはこれで使ってみて、満足したら有料版も考えてあげてくださいませ。

monitorus4.png
HTTPの応答が一回なかったら落ちたと見なすのか、EUとUS両方なかったら落ちたと見なすのか、それとも数回応答がなかった時点で落ちたと見なすのか・・・なども設定できますが、ここはデフォルトで十分。
それよりも、「Add Contact」をクリックして、落ちた時の連絡先を登録します。

monitorus5.png
連絡先登録画面。まずはEメールで登録しましょう。iPhoneのプッシュ通知とか、Twitter(DM)とか、面白げな機能はあとの楽しみということで。

monitorus6.png
「Add」を押すと、今度は確認メールが送られてくるので、メールに書かれているURLをクリックする必要があります。ちなみに、ここで確認したメールはmon.itor.usで共通なので、一回確認すれば、他のサーバを監視する際は確認せずにそのまま使うことが出来ます。

monitorus7.png
メールアドレスの確認がすんだら、「Add Rule」をクリックして通知ルールを登録します。最後に「Done」

monitorus8.png
監視サービスが追加されました。まだ一回も監視されていないのでさみしい見た目ですが、一晩待てば、どのくらいの時間で応答したのかを見ることが出来ます。

あとは、サーバが落ちるまで存在を忘れてしまってもかまいません。メールアドレスを登録する際、「WeeklyReport」にチェックを入れていたら、週に一回レポートが送られてきます。
サーバが落ちた時には、登録したメールアドレス宛にメールが飛んできます。
ビックリすると思うけど、落ちてからせいぜい30分。たぶんまだユーザーさんは「あれ?」と思うか、まだ誰も気づいていないくらいです。今のうちに直してしまえば大丈夫!

その先のサーバ監視

まずはこれで十分です。サーバが落ちたことをユーザーさんより先に気づいてサービスを復旧させることが出来れば、第一の役目は果たしていると言えますよね。
とはいえ、使っているうちに、もうちょっと楽が出来ないのかな?と思い始めると思います。

  • 完全に落ちた訳じゃなくて、エラーページを返している時も通知してほしい
  • メモリとかHDDが減ってきたのも見てほしい

今回使った監視機能は、HTTPの応答があるかないかで見ているので、Apacheは生きているけどデータベースが死んでいるなどの理由で中途半端な(たとえばPHPのワーニングを含んだ)WEBページを返していると、一応生きていると見なしてしまいます。

また、今回つかったExternal Monitorは外からアクセスして確認しているだけなので、メモリが減ってきているとか、HDDの空き容量がなくなってきたとか、そういう事象も見ることが出来ません。

そういうことが気になるようになってきたら、Nagiosとか、ZABBIXとか、そういう高機能な監視サーバのお勉強を初めてもいいかもしれません。
自分の場合は、mon.itor.usが大変気に入ったので、有料版のmonitisを使うことにしました。有料版になると、1分単位で監視したり、WEBページの中身を見てチェックしたり、ajaxページの遷移を一通りテストしてもらったりすることが出来ます。InternalMonitorでメモリやHDDを見てもらうのも可能。
監視のためにサーバ用意しなくていいですし、インストールとか監視サーバが落ちる現象に悩まされたりもしないので、もし良かったらmonitisもどうぞ。



エンジニア!

今回の震災に関連して、プログラマが役に立てることを!ということで、WEBサービスとか、スマートフォン向けアプリケーションがたくさん作られています。
プログラマは、「こんなものがあったらいいのに」と思った時、すぐにそれを作り出すことが出来る素敵な職業ですので、この災難に対しても、その腕を発揮するのはとってもいいことだと思います。

これから作る人や、別に震災向けのサービスじゃないんだけど、既存のサイトに関連機能を組み込みたい、という人のために、震災に関連するアプリ/サービスを作るために使えそうなAPI、データを公開しているページを集めました。

電力使用量に関する情報を得られるAPIなど

計画停電に関する情報を得られるAPIなど

その他、参考に出来そうなサイト

  • 計画停電時間検索。クリエイティブコモンズでperlスクリプトを公開。Wikiなど使って複数の開発者が協業中。PHP版も。

随時更新予定。他にもAPIを作った方、ここに載っていないAPIやデータをご存じの方はぜひコメントしてくださいませ。



MacBookAir(11インチ)を買いました。iPhoneアプリのために買ってあったMacMiniが壊れて、どうしようかと思っていたら買い手を捜している人がいたのでありがたくお買い上げ。
Let'sNoteの中でも特に小さいLet'sNoteRからの乗り換えだったので、キーピッチが広すぎて巨人のパソコンを使っているような気分ですが、スペックの割に軽快に動いてくれるし、ファンの音がしないのはとても快適なので、気に入っております。

Windowsから乗り換えた人の常で、Windowsでできたあの機能はどうやるんだ、ということでいろいろググッていたのですが、とりあえず一個便利なのを再現することに成功したのでメモ。具体的には、「日付と時刻をクリップボードにコピー」。

これはWindowsの標準機能ではなくて、もうすでに開発が停止してしまったbluewindとその関連ツールの合わせ技です。自分の場合、alt+bでBlueWindを立ち上げて、dateと入力すると、その時の日付と時間がクリップボードにコピーされるようにしていました。
これがあると、日報とか作業記録を書くのが超便利なのです。

で、これをMacでやる方法。

  • 日付と時刻をクリップボードにコピーするスクリプトを作る
  • spotlightからアプリを起動

日付と時刻をクリップボードにコピーするスクリプトを作る

とりあえず、キーボードから起動するのは後回しにして、立ち上げたら日付と時刻をクリップボードにコピーするアプリをいっこ用意します。

現在の日付時刻をクリップボードにコピーするAppleScript - サンフラットの開発日記
ありがたい事にAppleScriptを書いていただいているので、Apple Script Editorに貼りつけて
scriptEditor.jpg
「名前を付けて保存」でApplicationとして保存してあげれば、
saveAsApp.jpg
立ち上げるだけでその時の日付と時刻をクリップボードにコピーされるアプリケーションが出来上がる。あとで便利なので、Applicationフォルダに保存しておいてね。

spotlightからアプリを起動

これだけでも十分便利なんだけど、もとの使い勝手を考えると、キーボードから手を離さずに同じ機能を実現したい。マウスでアプリを立ち上げるとかまだるっこしいよね。
Mac的には、こういう時はSpotLightを使うらしい。Ctrl+Spaceで立ち上げるあの謎の機能に、「copy..」位まで入力してあげると、さっきのスクリプトが出てくる。
SystemUIServer.jpg
copyDateAndTimeが選ばれている状態でEnterキーを押してあげれば、クリップボードに日付と時刻文字列がコピーされるので、EverNoteでもEmacsでも、どこでも貼り付けることができる。
Evernote.jpg



sxchu_308383_titanium.jpg

TitaniumMobileプログラミングの話。
Windowを生成する時、urlパラメータを使うと、そのWindowは副コンテキストに分割されて動くことになるので、親コンテキストの変数を参照することは出来ません。

Window - titanium-mobile-doc-ja - UIカタログ - Window - Project Hosting on Google blockquote
これを乗り越えるための対策は、上記ドキュメントに書いてあるのですけど、微妙にいろいろ罠があって、実験して分かったことまとめ。


例えば、親コンテキスト(win1)の変数hogeがあって、副コンテキスト(win2)でボタンを押したらhogeをインクリメントしたい、というような場合。

main.jpg sub.jpg

まず、親コンテキストの変数を子コンテキストで参照するには、こういう風にする。

var hoge = 1;
win2.hoge = hoge;
すると、子コンテキスト側からは、
var win2    = Titanium.UI.currentWindow;
Ti.API.debug("hoge:"+win2.hoge);
みたいにして参照することが出来る。
ただし、変数はby value渡しになるので、副コンテキストで値を変更してもメインコンテキストのhogeには反映されません。
なので、
button1.addEventListener('click',function(e){
	win2.hoge = win2.hoge+1;
	label.text = 'hoge:'+ win2.hoge;
});
こういうふうに書いても、main側ではhogeの変更は全く無視されてしまいます。

メインコンテキストに値を反映したい時は、
function update_hoge(value){
	hoge = value;
}
という具合にセッターを用意してあげて、副コンテキストの方から
win2.update_hoge( Titanium.UI.currentWindow.hoge + 1);
という具合にして呼び出してあげると、メインコンテキストで実行されるので、値を反映することが出来ます。

button1.addEventListener('click',function(e){
	win2.update_hoge(win.hoge+1);
	label.text = 'hoge:'+ win.hoge;
});

ただしここにはさらに罠があって。update_hogeを呼んだからといって、副コンテキストが見ているwin2.hogeが勝手にアップデートされたりはしません。
なので、上記コードも、ボタンをクリックしても副コンテキストのhogeの値はちっとも増えないように見える。実際には、メインコンテキスト側のhogeが増えているので、いったんウインドウを閉じて開けば反映されるのですけど。

副コンテキスト側に値を戻してあげるには、update_hogeで反映してあげるしかないみたい。
function update_hoge(value){
	hoge = value;
	win2.hoge = hoge;
}
という具合にして書き戻すようにするか、get_hoge();を作るのがよいみたい。

コンテキストというのがスレッドのことなのかなんなのかによっては、意図しない順番で処理が実行されたりしそうで怖いのですけど、その辺は明日えらい人たちに聞いて勉強してこようと思います。

おまけ

というわけで明日(あ、今日になっちゃった)は はてな技術勉強会 Hackathonです。@masuidriveをはじめ、TitaniumMobile関係えらい人がいっぱい集まるのにもかかわらず、まだ席が空いています!もったいないお化けが出ますので、空いている人ははてなにGO!