Quantcast
Channel: もぎゃろぐ
Viewing all 62 articles
Browse latest View live

Evernote Devcup Workshop "世界に伝わる製品紹介ビデオの作り方"

$
0
0
6月17日(月) Evernote Devcup Workshop "世界に伝わる製品紹介ビデオの作り方"で聞いてきた内容のメモ。

概論

*「何を伝えたいのか」が重要

*「説明書」を作らない

  • 全部の機能を順番に説明して「で、何?」ってなる動画のこと
  • 技術から発想したアプリが陥りやすい
  • 「どういう問題があって、それをどう解決するのか」を伝える

*動画の長さ

  • 経験的に、1分半を超えると離脱率が上昇する
    • これを超える動画は何らかの形でユーザーを飽きさせない工夫が必要。男性向けだったら女の子を出すとかw
  • 短いほうが簡単に思えるかもしれないけど、短くするほうが難しい。
    • 「何を伝えたいのか」がちゃんと決まっていないと短くできない
    • テレビCM:15秒の動画がどれだけ難しいか。

*どんな動画がいいか困ったら?

  • 似たようなサービスの動画をみてみる
  • MOVAAA!!(モバー)というサービスがあるよ!

動画の要素

*開発者がカメラの前に立って話す

  • 一番簡単で、言いたいことも結構伝わる
  • 注意事項:冒頭で挨拶とか自己紹介をしない。そんなことは見ている人にとってどうでもいい

*iPhoneやPCのキャプチャ

*実写

  • 冒頭と最後に人を映すと印象的な動画になる。画面キャプチャだけの動画は、審査員にとって全部一緒に見えてしまう。
  • 人物が歩いてきてiphoneで何かする程度なら、意外と撮れる
  • 権利関係注意(人の顔や広告物はぼかしておかないと、ツッコミが入った時、動画を削除せざるを得なくなる)

*テロップ

  • 要所に入れるとインパクトが強くなる
  • iMovieでも出来るよ

*BGM

*ナレーション

*効果音

*以下、プロじゃないとたぶん無理な内容

  • 実写とアニメの合成
  • アニメーション
    • Gmail Priority Inbox - YouTube
      (簡単そうに見えるけど「僕もこれは作れないですね」「企画を相当練られてます」)
  • タイムラプス(静止画をひたすら撮って動画にする)
  • インフォグラフィックス
  • 音楽の編集
    • テンポのいい曲はズレが目立つので、編集できない素人には難しい。BGM的な音楽がオススメ

ぶっちゃけプロに頼むといくらかかるの?

  • MOBERCIAL(モバーシャル)の中の人の実例と内心
    • 五万円(今回のイベント参加者から五組限定出血価格!)
    • 数十万円(ベンチャー支援的な気持ちで制作した)
    • 数百万円代前半(クライアントの社員が出演したりして制作費を抑えてこれくらい)
    • 数百万円代後半(出演者も調達するとこれくらいになる)
  • 実際にはもっとナマナマしく、あの会社のこの動画がいくら位、とか聞いたのですけど、もちろんオフレコw

railsマルチプロセスとログとlogrotate

$
0
0

先日パーティにお招きいただいたM社の方から、mongrel_clusterで複数プロセス立ち上げている時、logroateすると、ひとつのプロセスを残して、ログファイルを見失って正常に動作できなくなる、というご相談をいただきました。

美味しいお酒をいっぱいのませていただいたのでちょうど僕も使うアテがあるので、僕がよく使っているthinのケースを書いてみます。たぶんmongrelでもそんなに変わらないんじゃないかな〜。

マルチプロセスで起動する

・セッションをファイルじゃなくてDBに保存するようにする。やり方はググれば出てくるので省略。
・ログはproduction.logじゃなくてSTDERRに出力して、thinの方でファイルに書いてもらう。具体的には、config/environments/production.rbとかで
  config.logger = Logger.new(STDOUT)
という具合に。
・thinの設定
$ sudo ln -s /var/www/example/api/config/thin.conf /etc/thin/example.yaml
$ sudo emacs /var/www/example/api/config/thin.conf 
---
chdir: /var/www/example/api
environment: production
servers: 3
address: 0.0.0.0
port: 3000
timeout: 30
log: log/thin_example.log
pid: tmp/pids/thin_example.pid
max_conns: 1024
max_persistent_conns: 100
require: []

wait: 30
daemonize: true
これでlocalhost:3000,3001,3002と3プロセスが立ち上がります。
ログは、
$ ls -la api/log/
-rw-r--r--  1 root    root     3081 Aug  6 20:42 thin_example.3000.log
-rw-r--r--  1 root    root     1292 Aug  6 20:42 thin_example.3001.log
-rw-r--r--  1 root    root    15632 Aug  6 20:42 thin_example.3002.log
という具合にプロセスごとに別々に出力されます。

Rails3.2からログの行が他プロセスのものと混ざるようになった件について - 昼メシ物語 などを見ていると、一つのファイルにかいた時ログが混じるという話が出ているのですけど、そもそも複数プロセスから一個のファイルに書き込む時点で怖くて仕方ないので、 最初から分けてあったほうがいっそスッキリするんじゃないかな〜。

ログが複数にわかれていても、

tail -f log/thin_example.*.log
とすれば一つの窓で監視することができます。

ロードバランサー(apache)の設定

 こんなかんじで
