コマンドラインでairdropを使う

2014/12/13追記: yosemite版を追記しました

社内のPCがほとんどMacなのでファイルのやりとりも自然とairdropが多くなります。

問題はその度にFinderを開かなければいけないことです。 alfredのairdropのworkflowとか入れてみたけど、なんかしっくりこないし。

というわけでコマンドラインで扱えるようにしましょう。

受け取る

10.9(Mavericks)以前

こちらのapple scriptを使うのが一番シンプルだと思います。

#!/usr/bin/osascript
tell application "Finder"
    activate
    tell application "System Events" to keystroke "R" using {command down, shift down}
end tell

ライセンスが明記されてないので、一応自己責任ということで。

10.10(Yosemite)以降

上記のスクリプトYosemiteで動かなくなってしまったので、改良しました。 ちなみにYosemiteではJXAと呼ばれる、JSのコード形式でApplescriptを実行できる機能が提供されているため、JSで書きました。

#!/usr/bin/env osascript -l JavaScript

function run() {
  finder = Application('Finder');
  finder.activate();
  delay(1); // sleep

  event = Application('System Events');
  event.keystroke('R', {using: ['command down', 'shift down']});
}

送る

これもapple scriptで解決できるかなーと頑張ってみました。しかしAXShowMenuでFinderのコンテキストメニューを出したところまでは良かったんですが、メニュー選択ができず断念。

色々探してみた結果、こちらのgemにたどり着きました。

# インストール
gem install terminal-share
source ~/.zshrc

# 実行
terminal-share -service airdrop -url file:///Users/akiomi/.vimrc

これを毎回打つのも面倒なので、シェルスクリプトを作りました。ライセンスはNYSLということで。

#!/bin/sh

