LDRの制限

制限があること、制限しなければなないこと、制限すべきこと。それをすべて正しい体験に落とし込んだのがLDR(livedoorReader, LiveDwangoReader)だと思っています。 制限があることは諦めではないこと。諦めからくる制限はあるけれど、良い体験を与えるための制限もあるということ。 差し引けばUXが提供できるわけではなく、UXを考えると自然に差し引くことになるということ。 そういったことを考えさせられたのがLDRでした。

他のフィードリーダーと比べてLDRはできることが制限されています。 よくある機能比較のチェックリストで他のフィードリーダーと並べると、LDRは完全に敗北するでしょう。

既読管理がフィード単位だったり、自分がどこまで未読なのかわかりにくかったり、Pin(スターのようなもの)には上限があります。

ところで、UXのUはユーザーのUだけども、ユーザーとは誰でしょう。 LDRの思想はどのようなものか、当時のインタビュー記事があります。

RSSリーダーにも2対8の法則がある」と池邊CTOは言う。2割のヘビーユーザーが、8割のフィードを読んでいるというのだ。「livedoor Readerは、2割の人に最適化している」 http://www.itmedia.co.jp/news/articles/0707/04/news034.html

また、最近書籍化された漫画 映画大好きポンポさん には以下のような台詞があります

評判欲しさに世間受けをねらったら八方美人なぼんやりぼやけた映画になっちゃうでしょ だからそれよりも誰か一人 その映画を一番見てもらいたい誰かのために作ればいいんだ そしたらフォーカスが絞られて作品の輪郭がグッと立つ