$ sudo ln -s /var/www/example/api/config/httpd.conf /etc/httpd/conf.d/example.conf
$ emacs /var/www/example/api/config/httpd.conf 
<VirtualHost *:80>
        ServerName example.com
        ServerAlias www.example.com
        DocumentRoot "/var/www/example/html/"
        ServerAdmin mogya+example@mogya.com
        ErrorLog "/var/www/example/log/error_log"
        TransferLog "/var/www/example/log/access_log"
        LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
        CustomLog /var/www/example/log/custom_log combined

        ProxyPass /api/v2 balancer://example
        ProxyPassReverse /api/v2 balancer://example
</VirtualHost>
<Proxy balancer://example>
	BalancerMember http://localhost:3000
	BalancerMember http://localhost:3001
	BalancerMember http://localhost:3002
</Proxy>

いまどきapacheなんて・・・という方はherokuでもAWSでもお好きなフロントエンドでどうぞ。

logrotate

sudo ln -s /var/www/example/api/config/logrotate.conf /etc/logrotate.d/example
emacs /var/www/example/api/config/logrotate.conf
/var/www/example/api/log/* {
    daily
    missingok
    rotate 1000
    notifempty
    copytruncate
    create 0666 root root
    sharedscripts
    postrotate
       /etc/init.d/thin restart > /dev/null
       /etc/init.d/httpd restart > /dev/null
    endscript
    dateext
}

thinだけrestartだと直後の挙動が怪しかったので、httpdもrestartするようにしてあげたほうがいいみたいです。

$ sudo logrotate -dv /etc/logrotate.d/example
で文法チェック。
$ sudo logrotate -f /etc/logrotate.d/example
で動作確認を行うことができます。

環境

$ rails -v
Rails 3.2.13
$ thin -v
thin 1.5.1 codename Straight Razor
$ httpd -v
Server version: Apache/2.2.24 (Unix)
Server built:   May 20 2013 21:12:45

Titanium SDKとiOS/Android SDKの関係

$
0
0

iOS7に対応したTitanium SDK 3.1.3が正式リリースになりました。 さっそく使おうかと思ったのですが、ひとつ気になることが。TitaniumSDKのバージョンをあげるということは、古いiPhoneやAndroid端末のサポートを切り捨てることになったりしないかな?

結論から言うと、3.1.3にあげても市場にある大半の機種で動作するようになっているので、あんまり気にしなくてよかったわけですが、せっかく調べたので一応まとめておきます。

特定のバージョンのTitanium SDKがサポートするiOS/Android SDKの範囲はこの辺に載っています。

まとめるとこんな感じ

Titanium SDK Version Min iOS/SDK Version Max iOS/SDK Version
3.2.0 6.0.x 7.0.x
3.1.3 5.0.x 7.0.x
3.1.1 - 3.1.2 5.0.x 6.1.x
3.1.0 4.3.x 6.1.x
2.1.3 - 3.0.x 4.0.x 6.1.x
2.1.0 - 2.1.2 4.0.x 5.1.x
2.0.x 4.0.x 5.1.x
1.8.x 4.0.x 5.0.x
1.7.1+ 3.1.2 5.0.x
1.7.0 3.1.2 4.3.x
1.6.1+ 3.1.0 4.3
1.6.0 3.1.0 4.2
Titanium SDK Version Min Android/SDK Version Max Android/SDK Version
3.1.2 - latest 2.3.3 (API 10) 4.3.x (API 18)
3.1.1 2.3.3 (API 10) 4.2.x (API 17)
3.1.0 2.2 (API 8) 4.2.x (API 17)
2.1.2 - 3.0.2 2.2 (API 8) 4.1.x (API 16)
2.0 - 2.1.1 2.2 (API 8) 4.0.x (API 15)
1.8.x 2.2 (API 8) 3.x.x (API 11)
1.7.x 2.1 (API 7) 3.x.x (API 11)

Android

Dashboards | Android Developers(公式データ)
VersionCodenameAPIDistribution
2.2Froyo82.4%
2.3.3 -
2.3.7
Gingerbread1030.7%
3.2Honeycomb130.1%
4.0.3 -
4.0.4
Ice Cream Sandwich1521.7%
4.1.xJelly Bean1636.6%
4.2.x178.5%

2.2は切っていいような気がします。Xperia(SO-01B)とau IS03を切り捨てて、Galaxy S(SC-02B)がぎりぎり生き残るくらいの目安です。
Android 2.3.3以降をサポートすることにすれば、TitaniumSDKは最新の3.1.3でも大丈夫なことになりますね。

iOS

ios_versions.png
iOSとAndroidのバージョン分布、各OS内の割合はiOS6が93%、Android最新バージョン(Jelly Bean)は33%: 「最高のタブレット」を求めて!(公式データのコピー)

iOS6が93%、iOS5が6%。それ以前は切ってよさそう。iPhone3GSですらiOS6対応ですから、iPhone3Gを切るくらいは十分アリでしょう。
3.1.3(=iOS7対応)でiOS 5.0-7.0サポートなので、これを使って問題なさそうです。

以上、Titanium SDK 3.1.3を使っても古い機種を切る心配はしなくてよさそう、という調査結果でした。
3.1.3、安定して動いてくれるといいのですけど・・・

[sublime text2]選択中の文字列で検索する

$
0
0
Preferences.sublime-settings.png

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

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

"find_selected_text": true

を追加するだけ。

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


[本] 実践!交渉学

$
0
0

「フットインザドア」とかの交渉じゃなくて、交渉がどういうものでどういう力学が働くのかといった解説をした本。無意識に実践しているような内容も多かったのですけど、体系的にまとまっているので思考を整理することができました。

読書メモ。

  • 「窓を開けたい」人と「窓を閉めたい」人が交渉する場合、そのままだと要求を突きつけあうだけで妥結の余地がない。けれども、「なぜ窓を開けたい/閉めたいのか」情報交換して「風が吹き付けるから寒い」「空気を入れ替えたい」という利害を明らかにすることで、両者の利害を満たす結論を出すことができる(「ここじゃなくて、むこうの窓を開けましょう!」)
  • 『BATNA』(不調時代替案)。交渉が破談になったとき取れる対応のこと。
    • たとえば中古ノートパソコンを友達から買う場合、最悪ヤフオクで買ってもいいのであれば、ヤフオクで買う場合の想定値段がBATNAになる。
    • 自分のBATNAを明かしてはならない。「ヤフオクで10万円だったからそれより安く」と言ってしまうと、たぶん9万8千円くらいで買うことになる。相手は5万円でもいいかな、と思っていたかもしれないのに!
    • 相手のBATNAを知っていれば有利に交渉ができる。友達が捨てるしかないと思っているのなら、一万円と申し出てもお得だと思ってくれるかもしれない。
  • 『ZOPA』(交渉可能領域)
    • お互いのBATNAを並べて譲りうる余地のこと。最低1万円で売りたいA君と、ヤフオクで買えば10万円で買えるB君の間では、1万円から10万円までの間がZOPAになる。
    • Aくんが20万円で売りたい場合は、ZOPAが消滅するので交渉の余地がなくなる
    • 「パレート最適」ZOPAの中で、お互いの利益が最大化する解の事(略)

  • この本の前半分がこんな感じの、1対1の交渉理論について書かれている。後半は、より複雑な、複数の人が絡んだ場合の交渉学。ビジネス上の交渉で使うことは少なそうだけれど、世の中なんでこんなことになっているかを理解するうえで面白かった。
    • WIN-WINってけっこう不公平だよね、という話
    • ステークホルダーを洗い出す重要性について
    • 合意形成について
    • マスコミの役割と、マスコミによっておきやすい問題について
    • 専門家が必要な交渉で何が起こるか、それに対する対処など

Ruby geocoderがすごい

$
0
0

住所を緯度経度に直したり、緯度経度から住所を求めたりする操作をgeocodingと言って、Google Maps APIを使うとまあたいていのことはできる。 ロケタッチAPIとか、Yahoo!ジオコーダAPIという手もある。

それはともかく、そのへんをパチパチ叩くコードを書いていて、「こんなのもうとっくに誰かが書いてんじゃないかなー」と思ってぐぐってみたらなんかすごいのが出てきた。

geocoder.png Ruby Geocoder

住所と緯度経度の相互変換はもちろん、距離や範囲の扱い、Google以外のAPIへの対応、キャッシュ処理など、「実装しようかなー。でもめんどくさいよね」とか思って先送りしていたような機能がほとんど全部実装されている。

住所の取得

	require 'geocoder'
	# 日本語ロケールに設定
	Geocoder.configure( :language  => :ja,	:units => :km )

	Geocoder.address("東京タワー")
	# => "日本, 〒105-0011 東京都港区芝公園4丁目4−2−8 東京タワー"

もちろん、住所しか取れないなんて馬鹿なことはなくて、GoogleMapsAPIの結果をそのままもらうこともできます

	Geocoder.search("東京タワー")
	# => [#<:result::google:0xa9741b8>
	     [{"long_name"=>"東京タワー",
	       "short_name"=>"東京タワー",
	       "types"=>["point_of_interest", "establishment"]},
	    :中略
	      {"long_name"=>"芝公園",
	       "short_name"=>"芝公園",
	       "types"=>["sublocality_level_1", "sublocality", "political"]},
	      {"long_name"=>"港区",
	       "short_name"=>"港区",
	       "types"=>["locality", "political"]},
	      {"long_name"=>"東京都",
	       "short_name"=>"東京都",
	       "types"=>["administrative_area_level_1", "political"]},
	      {"long_name"=>"日本",
	       "short_name"=>"JP",
	       "types"=>["country", "political"]},
	      {"long_name"=>"105-0011",
	       "short_name"=>"105-0011",
	       "types"=>["postal_code"]}],
	    "formatted_address"=>"日本, 〒105-0011 東京都港区芝公園4丁目4−2−8 東京タワー",
	    "geometry"=>
	     {"location"=>{"lat"=>35.6585805, "lng"=>139.7454329},
	      "location_type"=>"APPROXIMATE",
	      "viewport"=>
	       {"northeast"=>{"lat"=>35.6676459, "lng"=>139.7614403},
	        "southwest"=>{"lat"=>35.6495141, "lng"=>139.7294255}}},
	    "types"=>["point_of_interest", "establishment"]}>]    

緯度経度から住所へ(リバースジオコーディング)

	Geocoder.address("39.70150773,141.13672256")
	# => "日本, 〒020-0034 岩手県盛岡市盛岡駅前通 県道2号線"

	Geocoder.search("39.70150773,141.13672256")
	[#<:result::google:0xa4a80d0 :>"日本, 〒020-0034 岩手県盛岡市盛岡駅前通 県道2号線",
	  	:(中略)
	    "types"=>["route"]}>,
	 #<:result::google:0xa4a7f54 :>"日本, 盛岡駅前(バス)(岩手)",
	  	:(中略)
	    "types"=>["bus_station", "transit_station", "establishment"]}>,
	#<:result::google:0xa4a7ae0>"〒020-0034, 日本",
	  	:(中略)
	    "types"=>["postal_code"]}>,
	 #<:result::google:0xa4a77e8 :>"日本, 盛岡駅(岩手)",
	  	:(中略)
	    "types"=>["train_station", "transit_station", "establishment"]}>,
	:(以下略)

IPアドレスの場所を取得

	Geocoder.search("210.194.198.60")
	[#<:result::freegeoip:0xa900844>"210.194.198.60",
	    "country_code"=>"JP",
	    "country_name"=>"Japan",
	    "region_code"=>"19",
	    "region_name"=>"Kanagawa",
	    "city"=>"Yokohama",
	    "zipcode"=>"",
	    "latitude"=>35.4478,
	    "longitude"=>139.6425,
	    "metro_code"=>"",
	    "areacode"=>""}>]

	Geocoder.address("106.187.50.98")
	# => "Japan" # IPアドレスによってはこうなってしまう(笑)

距離や角度の演算

	t1 = Geocoder.search("東京タワー")[0].geometry['location'].values.join(',')
	t2 = Geocoder.search("東京スカイツリー")[0].geometry['location'].values.join(',')
	Geocoder::Calculations.distance_between(t1,t2)
	# => 8.20771162081327 # km
	Geocoder::Calculations.bearing_between(t1,t2)
	# => 51.834180520275936 # degree
	Geocoder::Calculations.compass_point Geocoder::Calculations.bearing_between(t1,t2)
	=> "NE" 

	# railsと組み合わせるとobj.distance_to みたいなこともできるらしい。

Bing APIを使ってみる

	# APIキーが必要。http://www.bingmapsportal.com
	Geocoder.configure( :lookup => :bing, :api_key=>'*****' )
	Geocoder.search("東京タワー")
	# => [#<:result::bing:0xa476e90>"Location:http://schemas.microsoft.com/search/local/ws/rest/v1", "bbox"=>[35.62964091461487, 139.69803606567407, 35.687581680599976, 139.79308331909155], "name"=>"Tokyo Tower, Japan", "point"=>{"type"=>"Point", "coordinates"=>[35.65861129760742, 139.7455596923828]}, "address"=>{"countryRegion"=>"Japan", "formattedAddress"=>"Tokyo Tower, Japan", "landmark"=>"Tokyo Tower"}, "confidence"=>"High", "entityType"=>"LandmarkBuilding", "geocodePoints"=>[{"type"=>"Point", "coordinates"=>[35.65861129760742, 139.7455596923828], "calculationMethod"=>"Rooftop", "usageTypes"=>["Display"]}], "matchCodes"=>["Good"]}, @cache_hit=nil>]
	Geocoder.address("東京タワー")
	# => "Tokyo Tower, Japan"

ほかにも、API呼び出しをキャッシュさせたり、Railsと組み合わせることで Hotel.near("Vancouver, Canada") みたいなこともできるようになるらしいです。

もっと早く探しておけばよかったなー。

latlngの宗教問題

$
0
0

1406390_59235278.jpg

geocoderの話が予想以上にうけてびっくりしたので、ジオコーディングのくだらない話を一つ。

ジオコーディングに関するコードを書いているとたいていハマる問題が一つあって、それは緯度経度をどういう変数で表すか。
geo - Longitude の略し方。lng 派と lon 派の終わらない争い - Qiita によると、だいたい世界には6つの派閥が存在するらしいです。

  • Lng派: lat,lng
  • Lon派: lat,lon
  • Long派: lat,long
  • Longitude(略さない)派: latitude,longitude
  • 緯度経度ペアに名前付けちゃう派: "34.12345,135.98765"
  • x,y派: latlngじゃなくてxとyで済ませちゃう人たち

個人的には、上記の他に、

[34.12345,135.98765]
とArrayで表す派閥が存在すると思っています。
例のRubyGeocoderは、もともと文字列を受け取ることになっていたのですが、最近Arrayも受け取るように修正が入ったようです。

ついでなので、Ruby界から、

{lat:34.12345,lng:135.98765}
と表す新Ruby派と、
{"lat"=>34.12345,"lng"=>135.98765}
と表す旧Ruby派なんかも参戦していただくと、問題が混沌としてきて、より宗教戦争らしくなってきますね。 609407_23691178.jpg

戦争を煽るばかりでは申し訳ないので、みんな仲良くできるコードを用意してみました。

緯度経度を表す多様なフォーマットを全部受け入れて任意のフォーマットで出力する試み
https://gist.github.com/mogya/6978002

これをつかえば、上記で上げたようなパターンをすべて扱うことが出来ます。

irb> GeoUtils::coordinates([34.12345, 135.98765])
=> [34.12345, 135.98765]
irb> GeoUtils::coordinates(["34.12345", "135.98765"])
=> [34.12345, 135.98765]
(以下、戻り値は略)
irb> GeoUtils::coordinates("34.12345", "135.98765")
irb> GeoUtils::coordinates(34.12345, 135.98765)
irb> GeoUtils::coordinates( {lat:34.12345, lng:135.98765} )
irb> GeoUtils::coordinates( {lat:34.12345, lon:135.98765} )
irb> GeoUtils::coordinates( {'lat'=>34.12345, 'long'=>135.98765} )
irb> GeoUtils::coordinates( {'x'=>34.12345, 'y'=>135.98765} )

出力側はgeocoderにあわせてarrayにしてあるけど、これも指定可能

irb> GeoUtils::coordinates([34.12345, 135.98765],:lat_lng)
=> {:lat=>34.12345, :lng=>135.98765}
irb> GeoUtils::coordinates([34.12345, 135.98765],:lat_long)
=> {:lat=>34.12345, :long=>135.98765}
irb> GeoUtils::coordinates([34.12345, 135.98765],:latitude_longitude)
=> {:latitude=>34.12345, :longitude=>135.98765}
こんなこともできます
irb> GeoUtils::coordinates(
	[34.12345, 135.98765],
	[:lat_lng,:lat_long,:lat_lon,:latitude_longitude,:x_y])
=> { :lat=>34.12345, :lng=>135.98765,
	 :long=>135.98765, :lon=>135.98765,
	 :latitude=>34.12345, :longitude=>135.98765}
使わなくて済んだはずのCPU時間を横着のために使うのはどうかという気もするのですが、気にならない方は自由に利用してください。

[titanium] regionChangedの抑制

$
0
0

Titanium™ Advent Calendar 2013 - Adventar の7日目は、大さん橋を見ながら@mogyaがお送りします。

1466042_10152052877289243_273095704_n.jpg

山下公園でコード書くとかかっこよくない?と思ったんだけど、寒くてコードどころじゃない感じでした...

さてさて、TitaniumにはMapViewというのがあって、これを使うと簡単に地図アプリが作れるのですが、GoogleMapsSDKのバージョンが上がった関係で、現在Androidでは標準のMapViewではなくてModules.Mapを使うように言われていて、ちょっと混乱期にあります。3.2.0で旧バージョンが削除されるらしいので、来年には落ち着くんじゃないかと思うのですけど。現行だと、こんなかんじで書かないといけません。

map_view.js

さらにさらに、MapViewを使って、地図をドラッグした時に発生するregionChangedイベント(これも最近名前がregionchangedイベントに変わりましたw)を契機としてモバイラーズオアシスAPIを呼び出すようにすれば、電源が使えるお店を一覧するアプリを作ることが出来ます。

実際作ってみるとわかるのですが、このつくりだと微妙に使い勝手の悪いアプリになります。ちょっと離れた位置を見ようとして移動を繰り返すと、画面がちょっと動くたびにデータをロードしに行くので、処理がたまってだんだん重くなってしまうのです。

ブラウザ上のGoogleMapsSDKで開発する場合には、処理が落ち着いた時に呼び出してくれるidleイベントというのが存在するので、これを使えば綺麗に実装することが出来ます。

[GoogleMapsAPI] APIと組み合わせる時のイベントはidleを使う - もぎゃろぐ

で、idleイベントが存在しないAndroidやiOSのSDKでどうするか、というのがこの記事のテーマです(前置き長すぎだろうw)

idleイベントと近そうなイベントとして、completeイベントというのがあって、これを使うのも一つのアイデアです。ただこのイベントは、地図のロードが完全に終わってから呼び出されるので、これで実装すると、「ユーザーがドラッグ→地図がロードされる→(一呼吸)→店舗が表示される」という、これまた使い勝手の微妙なアプリになります。スポット数が少なかったり、通信環境が安定していてAPIが高速に応答してくれていれば、余りばれないのですけど・・・

今年リリースした電源検索新バージョンや、iPhone版の電源検索では、regionChangedイベントでそのままAPIを呼び出さずに、キューにイベント情報を積んでおいて、一定時間regionChangedイベントが発生しなくなったら、最後の一回分だけAPIを呼び出す、という実装を行いました。

data_task.js

data_task.js部分が問題のロジックをカプセル化したものです。
regionChangeイベントが発生したらとりあえず全部requestでDataTaskにあずけてしまいます。

	mapview.addEventListener(regionchanged,function(evt){
		datatask.request(evt);
	});

DataTaskは内部でタイマーを持っていて、一定時間が経つと、最後に呼び出したrequestの引数を使って、actionコールバックを呼び出します。

actionコールバックの中でAPI呼び出しを行うようにすれば、おおむね、ユーザーが地図をドラッグしおわったタイミングでAPI呼び出しを行うことが出来ます。

var taskAction = function(self,evt){
		Titanium.API.info('taskAction '+evt.longitude+','+evt.latitude);
	};
	var DataTask = require('data_task');
	var datatask = new DataTask({
		interval:3000,
		action:taskAction,
		caller:this			
	}); 
	datatask.start();

Dalvik_Debug_Monitor.png

書きながら「そこまで頑張る必要があったんだろうか。実はcompleteイベントでいいんだったりして」とちょっと不安になってきたのですけど・・・大丈夫なはずだ。神は細部に宿る!

明日はryugooさん@ChatWorkです。よろしくお願いしますー。


sauceLabsをつかってブラウザテストを自動化する

$
0
0
SauceLabs2.jpg

Sauce Labsというサービスがあって、WindowsやMac、iOSやAndroid等の各種OS上の各種ブラウザを仮想マシン上に立ち上げて、ブラウザ上でブラウザを操作することができるサービスです。
当初これがあればWindowsマシンを持ち歩かなくてもIE6のテストが出来るね!くらいの認識だったのですけど、説明を見ていると、どうやらSelenium WebDriver経由でユニットテストを実施することが本来の用途らしいので、コードをコミットしたら各種ブラウザでテストを実施してダメだったら教えてくれる環境というのを構築してみました。
selenium webdriverが登場した頃から、理屈の上ではできると言われていたテストですけど、あれこれの環境を個人で維持するのは現実的でないので、こういうのをサービスとして提供してくれるのは嬉しいですよね。

たとえばこういう、Google.comに行って検索した結果のページを表示するテストを実施するコードを用意して...

capsのところはSauce Labs: Supported Device, OS, and Browser Platformsからコピペすることが出来て、必要な設定に書き換えればMacのChromeでもWindowsXPのIE6でも、iOS7でもAndroidでも、任意のブラウザで同じテストを実施することが出来ます。

ということで、環境変数BROWSERでブラウザの種類を指定してunittestができる仕組みを作ってみました。

#Special thanks to Ruby-ML

通常の Test::Unit::TestCaseの代わりに SaucelabsTestCasePCを継承してテストを作れば、環境変数BROWSERで指定したブラウザでテストを実施することができるようになります。

	$ env BROWSER=mac_chrome ruby pc/search.rb
	Loaded suite pc/search
	Started
	.
	Finished in 23.795709 seconds.
	
	1 tests, 1 assertions, 0 failures, 0 errors, 0 skips
	
	Test run options: --seed 21266
	$ env BROWSER=win_ie6 ruby pc/search.rb
	:

テスト結果はunittestとして成功失敗を判定する以外にも、Saucelabs上ではこのようにキャプチャ画像や動画として保存されているものを見ることも出来ます。

SauceLabs7.jpg SauceLabs6.jpg

ここまでできれば、あとはいつもどおりにunittestを書いてjenkinsさんにお願いしておけば、コードをコミットするだけで各種ブラウザの動作確認をしてくれるようになりますね。すばらしい。

ちなみにSauce Labsは月額課金のサービスで、月一時間位までは無料で使うことが出来ます。
1テスト30sくらいで実行できるので、全部のテストを一度通してみるくらいなら無料でも行けるけれど、本当にコミットするたびに全テスト走らせるのであれば、$12のManual会員か、$49のAutomated会員くらいは必要になるかもしれないですね。
今これを書きながら気づいたのですけど、githubに公開してあるコードは無料でテストできるらしいです。Sauce Labs: OSS

swap領域の把握にはsar -Sを使う

$
0
0
「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

respond.jsが効かないもうひとつの理由

$
0
0
modern.ieでIE8の動作確認していて、昨日まで動いていたはずのデザインが突如崩壊した!リリース直前なのに!respond.jsが効いてない!?なんで? コードを戻してみたり、「respond.js 効かない」でググってみても直らない。迫るリリース時刻!電車の動き出す音! って時は、そのVirtualMachineが外部ネットワークに接続できるかどうか確認することをおすすめします。CDN上のrespond.jsはネットワークにつながってないと当然動きません。 ホストマシンのrailsでテストしていると意外と気づかないので、パニックになった時は一度ご確認を。 ・・・あー。びっくりした。

RubyHiroba2014のLTについて

$
0
0

RubyHirobaのLTについていくつかお話できることを。

結果的につまらないプレゼンで時間をとってしまって、さらに運営に余計な対応をさせるはめになってしまったことはホント申し訳ないと思っております。

今回話題が公になったので、引き続き議論していただくための参考資料として、僕の側から見て何が起きていたのかを説明させていただきます。

前日まで

 RubyMLのメールでLT募集のことを知りました。

[ruby-list:49953] 9/21(日) RubyHiroba2014の参加受付中です

 これは面白いんじゃないかな、と思って、今回のようなLTをやろうと思っている旨を当人に相談した所、OKが出たので、LTthon | RubyHiroba 2014を見て、応募フォームからタイトル書いて申し込みました。この時、アンチハラスメントポリシーにはぜんぜん気付かなかったです。わりとギリギリの話題をやろうとしている自覚はあったので、気づいていたら止めてたと思います。

 LT申し込みフォームにタイトル記入欄があったから、内容が明快にわかるように「社長が美人で何がわるい」というタイトルで申し込みました。ダメならここで止めてくれるだろうと思ってました。
 結果的には、工数がないからノーチェックで通ってしまったのだそうです。ボランティアだからそうなることは仕方ないと思うのですけど、この時点でそんな可能性はまったく思いつかなくて、当日の案内メールが来たことで「あ、OKなんだな」と理解してしまいました。

当日

 一人目の人が欠席で、結果的にぼくがトップで発表することになりました。

 発表が*終わってから* 「ところでRubyHirobaにはアンチハラスメントポリシーというのがあります」といわれて、ドキっと思わなくもなかったのですが、その後「PHPをDisったりするのは禁止です」というから、「あ、これは場を盛り上げるためにぼくのネタを引き継いで冗談を言っているのだな」と理解しました。

 その後も、Tシャツ取りに行った時とか、「ここで食事しても大丈夫ですか?」ってスタッフの方に確認に行った時とか、どこかのタイミングで直接言っていただけたら、記事の公開を見合わせるとかもありえたのですけど、上述の通り冗談をいわれていると思っていたので、ぎりぎりオッケイなおもしろいプレゼンをしたつもりでいました。

 時間があればもう一個枠をいただいてRails+GoogleAnalysticsの話もやろうと思っていたのですけど、前日から体調不良気味だったし、午後になって枠がいっぱいになっていたので、無理せず帰宅しました。ひょっとしたら運営の方は、終わってからお話をしたかったのかもしれないですね。

月曜日

 土曜日のRuby関西同窓会で、LTと同様の話をしてスカウトした方がオフィスに来てくれたので、僕としては成功したつもりになってました。
そこで、資料に出ている当人にプレゼンを見せて、「公開してもいい?」と聞いたところ、「いいよ」とのことだったので、ノリノリで資料も公開しました。

半日後くらいにRubyHiroba運営の方からメールを頂いて、ここで初めて事態を悟りました。
指示に従って資料は非公開にして、連絡を待っていたのですが、今日になって、「RubyHirobaの アンチハラスメントポリシーに明確に抵触するものではない、という結論になりました」というメールを頂きました。WEBサイトで「残念ながら、ジェンダーや性的な表現について、アンチハラスメントポリシーに抵触する発表がありました」と書かれていることとの整合性については、僕にはよくわからないです。

LTthonで行っていただいたプレゼンですが、運営で協議したところ、RubyHirobaの アンチハラスメントポリシーに明確に抵触するものではない、という結論になりました。 曖昧な言い方で大変申し訳ないのですが、「あのようなポリシーを掲げているイベント での発表としてはあまり好ましくない。しかし、どこがダメで誰に対してのハラスメント であるかを明確にすることが難しい」という判断です。

ただ、ポリシーに抵触するのかしないのかはさして重要ではなくて、くだらないLTのために運営に余計な手間を取らせてしまったことはほんと申し訳ないし、調子のってたなーと思っております。以後気をつけます。

管理画面チラ見せナイト#2 をガン見してきた

$
0
0

管理画面チラ見せ♡ナイト#2 (#admin_night)見て思ったこと。「管理画面にも銀の弾丸はない」

個別の話も面白かったんだけど、それよりも、会場で質問している人と、登壇して自分の作った管理画面を説明している人の対照が面白いなーと思った。
僕もそうなんだけど、「うまくいかないんです」と質問している人たちはたいてい、本業とのリソース配分に悩んでいて、「どのくらいのリソース配分でやったんですか?」「何日くらいで作ったんですか?」と聞いていた。
それに対する回答は「マネージャさんの要求に答えて作っていたスクリプトが管理画面になりました」「本業の合間に楽しいから作ってました」というものばっかりで、具体的に工数確保した人がぜんぜんいなかった。
あと当然だけど、「これを使ったら一瞬で管理画面ができたんですハッピー!」みたいな話もなかった。

ベンチャー企業にリソースが足りないのは当たり前の話なので、そこで工数確保とか考え始めるとなんにも動かなくなってしまう。
エンジニア一人で開発からメンテナンスサポートまでやっている状態で管理画面を作るのと、サーバエンジニアが副業で作るのでは後者のほうがちょっとリッチかもしれないけれど、まあその程度の差で、ダブダブにお金があまってるから管理画面にデザイナとエンジニアを貼り付けられるような会社なんて存在しない。

その中でどうするかといえば、本業の開発と一緒で、やることが多すぎる状況の中でほんとに必要なのはどれか見極めるとか、エンジニアが楽しいから勝手にやっちゃうとか、そんな解決方法しかないんだと思う。

その他のメモ

  • おだんみつさんは @masuidriveに這いよる謎人だと思っていたけど、21cafeの頼りになるお姉さんだと見解を改めた
  • 「管理画面のデザインの良さはオペレーターのやる気に繋がる」
  • 「本業よりもクイックに喜びの声が上がるのでむしろやる気が出る」
  • 「画面横幅は貴重なリソースなのでムダにしない」
  • datadog 管理画面的にいろんな情報を集約してくれるサービス

スタートアップツールをチラ見せしてきた

$
0
0

スタートアップツールチラ見せ♡ナイトというイベントでAnytimesのツール導入状況についてお話してきました。

  • 社内でLINEが実用的に使われているところが笑わせどころのつもりだったのですが、案外みんな使っていることが判明して、LINEすげーと思いました。
  • 新しいツールを導入する時は、ゆるさが一つのポイントになる。
    • slackだったら高橋くんみたいなおもしろロボットをいれておくとか。
      トレタでの「slack」活用を紹介してみる - @hitoshi annex on hatena
    • Anytimesの場合は、そこまで手はかけ(られ)なかったのですけど、デザイナさんがslackbotのカスタマイズ(だれかが「いいね」と言ったら「いいねいいね!」と返すとか)で遊びはじめたのが良いきっかけになりました
    • slackでbotを導入する時はアイコンが命。男性の多い会社だったらアイドルとかアニメとか、そうでなかったら会長とか社内の有名人とか、そんなのを使って親しみやすさを作る。

sssslideをモバイルで使う

$
0
0
(2015-01-13 追記) sssslide側で対応していただけたので、ここで紹介したスクリプトを使わずとも、本家に掲載されているブックマークレットがそのままスマホでも動作するようになりました! (追記終わり)

SSSSLIDEというサイトがあって、SlideShareSpeaker Deckにアップロードされているスライドを、縦に並べてみることができる。

実はPCだとそんなに必要性を感じないのだけれど、スマホで使うととても便利。

Screenshot_2015-01-12-22-09-02.png

slideshareのスマホViewは、横にスライドして読むようになってんだけど、普段左手でスマホ持っていると、この動作はちょっとやりづらい。縦にスライドするほうが楽だし、全部表示されていたほうが断然早く読めるよね。


WEBページの内容を一時的に書き換えるテクニック

$
0
0

この記事は、以前書いた「不要なところは削除してやりたい放題できる『編集』 - もぎゃろぐ」の再掲です。需要はあると思うのになぜか広まらないのでもう一回書いてみる!

WEBサイトをキャプチャするとき、微妙に都合の悪い要素を削りたい時ってあるじゃないですか。広告とか、ユーザーさんのお名前を伏せ字にするとか。普通そういう処理は画像編集ソフトでやるのですけど、めんどくさいじゃないですか。動画とかそう簡単じゃないし。
そういう時、ブラウザで見ているページの中身を一時的に書き換えることができます。

編集

このリンクを右クリックして「お気に入りに追加」します。
alert.JPG

こういう警告が出ます。警告の内容は書いてある通りなので、信用できる方だけ「はい」を押してください。


先ほどのように、編集したいページに行ったら、そこでお気に入りから「編集」を選ぶと、WEBページにカーソルが出てきます。
Cursor_and_仕事管理___Any_Times・エニタイムズ.png
任意の箇所を変更することが出来ます。
Cursor_and_仕事管理___Any_Times・エニタイムズ 2.png
余計なところを削除したりできるのが、撮影の時に嬉しいです。
仕事管理___Any_Times・エニタイムズ 2.png
撮影に邪魔なカーソルは、どこか画面に映らない場所に移動させておきます。
あと、書き換えた画面は、もう一度ページを読み込み直すと元に戻ります。

GoogleグループでDocsの権限を管理する

$
0
0

今や会社でもドキュメントを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

メイドめーる終了のお知らせ

$
0
0

2008年の公開以来、沢山の皆様に使っていただいた「メイドめーる」ですが、サービスを終了させることにしました。

直接的な要因としては、GoogleカレンダーのAPIが更新されて、コードをバージョンアップしないと正常に動作しなくなっていたことです。このまま放置して意味不明なメールを送信し続けるよりは停止させたほうがいいと判断しました。

サービス終了の時、「社会環境が変化して役割を終えた」というのがよくありますが、メイドめーるに関しても同じことが言えます。
メイドめーるを開発した2008年は、iPhone3Gの発売直後、まだAndroidは存在すら怪しい時代でした。iPhoneでGoogleカレンダーを見るためには「同期」が必要で、Googleカレンダーと同期させる方法がブログネタとしてアクセス数を集めるような時代だったのです。

時は過ぎて、GoogleがAndroidOSを発表し、Googleのサービスはスマートフォンからアクセスできることが当たり前になりました。Google Nowでは、その日の予定をお知らせするのはもちろん、現地までの所要時間を計算して、「もうそろそろ出ないと遅刻しますよ」と通知までしてくれるようになりました。僕自身、GoogleNowのほうが便利なので、メイドめーるについては使わなくなってしまってずいぶん時間がたってしまっています。

まだガラケーのユーザーが残っているじゃないか、iPhoneのGoogleNowはそんなに便利じゃないぞ、というような状況は知っておりますし、メイドさんが好きだったのに、というユーザーさんがいてくださることはありがたいことなのですが、そもそもGoogleカレンダーを便利に使うためのサービスである以上、Googleと競争をするというのも馬鹿げた話ですから、これ以上の改善については、Googleにお任せするのが良いかと考えました。

お預かりしていたデータについて

メールアドレスやアクセストークンについては、責任をもって破棄させていただきます。
メイドめーるのサービスについては、ドメインを引き継いで運営したいという会社さんがおられるため、ひょっとしたら今後、運営会社が変更になってサービスが再開する可能性がないとは限らないのですが、その際にも、新たな会社さんにユーザーデータを勝手に譲渡したりすることはありません。

ソースコード

githubで公開しました。相当古い環境だし、テストも書かれていないのでこれをそのまま動かすことは困難だと思いますが、何かの参考になるかということで公開しておきます。

mogya/maidmail

オオカミ少年から学ぶメディアとの付き合い方

$
0
0

イソップ童話の「オオカミ少年」は、嘘をついた少年が狼に食われるという結末が有名ですが、もともとそんな結末はなくて、「村の羊はすっかり食べられてしまったとさ」というのが結末だったんだそうです。

日本ではイソップの話であるとして、狼に食べられるのは羊ではなく「羊飼いの少年」とする寓話がいくつも存在する。
(嘘をつく子供 - Wikipedia)

誰かが作り替えた話が、「そっちのほうがわかりやすいから」ということでどんどん広まっていって元の話を駆逐してしまう展開は、パクツイとかバイラルメディアでよく見られる現象ですね。

ところで、「村の羊はすっかり食べられてしまったとさ」という結論が元だとすると、これってどういう教訓だったんだろう、というのがfacebookで話題になりました。

食べられたのが少年じゃなくて村の羊ということは、村の人々の行動に問題があったということになります。ウソだかホントだかわからない話を鵜呑みにして、いきなり全員で武器を持って大騒ぎしちゃったことが問題なんじゃないでしょうか。
村人は、少年の話をきいた時点で、とりあえず武器を持った人を索敵に出して、他の人は冷静に待機しておくべきだったのです。
そういう対応なら、嘘だと判明しても「コラ!」って叱れば済む程度の話だっただろうし、対応コストが低いから、二回目以降も同じ行動を取り続けることが出来て、本当に狼が来た時には全力で事にあたることが出来たはずです。

センセーショナルな情報を見たからといって、真偽を確かめずに大騒ぎしてはいけない。

最近はバイラルメディアとかの流行りで、「わー!」「大変!」と言いたくなるようなタイトルの付いた記事があふれています。いちいちまともに受け取って騒いでいたら、体も心も疲れてしまいますよね。
本当に「これは大変だ」と思うのなら自分で真偽を確かめてから話題にすべきだし、そうでないのなら「ふーん」と言いながら判断を保留するくらいの態度がいいんじゃないでしょうか。オオカミ少年の話題を聞いてそんなことを思いました。

帰属意識が薄れない客先常駐の話

$
0
0

客先常駐という働き方はもうやめにできないか、っていう話が盛り上がっています。

実際自分が体験して、また仲間を現場に送りこむ立場になって思うのは、この働き方は働き手にあまりに負荷をかけるのではないかということです。
IT業界で客先常駐という働き方はもうやめにできないか - あいむあらいぶ

どういう問題があるのかについては、記事に書かれているとおりだと思いますので、元記事を読んでいただければと思います。

そういう問題が起きがちであることは認めつつも、それを解決することにほぼ成功していた会社で働いた経験があるので、この記事では、どういう対策が行われていたかを書いてみようと思います。

Viewing all 62 articles
Browse latest View live




Latest Images