StringをInputStreamに変換する

InputStream を受け取る API に、文字列から生成した InputStream を渡したいことがある。
このために StringBufferInputStream があったのだけれど deprecated であり、 StringReader を使うよう推奨されていて困る、ことがある。
自前で String から InputStream を生成する方法はこう。:

new ByteArrayInputStream(string.getBytes(Charset.forName("UTF-8")));

なお Charset.forName("UTF-8") は StandardCharsets.UTF_8 とすることもできる。(ただし Android の場合 API 19 以降)

巨大ドメインに参加している PC での /etc/passwd, /etc/group ファイルのつくりかた

先日 Cygwin を何度か入れなおす羽目になって、そのときにコンソールに表示されるこのメッセージ。:

Your group is currently "mkpasswd".  This indicates that your
gid is not in /etc/group and your uid is not in /etc/passwd.

The /etc/passwd (and possibly /etc/group) files should be rebuilt.
See the man pages for mkpasswd and mkgroup then, for example, run

mkpasswd -l [-d] > /etc/passwd
mkgroup  -l [-d] > /etc/group

Note that the -d switch is necessary for domain users.

「パスワードとグループがデフォルト設定のままになってるから mkpasswd と mkgroup を使って設定をするがいいじゃんよ」ってことなんだけれど、アクティブディレクトリーで膨大なユーザー・グループ情報が管理されている状況下で mkpasswd -d などすると実際死ぬ。延々とリスト取得していて、ちっとも終わりゃあしない!

で、対処法。現在のユーザー情報とホストマシンのローカル情報だけを反映した passwd と group ファイルを作ればよいので、:

$ mkpasswd -l -c > /etc/passwd
$ mkgroup -l -c > /etc/group

複数のドメインユーザーで共有する環境なら初回利用者は上記を実行して、それ以降に使うユーザーは自分のユーザー情報だけ追記更新ってのでもよさそう。:

$ mkpasswd -c >> /etc/passwd

ドメインユーザーに対して mkgroup -c が返す値は Domain Users:... のため、こちらは改めて追加する必要はない。

Windows 共有を Linux から利用する

CIFS UTILS を使って Linux 上のディレクトリーにマウントする。

準備

1. CIFS UTILS をインストールする

sudo apt-get install cifs-utils

2. Windows 共有の認証情報を保存する

cat > $HOME/.cifs-cred <<EOF
username=YOUR ID
password=YOUR PASSWORD
EOF
chmod 600 $HOME/.cifs-cred

3. マウント先ディレクトリーを作成する

mkdir -p $HOME/shared

マウント

mount -t cifs -o <オプション> <マウント先>

sudo mount -t cifs\
 -o noexec,nounix,uid=$(id -u),gid=$(id -g),credentials=$HOME/.cifs-cred\
 //Windows-Shared/ResourceName\
 $HOME/shared

アンマウント

umount [-l] <マウント先>

sudo umount $HOME/shared

-l オプションは、コマンドから即座に制御を戻しシステムにバックグラウンドでアンマウントさせる Lazy モード指定。
共有との制御通信に時間がかかる場合などに便利。

マングルされたシンボルのデマングル

アセンブルリストに出てくるマングルされたシンボルの羅列があまりにつからったので、ちょろっと調べてデマングルするためのコードを書いてみた。…だがしかし…

#include <cxxabi.h>
#include <cstdio>
#include <cstdlib>

int main(int argn, char **args) {
  if (argn > 1) {
    int status = 0 ;
    char *realname = abi::__cxa_demangle(args[1], 0, 0, &status);
    if (realname != NULL) {
      puts(realname);
      free(realname);
      return 0;
    } else {
      return 1;
    }
  } else {
    return 2;
  }
}

こんなんわざわざ書かなくても c++filt という便利コマンドがあった。

$ echo _ZN7android16LoadNativeBridgeEPKcPKNS_28NativeBridgeRuntimeCallbacksE |c++filt 
android::LoadNativeBridge(char const*, android::NativeBridgeRuntimeCallbacks const*)

objdump -d でディスアセンブルした出力をパイプで c++filt に流せば、可能な範囲でぜんぶデマングルしてくれる。

半開区間の探索

連続した半開区間があるとき、与えられた整数がどの半開区間に属するかを知りたい、なんて応用があって。

たとえば [0,30), [30, 50), [50, 80), [80, 100) とのような半開区間列があったとき 13 は [0, 30) に入るし、 50 は [50, 80) に入る。
この探索を Java コードでどう表現するか。

というので書いてみたのがこちら。:

class RangeFinder {
    public RangeFinder(long[] range) {
        assert range != null && range.length > 1 : "range は非 null で、要素を少なくともふたつ含む。";
        final int length = range.length - 1;
        index = new Range[length];
        for (int i = 0; i < length; ++i) {
            index[i] = new Range(range[i], range[i + 1]);
        }
    }

    public int find(final long value) {
        return Arrays.binarySearch(index, value);
    }

    private final Range[] index;

    private static final class Range implements Comparable<Long> {
        private final long beg;
        private final long end;

        public Range(long begin, long end) {
            this.beg = begin;
            this.end = end;
        }

        @Override
        public int compareTo(Long other) {
            final long value = other;
            if (value < beg) {
                return 1;
            }
            if (value < end) {
                return 0;
            }
            /* else */{
                return -1;
            }
        }
    }
}

こんなテストコードが動く。:

@Test
public void 所属する半開区間の探索() {
    // [0,10),[10,20),[20,30),[30,40),[40,50),[50,60),[60,70),[70,80),[80,90),[90,100)
    final long[] range = { 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100 };

    final RangeFinder finder = new RangeFinder(range);
    assertEquals(-1, finder.find(-1));
    for (int i = 0; i < 100; ++i) {
        assertEquals(i / 10, finder.find(i));
    }
    assertEquals(-11, finder.find(100));
}

binarySearch を使っているので、与える範囲の数列は昇順で並んでいることが前提。

もともとは…

もともとは binarySearch は値の探索には使えるけれど、連続した区間の探索に使うにはどうすればいいかな? というのがはじまりで。
long 配列があるんだったら、それを参照する形で流用できないものかと考えたのが次のコード。:

class OriginalRangeFinder {
    public OriginalRangeFinder(long[] range) {
        final int length = range.length - 1;
        this.range = range;
        index = new Index[length];
        for (int i = 0; i < length; ++i) {
            index[i] = new Index(i);
        }
    }

    public int find(final long value) {
        return Arrays.binarySearch(index, value);
    }

    private final long[] range;
    private final Index[] index;

    private final class Index implements Comparable<Long> {
        final int offset;

        public Index(int offset) {
            this.offset = offset;
        }

        @Override
        public int compareTo(Long other) {
            final long value = other;
            if (value < range[offset]) {
                return 1;
            }
            if (value < range[offset + 1]) {
                return 0;
            }
            /* else */{
                return -1;
            }
        }
    }
}

でも long と Index の配列を二本もたないほうが、そして Index クラスで親の range フィールドを共有しないほうが、わかりやすいだろうなというので冒頭に掲げたコードになりました。

剰余をつかわない FizzBuzz

twitter で剰余演算をつかわずに FizzBuzz をどう実装するかというのを見かけて、それだったら…とつくってみたくなった。のでつくってみた。

かんたんにまとめると、 "Fizz", "", "", "Fizz", "", "", … と繰り返す文字列のリストと "Buzz", "", "", "", "", "Buzz", "", "", … を繰り返す文字列のリストを組み合わせて、これの組み合わせが空文字列になるところを数字に置き換えると答えになる、というもの。

カッとなって twitter に投げたときは zip して uncurry (++) などと回り道をしたけれど、そこは zipWith で置き換えられるので、こんなかんじになる。:

cr = concat.repeat
fs = cr ["Fizz", "", ""]
bs = cr ["Buzz", "", "", "", ""]
fb n = let v = (zipWith (++) fs bs) !! n
  in if v == "" then show n else v
-- そして
map fb [1..100]

解説

fs は、 ["Fizz", "", ""] というリストの繰り返し (repeat) [ ["Fizz", "", ""], ["Fizz", "", ""], ["Fizz", "", ""], ...] をつくり、これを (concat して) 平らにして ["Fizz", "", "", "Fizz", "", "", "Fizz", "", ...] をつくっている。
同様に ["Buzz", "", "", "", ""] から bs = ["Buzz", "", "", "", "", "Buzz", "", "", ...] をつくる。

つぎに fs と bs の各要素を順に組み合わせたリストをつくる。
これは zipWith (++) fs bs でできる。 fs と bs それぞれの要素を先頭から順にとって (++) で結合した結果からリストをつくる処理になる。
(もともと zip は zipWith (,) で定義できて、タプルを生成する関数 (,) をふたつのリストに適用している)

さて、できあがったリストは ["FizzBuzz", "", "", "Fizz", "", "Buzz", "", ...]。
この要素が空文字列 "" になるところを数値からつくった文字列 (show n) に置き換えればよい。

