読み書きプログラミング

日常のプログラミングで気づいたことを綴っています

アプリを検索クローラーに見てもらう

作ったMeteorアプリをGoogleで検索すると、URLとタイトルは引っかかるのですが、中身が空白です。
ウェブアプリは仕方がないのかと思っていたのですが、ちゃんと枠組みがあるのですねぇ。

Making AJAX applications crawlable

Meteorにもspiderableというパッケージがありました。このパッケージはPhantomJSがMeteorサーバー上に必要なので、spiderable-remoteを使いました。

以下、備忘録。

herokuにPhantomJSのサーバーを用意する。

基本、phantomjs-remoteのサーバーコードを動かすのですが、herokuでTCPポートを使うには、Ruppel's Socketsを使います。

1. gitレポジトリを用意して、phantom-server.jsをコピー。

2. ビルドパックが複数使えるように設定

heroku buildpacks:set https://github.com/ddollar/heroku-buildpack-multi.git

. ファイル.buildpacksを用意。

https://github.com/heroku/heroku-buildpack-nodejs.git
https://github.com/stomita/heroku-buildpack-phantomjs.git

3. Ruppell's Socketsを追加。

heroku addons:create ruppells-sockets
git submodule add https://bitbucket.org/ruppells/sockets-connect.git lib/sockets-connect

4. ポート番号にprocess.env.RUPPELLS_SOCKETS_LOCAL_PORTを参照するように修正する。