LDRのターゲットユーザーはコアな情報ジャンキーです。 そこにフォーカスを絞った結果、そのユーザーに対して正しいUI/UXを提供できるのです。 だれにもフォーカスを合わせないプロダクトは誰にとっても正しくないものとなってしまいます。 (フォーカスを合わせないプロダクトの例 http://fladdict.net/blog/2016/09/100toku-knife.html )

また話が変わって、LDRは何を提供しているのでしょう。

インターネットに流れるデータは今後も増え続けます。 それを検索システムや、AIがフィルタリングしてくれるとして、ほんとうに取りこぼしませんか?

流れるデータは大量すぎるので機械にやらせる必要はあるでしょう。 ただ、自分自身でフィルタリングしてジャッジする必要もあるでしょう。

LDRはそのフィルタリングを効率よく行うためのツールです。 読むためのツールではなく、読むエントリーを探すためのツールです。

さて、ようやく制限の話。

情報ジャンキーが、 素早く 大量に 効率よく フィルタリングを行うのに、エントリー単位の既読管理は必要でしょうか? いえ、必要ではありません。むしろ、エントリー単位の既読管理がないことが速度の向上に繋がることでしょう。 システム上の制限かもしれませんが、この制限がエクスペリエンスを向上させているのです。

無制限のPinは必要でしょうか? 古い情報は無価値です。古すぎる情報はむしろ有害となりえます。 またこれもエクスペリエンスを向上させているのです。

エントリーの未読数の表示に上限があるのも、キーボード操作を要求されるのも、システム上の制限かもしれません。 しかし、ターゲットである情報ジャンキーにとっては、差し引かれた機能のほうが正しい体験となるのです。

また、フォーカスされたユーザーにフォーカスした機能を提供することで、ようやく、足さなくて良いという判断も可能となります。

僕はUXを考えるとき、LDRを思い浮かべることがあります。 何が足りないのか、そこから何を引かなくてはならないのか、また何を引くべきか。 誰に提供するのか、誰に提供しないのか。 マイナスをするデザインを行うのでなく、デザインを行うとマイナスとなる。

そんな完璧なプロダクトがついに終了となりました。 想像するにクローラーのおもりが大変だったんだろうなぁという印象で、ドワンゴには何らかの収益を生むモデルに変更していもらいたかったのでちょっぴり残念です。

LDRは一度キメたらやめられない。今はInoreaderへの課金も済んだのですが、物足りない。もっとスピードをくれよーという感じです。

LDRが前に一度消えかけたときや、GoogleReaderが終了したとき、「情報収集はツイッターで十分だよな」という声があったけれど、 一次情報をどこで得るのかというと、やはり現状はフィードリーダーを使うしかなさそうで、次の最高のフィードリーダーが現れることを期待しています。(azuさんが作成しているようなので、楽しみです)

さいごに、LDRのすべての関係者に感謝します。ありがとうございます。そしてお疲れ様でした。 あと、ポンポさんは最高の漫画なのでみんな、買おう! https://www.amazon.co.jp/dp/4040694538

EspressoでGoogleInstrumentationTestRunnerを使った時に全部のテストを回したくない

Espresso: https://code.google.com/p/android-test-kit/wiki/Espresso

AndroidをEspressoでテストするときにGoogleInstrumentationTestRunnerを指定すると思います。 このときに今書いているテストだけを実行したくなったりすると思うのでその方法を書いておきます。

まず新しくGoogleInstrumentationTestRunnerを継承した自分用のTestRunnerを書きます。

// MyInstrumentationTestRunner.java
public class MyInstrumentationTestRunner extends GoogleInstrumentationTestRunner {

    private static final String ARGUMENT_TEST_CLASS = "class";

    @Override
    public void onCreate(Bundle arguments) {
        if(!BuildConfig.TEST_CLASS.isEmpty()){
            arguments.putString(ARGUMENT_TEST_CLASS, BuildConfig.TEST_CLASS); // ここで指定
        }
        arguments.putString("disableAnalytics", "true"); // ついでにトラッキングもOFF
        super.onCreate(arguments);
    }
}

次にbuild.gradleで自分のクラスを指定して、buildConfigを追加します。

# build.gradle
android {
    defaultConfig {
        testInstrumentationRunner "yourpackage.MyInstrumentationTestRunner"
        buildConfigField "String", "TEST_CLASS", project.hasProperty('testClass') ? "\"${testClass}\"" : "\"\""
    }
}

これで以下のように実行すれば個別のテストクラスを実行できます

./gradlew connectedAndroidTest -PtestClass=yourpackage.MyActivityTest

ただ、上記の場合、testClass=hoge でテストクラス名を間違えてもSuccessになっちゃうので、そういう時にFailさせたいと思うのですが、TestRunner内でFailさせる方法がどうしても分からなかったので以下のように設定しました

public class MyInstrumentationTestRunner extends GoogleInstrumentationTestRunner {

    private static final String ARGUMENT_TEST_PACKAGE = "package";
    private static final String ARGUMENT_TEST_CLASS = "class";

    @Override
    public void onCreate(Bundle arguments) {
        if(!BuildConfig.TEST_CLASS.isEmpty()){
            String className = BuildConfig.TEST_CLASS;

            try {
                // クラスを動的に取りに行って
                Class.forName(className);
                arguments.putString(ARGUMENT_TEST_CLASS, className);
            } catch (ClassNotFoundException e) {
                // テストクラスがなければ、Failするクラスを読み込む
                FailableTest.isFail = true;
                FailableTest.message = className + " Class Not Found";
                arguments.putString(ARGUMENT_TEST_CLASS,  FailableTest.class.getName());

                e.printStackTrace();
            }
        }
        arguments.putString("disableAnalytics", "true");
        super.onCreate(arguments);
    }
}
public class FailableTest extends TestCase {

    public static boolean isFail = false;
    public static String message = "Failed";

    public void testFailable() {
        // すべてのテストを実行した時にFailしないように通常は isFail = false
        assertFalse(message, isFail);
    }
}

ARGUMENT_TEST_CLASS や、その他の指定方法は androidのソースを引っ張ってきて android/frameworks/base/test-runner/src/android/test/InstrumentationTestRunner.java を参照して下さい

検索しても情報出てこなさすぎだったんですが、みんなテスト書いてるんですかね

BLE112に書き込みしたいだけ

BlueGigaオフィシャルのドキュメントの「BLEGUI APPLICATION, USER GUIDE」 やら、「Application Note,BGDemo」 やらを読んで、DKBLE112に載ってるBLE112に書き込むことはできるようになったんですが、 単体のBLE112にどうやって書き込むのだろうと思いました。

ちなみに、購入可能な唯一の書籍で

Bluetooth Low Energy: The Developer's Handbook

Bluetooth Low Energy: The Developer's Handbook

がありますが、 個人的にはBlueGigaのドキュメントのほうが読みやすかったです。 もちろん、詳細さには敵いませんが、まず、ハードウェアとプロトコル仕様などを軽く知るには、BlueGigaのドキュメントを読むのも良いと思います。

f:id:eckrel:20140102040930p:plain

で、「ble112 ccdebugger」などで検索かけて繋いでる画像を参考にしたり、BLE112のデータシートなどを見て、 1,2,4,5,29 番ピンをccdebuggerにつなげれば良いように見えたので、つないでみたけど動かない。 動かないという判断はCCDebuggerのランプが赤いかどうか。正しければ緑に光る。

悩んで、それらしい情報を発見。 http://e2e.ti.com/support/low_power_rf/f/538/t/301037.aspx

どうやら、上記に加えて、20番ピン(DVDD)の入力が必要でした。

結果としては、1,2,4,5,20,29 番ピンを接続すれば、書き込みだけは可能でした。 本来は9番ピンのDVDD_USBやらその他GNDも繋がないといけないはずなので、、軽く試したい場合のみ利用下さい。

最終的な足の伸び具合は以下のように。

f:id:eckrel:20140102034022j:plain

20番ピンが必要と思わず、買ってしまったサンハヤトのピッチ変換基板は無駄に。。

f:id:eckrel:20140102033956j:plain

Anacondaのパスとかを治すスクリプト書きました

スクリプトの中身を確認して自己責任でお使いください

Anaconda がインストールした so や dylib が参照しているパスを治すスクリプト

https://gist.github.com/eckrel/5243492

OpenCVのライブラリをAnacondaに突っ込むスクリプト

https://gist.github.com/eckrel/5243495

import cv がsegfalするので AnacondaでOpenCVしたMacの話

Macにpyenv+opencvをインストールしたいのです

pyenv install 2.7.3 でインストールしたもの (A)

  • npymath.ini が見つからないエラー
  • scipyがインストール出来ない

pyenv virtualenv --distribute 2.7.3 venc27 でインストールしたもの (B)

libpython2.7.a (libpython2.7.dylib) が見つからない?

  • scipyはインストールできる
  • matplotlibがインストール出来ない
  • CC=clang pip install matplotlib なら通る

Linux(Ubuntu) でインストールしてみる (C)

Ubuntuなら動く

(A) と コレ(C) を比較してみると (A)には PYTHON_PATH/lib/python2.7/site-packages/numpy/core の下に lib ディレクトリが無い => numpyのインストールに失敗では?

numpyがきちんとインストールされない => opencvのpythonモジュールはnumpy必須なのでインストール出来ない

A,B はnumpyがきちんとインストールされていないであろうと思われる

どちらも numpyのimport_array() でsegfalしてる

このとき使ったインストールスクリプト

# brew switch ffmpeg 1.0

VERSION=2.4.3
INSTALL_DIR=$HOME/lib/opencv
# PYTHON_HOME=$HOME/.pyenv/versions/venv27
PYTHON_HOME=$HOME/.pyenv/versions/2.7.3
PYTHON_VERSION=2.7

mkdir -p opencv
cd opencv

curl -L http://sourceforge.net/projects/opencvlibrary/files/opencv-unix/${VERSION}/OpenCV-${VERSION}.tar.bz2/download -o OpenCV-${VERSION}.tar.bz2
tar jxvf OpenCV-${VERSION}.tar.bz2

mkdir -p ${INSTALL_DIR}
cd OpenCV-${VERSION}

mkdir -p build
cd build

cmake \
  -G "Unix Makefiles" \
  -D CMAKE_BUILD_TYPE=RELEASE \
  -D CMAKE_INSTALL_PREFIX=$INSTALL_DIR \
  -D BUILD_NEW_PYTHON_SUPPORT=ON \
  -D PYTHON_LIBRARY=$HOME/.pyenv/versions/2.7.3/lib/libpython${PYTHON_VERSION}.a \
  -D PYTHON_EXECUTABLE=$PYTHON_HOME/bin/python \
  -D PYTHON_PACKAGES_PATH=$PYTHON_HOME/lib/python${PYTHON_VERSION}/site-packages \
  -D PYTHON_INCLUDE_DIR=$PYTHON_HOME/include/python${PYTHON_VERSION} ..

make -j4
make install

ScipySuperpackの力を借りる (D)

ScipySuperpack

(A) や (B) とほぼ同じ import_array() でsegfalする

Anacondaの力を借りる (E)

scipy勉強会で知ったAnacondaを入れてみる

Anaconda - Scalable Data Analytics and Scientific Computing in Python

  • パッケージコレクション
  • Anaconda CE は無料
  • 同梱されているパッケージはこちら http://docs.continuum.io/anaconda/1.3/pkgs.html
  • Mac用はOpenCVは同梱されていない
  • ローカルディレクトリにインストールできる
  • matplotlibやqt, scikit-learnやpandas, cythonまで一緒にインストールされる お手軽!!

Anaconda すんなり入りませんでした

libgcc_s.1.dylibがない

Python 2.7.3 :: Continuum Analytics, Inc.
creating default environment...
Traceback (most recent call last):
  File "/Users/yano/lib/anaconda/pkgs/conda-1.3.5-py27_0/lib/python2.7/site-packages/conda/install.py", line 28, in <module>
    import json
  File "/Users/yano/lib/anaconda/pkgs/python-2.7.3-6/lib/python2.7/json/__init__.py", line 108, in <module>
    from .decoder import JSONDecoder
  File "/Users/yano/lib/anaconda/pkgs/python-2.7.3-6/lib/python2.7/json/decoder.py", line 5, in <module>
    import struct
  File "/Users/yano/lib/anaconda/pkgs/python-2.7.3-6/lib/python2.7/struct.py", line 1, in <module>
    from _struct import *
ImportError: dlopen(/Users/yano/lib/anaconda/pkgs/python-2.7.3-6/lib/python2.7/lib-dynload/_struct.so, 2): Library not loaded: /usr/local/lib/libgcc_s.1.dylib
  Referenced from: /Users/yano/lib/anaconda/pkgs/python-2.7.3-6/lib/python2.7/lib-dynload/_struct.so
  Reason: image not found

みたいなエラーがでたので ln -s /usr/lib/libgcc_s.1.dylib /usr/local/lib/libgcc_s.1.dylib した

gccbrewからインストールしたgccを使っている

hfx_codecがインポートされてない

LookupError: unknown encoding: hex

と出てインストールが停止する。インストールスクリプトはAnacondaのインストール指定したディレクトリに展開されているので ~/lib/anaconda/pkgs/conda-1.3.5-py27_0/lib/python2.7/site-packages/conda/install.pyfrom encodings import hex_codec を追加して、インストールを再開

Anacondaのインストーラーのシェルスクリプトから抜き出したものを再度実行する

PREFIX=/Users/yano/lib/anaconda
PYTHON=python

echo "creating default environment..."
CONDA_INSTALL="$PREFIX/pkgs/conda-1.3.5-py27_0/lib/python2.7/site-packages/conda/install.py"
$PYTHON $CONDA_INSTALL --prefix=$PREFIX --pkgs-dir=$PREFIX/pkgs --activate-all || exit 1
echo "installation finished."

pyenvにAnacondaを管理させるには

pyenvは ~/.pyenv/versions ディレクトリ以下にPYTHON_PATHにあたるディレクトリをまるっと 移動させてやるとそれだけで認識してくれるので、 ~/lib/anaconda にインストールしたPythonとライブラリを anaconda ディレクトリをそのまま ~/.pyenv/versions/anaconda として移動してやれば大丈夫だと思いましたが、 どうやらanacondaがインストールするライブラリの参照しているパスや、shebangのパスが /usr/bin/env python でなく決め打ちになっているので、 インストール時に指定するパスを ~/.pyenv/versions/anaconca としましょう。

Anacondaのインストールはこれで終わり!

Anaconda環境にOpenCVをインストールする

さっきと同じようなスクリプトで。違いはPYTHON_HOMEとcmakeのPYTHON_LIBRARY

VERSION=2.4.3
INSTALL_DIR=$HOME/lib/opencv
PYTHON_HOME=$HOME/.pyenv/versions/anaconda
PYTHON_VERSION=2.7

mkdir -p opencv
cd opencv

curl -L http://sourceforge.net/projects/opencvlibrary/files/opencv-unix/${VERSION}/OpenCV-${VERSION}.tar.bz2/download -o OpenCV-${VERSION}.tar.bz2

tar jxvf OpenCV-${VERSION}.tar.bz2

mkdir -p ${INSTALL_DIR}
cd OpenCV-${VERSION}

mkdir -p build
cd build

cmake \
  -G "Unix Makefiles" \
  -D CMAKE_BUILD_TYPE=RELEASE \
  -D CMAKE_INSTALL_PREFIX=$INSTALL_DIR \
  -D BUILD_NEW_PYTHON_SUPPORT=ON \
  -D PYTHON_LIBRARY=$PYTHON_HOME/lib/libpython${PYTHON_VERSION}.dylib \
  -D PYTHON_EXECUTABLE=$PYTHON_HOME/bin/python \
  -D PYTHON_PACKAGES_PATH=$PYTHON_HOME/lib/python${PYTHON_VERSION}/site-packages \
  -D PYTHON_INCLUDE_DIR=$PYTHON_HOME/include/python${PYTHON_VERSION} ..

make -j4
make install

cv2.soが参照しているライブラリのパスがおかしい

先程はDYLD_FALLBACK_LIBRARY_PATHを設定することで、この問題を回避しました。

libpython2.7.dylibのパスがおかしいのですが、では、どこを参照しているかというと、 /opt/anaconda1anaconda2anaconda3/lib/libpython2.7.dylib とかふざけたパスが設定されてるので、これをinstall_name_tool で修正します

% cd ~/.pyenv/versions/anaconda/lib/python2.7/site-packages
% install_name_tool -change /opt/anaconda1anaconda2anaconda3/lib/libpython2.7.dylib @executable_path/../lib/libpython2.7.dylib ./cv2.so

実行するpython~/.pyenv/versions/anaconda/binにあるので@executable_pathからの相対パスでいいと思います

追記:パスを修正するスクリプトを書きました >>

OpenCVのライブラリのパスはDYLD_LIBRARY_PATHに

追記:OpenCVのライブラリをanacondaに突っ込むスクリプトを書きました >>

OpenCVのライブラリのパスはずっとこのままの予定なので、DYLD_LIBRARY_PATHにセットしちゃいます

```sh

opencv

if [ -n "$DYLD_LIBRARY_PATH" ]; then export DYLD_LIBRARY_PATH=$DYLD_LIBRARY_PATH:~/lib/opencv/lib else export DYLD_LIBRARY_PATH=~/lib/opencv/lib fi

</del>

<del>
ライブラリパスを修正したのとpyenvで管理するようになったので、
`PATHとDYLD_FALLBACK_LIBRARY_PATH の設定`で設定した環境変数は両方要らなくなりました。消しましょう
</dek>


これで`penv global anaconda`などでanacondaのpythonが使えるようになって、
さらにimport cvしてもsegfalしなくなりました。やったね!

# まとめ

- Anaconda便利
- OpenCVのpythonモジュールインストールすげぇはまるというか鬼門はnumpyだと思う
- pyenvとAnacondaは共存できる!