まとめると \n -> let v = (zipWith (++) fs bs) !! n in if v == "" then show n else v。
これは FizzBuzz リストの n 番目の要素をとってこれを v とし、この v が空文字なら show n、そうでなければ v の値となる関数。

tweet での uncurry の説明

zipWith (++) fs bs を、 tweet したときは map (uncurry (++)) (zip fs bs) でつくっていた。
この動きだけれど、まず fs と bs を zip してリストをつくる。これはタプルのリスト、 [("Fizz", "Buzz"), ("", ""), ("", ""), ("Fizz", ""), ("", ""), ("", "Buzz"), ...] のようになる。
このリストに (map (uncurry (++))) を適用する。リスト内の各タプルに、関数 uncurry (++) を適用する、ということ。
もともと関数 (++) はリストを受け取って、さらにリストを受け取る関数(そしてこの関数はリストを返す)を返す高階関数。だからタプルには適用できない。ところが uncurry を (++) に適用するとあら不思議、高階関数 (++) がタプルを受け取ってリストを返す関数になってしまう。

(++) :: [a] -> [a] -> [a]
uncurry (++) :: ([a], [a]) -> [a]

uncurry の実装はこんなかんじ:

uncurry :: (a -> b -> c) -> (a, b) -> c
uncurry f = \(x, y) -> f x y

型は、 a -> (b -> c) という関数を受け取って (a, b) -> c という関数を返す高階関数。実装は関数 f を受け取って、関数 \(x, y) -> f x y という関数を返す。タプルを受け取って、そのタプルの要素をもとの f に渡すだけ。なんというか、こんなにさらっと書き下すだけで関数のインターフェースががらっと変わってしまうのが、ほんと、楽しい。

閑話休題

結局、タプルのリストに uncurry (++) を適用することで、タプルの前後要素が関数 (++) で連結される、と、そういう動きになる。

別解

Maybe をつかったほうが、より、 Haskell っぽいんじゃないかなって。:

cr = concat.repeat
fs' = cr [Just "Fizz", Nothing, Nothing]
bs' = cr [Just "Buzz", Nothing, Nothing, Nothing, Nothing]
fb n = fromJust $ zipWith mappend fs' bs' !! n `mplus` Just (show n)

でも、ちょっと読みにくい、よね? 残念だなあ。

Maybe の Monoid としての性質をつかって mappend。 mappend は Just の中身に適用される関数で、ここでは文字列(つまり文字のリスト)が Just の中身だから文字列が連結される。よって Nothing や Just "Fizz"、 Just "Buzz"、 Just "FizzBuzz" のはいったリストをつくりだせる。

そして Maybe の MonadPlus としての性質をつかって mplus。 mplus は、ふたつの Maybe を受け取り、先に Just になった値を返す(か、どちらも Nothing なら Nothing を返す)。

だから、先に mappend した Maybe リストのうち Nothing になるところが、 Just (show n) で置き換えられて、結果、ほしかったリストができあがるという仕組み。

イデアはいいとおもうんだけれどなあ。一ヶ月経ったら、たぶん自分も読めない。

IBus-Anthy の日本語入力で、キーボードレイアウトを US に変える

Ubuntu 13.10 にアップグレードしたら日本語入力が日本語配列強制になって難儀していた*1
ちょっと検索して「キーボード配列は変えられない、クソが!」というエントリーを見てしまったので諦めていたのだけれど、変えられました!

コントロールパネルから Text Entry を開き、 Input source to use で Japanese(Anthy) をフォーカスすると、その右下、キーボードレイアウトのアイコンの左横に設定アイコンが表示されるのでこれをクリック。

すると Setup - IBus-Anthy というパネルが開く。その Typing Method タブに Keyboard layout があるので、ここから us を選ぶ。完了。(あるいは Default を選ぶと、つながっているキーボードそのものを適当に扱ってくれるようなのでこれを選んでもいいとおもう)

ところで入力ソース切り替えが Super + Space になっているのは、どうにかなるんでしょうか? Super を押したところで、なんていうんだろう、 Windows スタートメニューみたいなのが開いてフォーカスを奪われるので、ソース切り替えができないんです。仕方ないので Shift + Super + Space の順で押して逆向きにソース切り替えするというのでしのいでいますが…。良案求む。

*1:英語配列キーボードを使っているのに、日本語入力に変えると日本語配列キーボードがつながっているかのように入力がねじまげられてしまう。こうなると \ や _ が入力できなくなるので死にそうになる