...
if (process.argv.length < 2) {
...
var port = process.env.RUPPELLS_SOCKETS_LOCAL_PORT;
...

5. Procfileを用意する。

socket: ./lib/sockets-connect/rs-conn phantom-server.js
heroku ps:scale socket=1

6. クライアントが使うURIをメモしておく。

heroku config:get RUPPELLS_SOCKETS_FRONTEND_URI

7. herokuにデプロイ

git push heroku master

Meteorアプリ側

1. spiderable-remoteを追加する。

meteor add gadicohen:spiderable-remote

2. サーバー側で環境変数を追加するコードを追加する。

if (Meteor.isServer) {
  process.env.PHANTOMJS_REMOTE = <上でメモったURI>
}

完了!

ImageIdentifyをREST APIとして使う

Twitter友達からWolfram Language Image Identification Projectを教えていただきました。こんな記事がありますね。

http://gigazine.net/news/20150527-wolfram-language-image-identification-project/

で、これをREST APIとして使えるかどうか調査しました。結果は「できる」です。

Wolfram Language Image Identification Projectは、よくわかりませんが、Wolfram Programming Cloudの実力を示すデモサイトのようです。

https://programming.wolframcloud.com/app/

以下、登録が終わってサインインして、新しいノートブックが使えるようになった状態から、 Image Identification REST APIを作る手順です。

1. 画像URLから識別を行う関数を定義する

f[url_]:=Module[{image=Import[url]},ImageIdentify[image]]

(入力を評価するには、Shift + returnです。)

2. 定義した関数でREST APIをデプロイする

api = CloudDeploy[APIFunction[{"url"->"String"}, f[#url]&,"JPG"]]

入力を評価すると、デプロイされたURLが表示されます。

3. REST APIパーミッションをPublicにする
(デフォルトではPrivateです)

SetOptions[api, Permissions->"Public"]

以上で出来上がりです。
2で取得したURLに?url=<特定したい写真のURLをURLエスケープしたもの>を足してアクセスすると、特定結果が得られます。


直接、写真データをPOSTして得られるようにしたかったのですが、Wolfram言語は今のところ、RESET APIに関してGETしかサポートしていないようです。

MeteorでRatchet

モバイルCSSフレームワークRatchetのMeteorパッケージはいくつかありますが、ほとんどは、オリジナルのファイルをラップしたものでした。
1つだけ、ページ遷移のアニメーションをサポートしたものがあったので、そのご紹介と私の改良を簡単に書きます。

https://atmospherejs.com/zendy/velociratchet

このパッケージは、ratchetのJSは全く使用せず、Iron Routerのページ遷移アニメーションパッケージmomentum-iron-routerを使ったパッケージです。

諦めていたのでこれを知った時嬉しかったのですが、2点残念なことがありました。

  1. ratchetのページ遷移以外のエフェクトがサポートされていない
  2. themeがサポートされていない

それなら、そこは私がとforkしたのが以下のレポジトリです。

https://github.com/y-ich/velociratchet-meteor-package

Ratchetのオリジナルは、iOSAndroidかテーマを開発ユーザーが選ぶようになっていますが、それは筋違いな気もするので、自動判別してテーマを使うようにしました。

日本語マニュアル 5.36.1

英語マニュアルをちょっと見てみたら更新量が少なかったので、日本語マニュアルも更新しました。

http://maxima.osdn.jp/maxima.html

sourceforge、URLが変わったんですね。

Maxima,最近あまり活動が活発ではないのでしょうか?
構文を関数型っぽいモダンなものに直すとか期待しているんだけどなぁ。

Iron RouterとappcacheとUIWebView

appcacheを入れたMeteorのアプリがUIWebViewで動かないことが多々あるという不具合に半年前気がついたのですが、ようやく原因がわかりました。因果関係は置いておいて、原因は、

iOSのUIWebViewやWKWebViewは、window.locationにURL文字列を代入した時、高確率で無視する(locationは変わらないしページ遷移もしない)。

この不具合があるので、パス付きのURLを渡すと、appcacheを使用している場合、ハッシュスタイルのURLへの変換に失敗します。

オールマイティな対策は思いつかないのですが、(ツイートなど)UIWebViewでアクセスするようなURLの場合ハッシュスタイルURLを使っておけば問題は出ないようです。
将来、appcacheを使わなくなっても、Iron RouterはハッシュスタイルURLを解釈してオリジナルのURLにリダイレクトしてくれます。

Meteorは基本重いのでappcacheはできるだけ有効にしたいですね。

複数のアプリで1つのアカウントデータベースを使うその2

以前に、remote DDP serverのデータベースでユーザー管理を行う方法を書きました。

複数のアプリで1つのアカウントデータベースを使う

この記事でも書いた通り、OAuthなどcallback URLを使う認証の場合はうまくいかないので、以下のように考えてみました。

1. メインアプリサーバーで、ユーザー情報を_idでpublishできるようにしておく。

2.サブアプリでの認証時にサブアプリサーバーでメインアプリにアカウントがあることを確認する。

確認できなければ作成しない。確認できたらアカウントにメインアプリのアカウントの_idを紐付けする(mainId)。

3. サブアプリのクライアントに以下のコードを入れる。

share.remote = DDP.connect 'http://mainApp.meteor.com/'
share.users = new Meteor.Collection 'users', share.remote
share.user = ->
    share.users.findOne()

Tracker.autorun ->
    user = Meteor.user()
    share.remote.subscribe 'remoteuser', user.mainId

で、後は、Meteor.user, Meteor.usersの代わりにshare.user, share.usersを使います。

如何でしょう?
実際に書いたコードはちょっと違ったことをしているので上記アイデア自体はまだ試していませんが、うまく行きそうな気がしています。

OpenCV3をMacにインストールする

追記(2015/07/24): HomeBrewにフォーミュラhomebrew/science/opencv3が追加されて、特に苦労することなくインストールできるようになっていました。

OpenCV3 ベータ版が昨年11月に公開されました。
Python3でOpenCV3のプログラムを書いてみたいと思い、インストールしようとしたところ、色々、障害があり、それらを解決せずに逃げてなんとかインストールできました。

以下、備忘録です。

1. pyenvを諦める。
具体的には.bash_profileでpyenvのパスを通すスクリプトコメントアウト

2. brew install python3

3. pip3 install numpy
brew install numpyが失敗するのでpip3でインストールしておく。

4. brew tap homebrew/science

5. brew edit opencv
opencvのFormulaを変更する。

class Opencv < Formula
  homepage "http://opencv.org/"
  head "https://github.com/Itseez/opencv.git"

  stable do
    url "https://github.com/Itseez/opencv/archive/2.4.10.1.tar.gz"
    sha256 "1be191790a0e279c085ddce62f44b63197f2801e3eb66b5dcb5e19c52a8c7639"
    # do not blacklist GStreamer
    # https://github.com/Itseez/opencv/pull/3639
    patch :DATA
  end

  bottle do
    root_url "https://downloads.sf.net/project/machomebrew/Bottles/science"
    sha1 "ccc506ef6cf339048d21c4ef3d8995c76706c9d9" => :yosemite
    sha1 "fc69f870b36504f271dfe42deb5cb27c49bf21cd" => :mavericks
    sha1 "1726a921ced13ebe7f2df0f18f64997091070f71" => :mountain_lion
  end

  devel do
    url "https://github.com/Itseez/opencv/archive/3.0.0-beta.tar.gz"
    sha1 "560895197d1a61ed88fab9ec791328c4c57c0179"
    version "3.0.0-beta"
  end

  option "32-bit"
  option "with-java", "Build with Java support"
  option "with-qt", "Build the Qt4 backend to HighGUI"
  option "with-tbb", "Enable parallel code in OpenCV using Intel TBB"
  option "without-tests", "Build without accuracy & performance tests"
  option "without-opencl", "Disable GPU code in OpenCV using OpenCL"
  option "with-cuda", "Build with CUDA support"
  option "with-quicktime", "Use QuickTime for Video I/O insted of QTKit"
  option "with-opengl", "Build with OpenGL support"
  option "without-brewed-numpy", "Build without Homebrew-packaged NumPy"

  option :cxx11

  depends_on :ant if build.with? "java"
  depends_on "cmake"      => :build
  depends_on "eigen"      => :recommended
  depends_on "gstreamer"  => :optional
  depends_on "gst-plugins-good" if build.with? "gstreamer"
  depends_on "jasper"     => :optional
  depends_on :java        => :optional
  depends_on "jpeg"
  depends_on "libpng"
  depends_on "libtiff"
  depends_on "libdc1394"  => :optional
  depends_on "openexr"    => :recommended
  depends_on "openni"     => :optional
  depends_on "pkg-config" => :build
  depends_on "qt"         => :optional
  depends_on "tbb"        => :optional

  depends_on :python      => :recommended
  depends_on "homebrew/python/numpy" if build.with? "brewed-numpy"

  # Can also depend on ffmpeg, but this pulls in a lot of extra stuff that
  # you don't need unless you're doing video analysis, and some of it isn't
  # in Homebrew anyway. Will depend on openexr if it's installed.
  depends_on "ffmpeg" => :optional

  def arg_switch(opt)
    (build.with? opt) ? "ON" : "OFF"
  end

  def install
    ENV.cxx11 if build.cxx11?
    jpeg = Formula["jpeg"]
    dylib = OS.mac? ? "dylib" : "so"
    py_ver = build.stable? ? "" : "3"

    args = std_cmake_args + %W[
      -DCMAKE_OSX_DEPLOYMENT_TARGET=
      -DBUILD_ZLIB=OFF
      -DBUILD_TIFF=OFF
      -DBUILD_PNG=OFF
      -DBUILD_OPENEXR=OFF
      -DBUILD_JASPER=OFF
      -DBUILD_JPEG=OFF
      -DJPEG_INCLUDE_DIR=#{jpeg.opt_include}
      -DJPEG_LIBRARY=#{jpeg.opt_lib}/libjpeg.#{dylib}
    ]
    args << "-DBUILD_TESTS=OFF" << "-DBUILD_PERF_TESTS=OFF" if build.without? "tests"
    args << "-DBUILD_opencv_python#{py_ver}=" + arg_switch("python")
    args << "-DBUILD_opencv_java=" + arg_switch("java")
    args << "-DWITH_OPENEXR="   + arg_switch("openexr")
    args << "-DWITH_EIGEN="     + arg_switch("eigen")
    args << "-DWITH_TBB="       + arg_switch("tbb")
    args << "-DWITH_FFMPEG="    + arg_switch("ffmpeg")
    args << "-DWITH_QUICKTIME=" + arg_switch("quicktime")
    args << "-DWITH_1394="      + arg_switch("libdc1394")
    args << "-DWITH_OPENGL="    + arg_switch("opengl")
    args << "-DWITH_JASPER="    + arg_switch("jasper")
    args << "-DWITH_QT="        + arg_switch("qt")
    args << "-DWITH_GSTREAMER=" + arg_switch("gstreamer")

    if build.with? "python"
      py_prefix = `/usr/local/bin/python#{py_ver}-config --prefix`.chomp
      py_lib = OS.linux? ? `/usr/local/bin/python#{py_ver}-config --configdir`.chomp : "#{py_prefix}/lib"
      args << "-DPYTHON#{py_ver}_LIBRARY=#{py_lib}/libpython3.4m.#{dylib}"
      args << "-DPYTHON#{py_ver}_INCLUDE_DIR=#{py_prefix}/include/python3.4m"
    end

    if build.with? "cuda"
      ENV["CUDA_NVCC_FLAGS"] = "-Xcompiler -stdlib=libstdc++; -Xlinker -stdlib=libstdc++"
      inreplace "cmake/FindCUDA.cmake",
        "list(APPEND CUDA_LIBRARIES -Wl,-rpath \"-Wl,${_cuda_path_to_cudart}\")",
        "#list(APPEND CUDA"
      args << "-DWITH_CUDA=ON"
      args << "-DCMAKE_CXX_FLAGS=-stdlib=libstdc++"
    else
      args << "-DWITH_CUDA=OFF"
    end

    # OpenCL 1.1 is required, but Snow Leopard and older come with 1.0
    args << "-DWITH_OPENCL=OFF" if build.without?("opencl") || MacOS.version < :lion

    if build.with? "openni"
      args << "-DWITH_OPENNI=ON"
      # Set proper path for Homebrew's openni
      inreplace "cmake/OpenCVFindOpenNI.cmake" do |s|
        s.gsub! "/usr/include/ni", "#{Formula["openni"].opt_include}/ni"
        s.gsub! "/usr/lib", "#{Formula["openni"].opt_lib}"
      end
    end

    if build.include? "32-bit"
      args << "-DCMAKE_OSX_ARCHITECTURES=i386"
      args << "-DOPENCV_EXTRA_C_FLAGS='-arch i386 -m32'"
      args << "-DOPENCV_EXTRA_CXX_FLAGS='-arch i386 -m32'"
    end

    if ENV.compiler == :clang && !build.bottle?
      args << "-DENABLE_SSSE3=ON" if Hardware::CPU.ssse3?
      args << "-DENABLE_SSE41=ON" if Hardware::CPU.sse4?
      args << "-DENABLE_SSE42=ON" if Hardware::CPU.sse4_2?
      args << "-DENABLE_AVX=ON" if Hardware::CPU.avx?
    end

    mkdir "macbuild" do
      system "cmake", "..", *args
      system "make"
      system "make", "install"
    end
  end

  test do
    Language::Python.each_python(build) do |python, _version|
      system python, "-c", "import cv2"
    end
  end
end


__END__
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 1d7d78a..1e92c52 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -135,7 +135,7 @@ OCV_OPTION(WITH_NVCUVID        "Include NVidia Video Decoding library support"
 OCV_OPTION(WITH_EIGEN          "Include Eigen2/Eigen3 support"               ON)
 OCV_OPTION(WITH_VFW            "Include Video for Windows support"           ON   IF WIN32 )
 OCV_OPTION(WITH_FFMPEG         "Include FFMPEG support"                      ON   IF (NOT ANDROID AND NOT IOS))
-OCV_OPTION(WITH_GSTREAMER      "Include Gstreamer support"                   ON   IF (UNIX AND NOT APPLE AND NOT ANDROID) )
+OCV_OPTION(WITH_GSTREAMER      "Include Gstreamer support"                   ON   IF (UNIX AND NOT ANDROID) )
 OCV_OPTION(WITH_GSTREAMER_0_10 "Enable Gstreamer 0.10 support (instead of 1.x)"   OFF )
 OCV_OPTION(WITH_GTK            "Include GTK support"                         ON   IF (UNIX AND NOT APPLE AND NOT ANDROID) )
 OCV_OPTION(WITH_IMAGEIO        "ImageIO support for OS X"                    OFF  IF APPLE )
  • 変更場所は、build.stableじゃない時のPythonのバージョンを3に
  • python-configの代わりに/usr/local/bin/python3-configを使用
  • PYTHON3_LIBRARYとPYTHON3_INCLUDE_DIRのパスをそれなりに合わせる

6. brew install opencv --devel --without-brewed-numpy

かなりやっつけ仕事ですが、これで、/usr/local/bin/python3からimport cv2ができるようになりました。