if [ $# -ne 1 ]; then
  echo "usage: $0 FILE" 1>&2
  exit 1
fi

if [ ! -e $1 ]; then
  echo "$1: No such file or directory" 1>&2
  exit 1
fi

target=file://$(cd $(dirname $1) && pwd)/$(basename $1)
terminal-share -service airdrop -url $target

これで快適にファイルのやり取りができそうです。

cuda 6.0をubuntu serverに導入する

昔使ってたワークステーションにXPが載ってたんですが、サポートも切れたし…ということで最近ubuntu serverに変更しました。

そのワークステーションには古いグラボが載ってて学生の頃にはcudaで遊んでたので、また遊べるようにセットアップしてみます。

cuda 6.0を選択したのは、詳しくないけど、どうせなら新しいものをということで。unified memoryなのも便利そうだし。

環境

手順

Xの停止

自分の環境ではubuntu-desktopパッケージを入れているので、まずXを止める。Xのサーバが立ってない環境では不要なはず。

sudo service lightdm stop

cuda toolkitのインストール

次にcuda toolkitを入れる。現時点でcuda 6.0はRC。

wget http://developer.download.nvidia.com/compute/cuda/6_0/rc/installers/cuda_6.0.26_rc_linux64.run
chmod 755 cuda_6.0.26_rc_linux64.run

sudo ./cuda_6.0.26_rc_linux64.run -silent -driver # ドライバのインストール
sudo ./cuda_6.0.26_rc_linux64.run # 利用許諾の同意やサンプルの導入など

.zshrc.bashrcに各種バイナリへのパスを通す。

# .zshrc

export PATH includes="/usr/local/cuda-6.0/bin"
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:/usr/local/cuda-6.0/lib64"

サンプルの実行(1)

これでサンプルなども含めて一式が入ったのでサンプルをビルドしてみる。

sudo aptitude install g++

cd ~/NVIDIA_CUDA-6.0_Samples
make

さっそく実行!と思ってサンプルをいくつか実行してみるも、自分の環境では以下のようなエラーが出てしまった(サンプルによって出力はことなるが、エラーコードが35)。

cudaGetDeviceCount returned 35

nvidiaドライバのインストール 

これはデフォルトで使用されているnouveauというドライバが問題なようなので、nvidiaのドライバを入れる。以下のサイトから適切なドライバをダウンロードし、インストールする。

chmod 755 NVIDIA-Linux-x86_64-331.67.run
sudo ./NVIDIA-Linux-x86_64-331.67.run

しかし、nouveauドライバが有効になっている場合にはインストールに失敗する。 この場合には自動的に/etc/modprobe.d/nvidia-installer-disable-nouveau.confというファイルが作成され次回起動時からnouveauドライバを読み込まないようになるため、再起動する。

sudo reboot

再度ドライバのnvidiaドライバのインストール。

sudo ./NVIDIA-Linux-x86_64-331.67.run

Xの再開

冒頭でXを止めた場合は再開する。

sudo service lightdm start

サンプルの実行(2)

これでようやくサンプルを実行できる。

cd ~/NVIDIA_CUDA-6.0_Samples/bin/x86_64/linux/release
./deviseQuery

出力はこんな感じ。ちゃんとCUDA 6.0が入っていて、動いているのが確認できる。

./deviceQuery Starting...

 CUDA Device Query (Runtime API) version (CUDART static linking)

Detected 1 CUDA Capable device(s)

Device 0: "GeForce 8600 GT"
  CUDA Driver Version / Runtime Version          6.0 / 6.0
  CUDA Capability Major/Minor version number:    1.1
  Total amount of global memory:                 256 MBytes (268107776 bytes)
  ( 4) Multiprocessors, (  8) CUDA Cores/MP:     32 CUDA Cores
  GPU Clock rate:                                1188 MHz (1.19 GHz)
  Memory Clock rate:                             700 Mhz
  Memory Bus Width:                              128-bit
  Maximum Texture Dimension Size (x,y,z)         1D=(8192), 2D=(65536, 32768), 3D=(2048, 2048, 2048)
  Maximum Layered 1D Texture Size, (num) layers  1D=(8192), 512 layers
  Maximum Layered 2D Texture Size, (num) layers  2D=(8192, 8192), 512 layers
  Total amount of constant memory:               65536 bytes
  Total amount of shared memory per block:       16384 bytes
  Total number of registers available per block: 8192
  Warp size:                                     32
  Maximum number of threads per multiprocessor:  768
  Maximum number of threads per block:           512
  Max dimension size of a thread block (x,y,z): (512, 512, 64)
  Max dimension size of a grid size    (x,y,z): (65535, 65535, 1)
  Maximum memory pitch:                          2147483647 bytes
  Texture alignment:                             256 bytes
  Concurrent copy and kernel execution:          Yes with 1 copy engine(s)
  Run time limit on kernels:                     No
  Integrated GPU sharing Host Memory:            No
  Support host page-locked memory mapping:       Yes
  Alignment requirement for Surfaces:            Yes
  Device has ECC support:                        Disabled
  Device supports Unified Addressing (UVA):      No
  Device PCI Bus ID / PCI location ID:           1 / 0
  Compute Mode:
     < Default (multiple host threads can use ::cudaSetDevice() with device simultaneously) >

deviceQuery, CUDA Driver = CUDART, CUDA Driver Version = 6.0, CUDA Runtime Version = 6.0, NumDevs = 1, Device0 = GeForce 8600 GT
Result = PASS

ついでにcublasも試す。

./matrixMulCUBLAS

出力はこんな感じ。なんだか昔より速くなってる気がする(うろ覚え)。

[Matrix Multiply CUBLAS] - Starting...
GPU Device 0: "GeForce 8600 GT" with compute capability 1.1

MatrixA(160,320), MatrixB(160,320), MatrixC(160,320)
Computing result using CUBLAS...done.
Performance= 21.99 GFlop/s, Time= 0.745 msec, Size= 16384000 Ops
Computing result using host CPU...done.
Comparing CUBLAS Matrix Multiply with CPU results: PASS

railsのオーバーライドPOSTで独自のHTTPメソッドを扱う

みなさんは確認画面のURIってどうしてるんでしょうか?

例えばユーザの作成時に/users/confirmってするのはなんかしっくり来ないな、と思って調べて以下の記事にたどり着きました。

"confirm"などの追加のアクションはオーバーロードPOST*2であるから、URLは動詞でよいしGETできなくてかまわない、という考えがあって、たぶんRailsもその考えに沿っている感じがするのですが、これにはあまり同意できません。URLとして現れるものは、基本的にGETできる(リソースとして意味がある)べきだと思います。

多くのWebアプリケーションは、オーバーロードPOSTを通じてサポートする操作のために、新しいURIを作成する。たとえば/weblog/myweblog/rebuild-indexのようなURIは、そのURIにリンクしても意味はない。このようにURIメソッド情報を含める代わりに、既存のリソース(/weblog/myweblog)でオーバーロードPOSTをサポートし、入力表現でメソッド情報(method=rebuild-index)を要求すればよい。 「RESTful Webサービス」p.229

これを読んで、確かに、と思ったのでmethod=confirmとして送る方法を調べてみました。

環境

rails4で試しましたが、おそらく3でも同じはず。

view

rails4では編集画面などでPUT/PATCHとして送るべき場面でも、デフォルトではPOSTで投げ、代わりに_methodというパラメタにPUT/PATCHといった値を積んでます。

そのため、単に

<%= form_for @user, method: :confirm do |f| %>
  ...
<% end %>

のようにすれば_method=confirmとして送ってくれます。スゴイ!

routing

とりあえず、なにも聞かずに以下のようなファイルを作ってください。ファイル名は何でも可。

# config/initializers/http_methods.rb

%w(confirm).each do |method|
  Rack::MethodOverride::HTTP_METHODS << method.upcase

  ActionDispatch::Request::HTTP_METHODS << method.upcase 
  ActionDispatch::Request::HTTP_METHOD_LOOKUP[method.upcase] = method.to_sym

  ActionDispatch::Routing::Mapper::HttpHelpers.class_eval do
    define_method(method.to_sym) do |*args, &block|
      map_method method.to_sym, args, &block
    end
  end
end

これはCONFIRMメソッドをサーバ側で処理できるようにするためにあれこれしている処理です。

まずRack::MethodOverride::HTTP_METHODSのところ。

これはrack側でオーバライドPOSTを実現するための仕組みで、POSTメソッド_methodパラメタやHTTP_X_HTTP_METHOD_OVERRIDEヘッダで指定された値で上書きます。 しかし、デフォルトではRFC2616で定義されてるメソッド(CONNECTTRACEを除く)以外が渡された場合はなにもせず、ルーティング側にはそのままPOSTとして渡されてしまうため、ホワイトリストに追加しています。

次にActionDispatch::Request::HTTP_METHODS*のところ。

これはルーティング時に走る処理で、許可されたHTTPメソッドかチェックしています。 RFC2616、2518、3253、3648、3744、5323、5789で定義されているメソッド以外を渡そうとするとinternal server errorが発生してしまうため、ここでもホワイトリストに追加します。

最後にActionDispatch::Routing::Mapper::HttpHelpersのところ。

これはroutes.rb

confirm :users, to: 'users#confirm’

のように書きたかったのでこのように定義してます。

match :users, to: 'users#confirm', via: :confirm

でも問題なく動くので、必要ない場合は削除しても問題ないです。

最後に

とまあrails初心者なりに色々調べてみました。が、こういうことをしている情報はあまり見つからなかったのでrails的には行儀が悪いのかも。もっとスマートな方法があればぜひ教えてください!

追記(2014/08/27)

rspecのrequest specなどでテストする際にconfirm '/hoge'のように書きたい場合は、以下のコードを追加すればOKです。

# config/initializers/http_methods.rb

%w(confirm).each do |method|

  ...

  ActionDispatch::Integration::RequestHelpers.class_eval do
    define_method(method.to_sym) do |path, parameters = nil, headers_or_env = nil|
      process method.to_sym, path, parameters, headers_or_env
    end
  end
end