tmuxでコンソール共有が便利すぎる

「ふええプログラミング分からない><」とか「ふええコンパイルうまくいかない><」とか、
場合によっては環境に依存しそうな問題を友人から持ちかけられたことって多いとおもいます。
というかぼくは持ちかける側なのですが(´・ω・`)

普通は「いまPATHは〜で、これを実行するとこういう結果がでて...」みたいにSkypeでログを切り貼りしながら話を進めたりするんですが、これ結構心が折れる。「ここがおかしい」「ここってどこ!!」「(スクリーンショットを貼る)」みたいなこともよくあるし。

で、えりっくさんなりの解決策が1つ見つかったのでご紹介。
tmuxを使うことで、相談してきた相手の見ているコンソールをまんま自分の目の前に再現し、さらにそのまま相手の権限で操作を行うことができます(ちょっと危険)。
ちなみに学校やVPSのように外部からSSHアクセスできる環境が条件となります(ローカルのひとごめんね!)。

相談する側の操作:

tmux -S /tmp/shared_sock
chmod 777 /tmp/shared_sock

でtmux起動、ソケット作成。このソケットファイルは互いにアクセスできる場所に置きましょう。
相談を受ける側の操作:

tmux -S /tmp/shared_sock attach

だけ。

これで全く同じ画面を共有できます。
カーソルは当然ながら共通なので、Skype音声通話で「ちょっと操作していい?」みたいに同期をとりながらやるとストレスなく操作ができていいかんじです。
ちなみにMacだと「システム環境設定」から「リモートログイン」でsshdを立てられます。ローカルですごい数の相談相手にお願いする場合とかに便利かも?

注意:exitで終了すると両方のセッションが落ちてしまうので、相談を受けた側はtmux detachで退席しましょう!!!

screenでもできることはわかっていたんですが、tmuxのほうがこんなにお手軽だったので。
http://sourceforge.jp/magazine/06/09/11/088249
参考までにscreenでの実現方法も書いておきます。

追記:
http://partty.org/ 使おう

第7回カーネル/VM探検隊で仮想マシン作った発表してきました

題名のとおりです、カーネル/VM探検隊でLTしてきました!
カーネル/VM探検隊に関しては↓
http://atnd.org/event/kernelvmseven
https://sites.google.com/site/kernelvm/

えーと、数日間でMIPS R3000アーキテクチャ仮想マシンErlang(!)で途中まで書きました。
recrioって名前を付けました。一応動いてはいますが、割り込みあたりがまだちゃんと実装できてなかったり、
ELFロードできてなかったり、なんかもういろいろダメですね...

スライドはこちら。
http://www.slideshare.net/siritori/ss-12638392

リポジトリはこちら。
https://github.com/siritori/recrio

recrio_debugモジュールでなんかいろいろテストして遊べます。

3> recrio_debug:test().
true
addi reg(2) := reg(0) + <<255,0>>
reg2 : 00000000000000001111111100000000              
       0 : 00100000000000101111111100000000              
       4 : 00100000000000011111011110001111              
       8 : 00100100001000011111000011111111              
       C : 00000000000000010000100001000010              
      10 : 00010000001000000000000000000100              
      14 : 10101100010000010000000000000000              
      18 : 00100000010000100000000000000100              
      1C : 00001000000000000000000000000011              
      20 : 00000000000000000011111111001101              

addi reg(1) := reg(0) + <<247,143>>
reg1 : 00000000000000001111011110001111              
reg2 : 00000000000000001111111100000000              
       0 : 00100000000000101111111100000000              
       4 : 00100000000000011111011110001111              
       8 : 00100100001000011111000011111111              
       C : 00000000000000010000100001000010              
      10 : 00010000001000000000000000000100              
      14 : 10101100010000010000000000000000              
      18 : 00100000010000100000000000000100              
      1C : 00001000000000000000000000000011              
      20 : 00000000000000000011111111001101
4> 

MIPSアーキテクチャのいいお勉強になりますね。実際、だんだんオペコードを覚えてきました...
バイナリパターンマッチのお陰でデコード部分がすんごい簡単に書けるのがステキだなって思いました。
ErlangなくせにOTPも使ってませんごめんなさい

詳しいことはスライドを見て下さいね!゜+.(・ω・)゜+.゜

Twitterにおけるつぶやきの即時話題推定技術「どたばたかいぎ」の裏側(実装途中)

OverView

最初はPerlで書いてたんですけど、今は主にErlangで書いてあります。TwitterのUser Streamsからつぶやきを取得し、MeCab形態素解析にかけて名詞のみ抽出しています。MeCabは既に強化済です*1
このエントリのお話すること

  1. ErlangからOauthライブラリ使ってUserStreamsにつなぐところ
  2. どたばたかいぎのCore部分
  3. ErlangからMeCabを触るNIFインターフェイスのこと

Erlang内でつかっているもの

べ、べつに http://naoyat.hatenablog.jp/entry/2012/01/04/220639 のエントリの存在に書き終えたあとで気づいたりとかしてないし...車輪の再発明じゃないし...(´;ω;`)

1.ErlangからOauthライブラリ使ってUserStreamsにつなぐところ

何度見たかわからないid:takkkunhttp://d.hatena.ne.jp/takkkun/20091016/1255722692を読みながらhttp://d.hatena.ne.jp/polistes/20111130/1322663545とうまいことつなげる。
つぶやきが流れてきたらjiffyちゃんでdecodeしたのちにコールバック関数CallBack(Bin, Args)でゴニョゴニョできるような設計に。なにか画面出力するときはNotifierに流しこむようにしておきました。じゃないと標準出力が非常に残念なことになる(´・ω・`) 流れてきた欠片を拾うだけのstreamer/2と、それを受け取ってからプロセス生成したりNotifierに伝えるlistenerがあります。要erlang-oauth, jiffy。get_access_token()という関数があるんだけどコピペなので省略。

-module(userstream).
-author("Eric Sartre <siritori@gmail.com>").
-export([start/5, stop/1]).
-define(CONSUMER_KEY, "ConsumerKey").
-define(CONSUMER_SECRET, "ConsmerSecret").

start(AccessToken, AccessTokenSecret, Notifier, CallBack, Args) ->
   Listener = spawn(?MODULE, listener, [Notifier, CallBack, Args]),
   Streamer  = spawn(fun() ->
      Consumer = {?CONSUMER_KEY, ?CONSUMER_SECRET, hmac_sha1},
      Options = [{sync, false}, {stream, self}],
      URL = "https://userstream.twitter.com/2/user.json",
      case oauth:post(URL, [], Consumer, AccessToken, AccessTokenSecret, Options) of
         {ok, RequestId} -> streamer(RequestId, Listener);
         {error, Reason} -> send(Listener, {error, Reason})
      end
   end),
   {ok, Streamer}.

stop(Streamer) ->
   send(Streamer, stop),
   receive {Streamer, stopped} -> stopped end.

streamer(RequestId, Listener) ->
   receive
      {http, {RequestId, stream_start, _Headers}} ->
         send(Listener, started),
         streamer(RequestId, Listener);
      {http, {RequestId, stream, Part}} ->
         case Part of
            <<"\r\n">> -> noop;
            _          -> send(Listener, {stream, Part})
         end,
         streamer(RequestId, Listener);
      {http, {RequestId, {error, Reason}}} ->
         send(Listener, {error, Reason}),
         erlang:exit(stream_disconnected);
      {From, stop} ->
         httpc:cancel_request(RequestId),
         send(Listener, stop),
         send(From, stopped)
   end.

listener(Notifier, CallBack, Args) ->
   receive
      {_Streamer, start} ->
         send(Notifier, start),
         listener(Notifier, CallBack, Args);
      {_Streamer, {stream, Part}} ->
         spawn(fun() ->
            {Data} = jiffy:decode(Part),
            case lists:keyfind(<<"text">>, 1, Data) of
               false -> ok;
               {<<"text">>, Text}  ->
                  CallBack(unicode:characters_to_binary(Text), Args)
            end
         end),
         listener(Notifier, CallBack, Args);
      {_Streamer, {error, Reason}} ->
         send(Notifier, {error, Reason});
      {_Streamer, stop} ->
         send(Notifier, stop)
   end.

send(To, Msg) -> To ! {self(), Msg}.

たとえばこんなふうにつかう。

-module(hoge).
-compile(export_all).
callback(Bin, _Args) -> printer ! {tweet, Bin}.
test() ->
   erlang:register(printer, spawn(?MODULE, printer, [])),
   userstream:start("なんたら", "かんたら", printer, fun ?MODULE:callback/2, []).
printer() ->
   receive 
      {_Listener, start} ->  
         io:format("Info: stream started~n"), 
         printer(); 
      {tweet, Bin} ->  
         io:format("tweet!:~ts~n", [Bin]), 
         printer(); 
      {_Listener, {error, Reason}} ->  
         io:format("Error: ~p~n", [Reason]); 
      {_Listener, stop} ->  
         io:format("Info: stream stopped~n") 
   end.

たぶん一行づつUserStreamが流れるとおもう。

2.どたばたかいぎのCore部分

どたばたかいぎではさっきのuserstreamモジュールをこんなふうに使っています。category.etsには単語のカテゴリのリスト、redirect.etsには単語の言い換えのリスト(ほぼ要素数は1)が格納されてます。

-module(dotabata).
-export([kaigi/0, stop/1, callback/2, printer/0]).

kaigi() ->
   {ok, _} = mecab:init_context(),
   {ok, CategoryTab} = ets:file2tab("category.ets"),
   {ok, RedirectTab} = ets:file2tab("redirect.ets"),
   Tab = {CategoryTab, RedirectTab},
   {ok, AccessToken, AccessTokenSecret} = userstream:get_access_token(),
   register(printer, spawn(fun ?MODULE:printer/0)),
   Streamer = userstream:start(AccessToken, AccessTokenSecret, printer, fun ?MODULE:callback/2, Tab),
   {Streamer, CategoryTab, RedirectTab}.

stop({Streamer, CategoryTab, RedirectTab}) ->
   userstream:stop(Streamer),
   ets:delete(CategoryTab),
   ets:delete(RedirectTab).

printer() ->
   receive
      {_Listener, start} ->
         io:format("Info: stream started~n"),
         printer();
      {tweet, Bin, Tokens} ->
         io:format("tweet!:~ts~n", [Bin]),
         lists:foreach(fun(I) -> io:format("~ts~n", [I]) end, Tokens),
         io:format("~n"),
         printer();
      {_Listener, {error, Reason}} ->
         io:format("Error: ~p~n", [Reason]);
      {_Listener, stop} ->
         io:format("Info: stream stopped~n")
   end.

callback(Bin, {CategoryTab, RedirectTab}) ->
   {ok, Tokens0} = mecab:parse(Bin),
   Tokens = lists:foldl(fun(I, Acc) ->
      case ets:lookup(RedirectTab, I) of
         [] -> [I|Acc];
         [{I, Token}] -> Token ++ Acc
      end
   end, [], Tokens0),
   Categories = lists:foldl(fun(I, Acc) ->
      case ets:lookup(CategoryTab, I) of
         [] -> [I|Acc];
         [{I, Category}] -> [I|Category] ++ Acc
      end
   end, [], Tokens),
   printer ! {tweet, Bin, sets:to_list(sets:from_list(Categories))}.

キモはcallback/2。mecabモジュール(後述)によってつぶやきから名詞のリストを取り出し、redirect.etsによって表記ゆれを吸収しています。その後category.etsによってその上位概念を取得し、すべてリストに追加してuniqueにしたあとprinterに投げて表示させています。

3.ErlangからMeCabを触るNIFインターフェイス

Erlang形態素解析をするためにMeCabさんを使います。NIFをつかってErlangVMにドゴォォォンと載せちゃう。まずは.erlのスケルトン。

-module(mecab).
-export([load/0, init_context/0, parse/1, destroy_context/0]).

load() -> erlang:load_nif("./mecab", 0).
init_context() -> {error, library_not_loaded}.
parse(Bin) when is_binary(Bin) -> {error, library_not_loaded}.
destroy_context() -> {error, library_not_loaded}.

んでもってCをゴリゴリ書く。大枠はこんなかんじ。こう書くとErlangからはfunc0/0とfunc1/3が見えるようになる。

#include "erl_nif.h"
static ERL_NIF_TERM func0_(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
   ・
   ・
}
static ERL_NIF_TERM func1_(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
   ・
   ・   
}

static ErlNifFunc nif_funcs[] = {
   {"func0", 0, func0_},
   {"func1", 3, func1_},
};
ERL_NIF_INIT(mecab, nif_funcs, NULL, NULL, NULL, NULL)

引数でbinaryを指定して受け取って、それを文字列にするあたりのコード。
enif_inspect_binaryでERL_NIF_TERMなbinaryをErlNifBinaryに変換するんですって。ErlNifBinaryは使った後に後片付けが必要。

static ERL_NIF_TERM parse(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
   ErlNifBinary bin;
   enif_inspect_binary(env, argv[0], &bin);
   char *input = (char*)malloc(bin.size+1);
   memcpy(input, bin.data, bin.size);
   input[bin.size] = '\0';
   enif_release_binary(&bin);

逆に文字列('\0'で終わってないけど)からbinaryに変換するコード。ERL_NIF_TERMになったのでもうこいつはVMの管理下にあるのでreleaseはしない。

   ErlNifBinary bin;
   enif_alloc_binary(node->length, &bin);
   memcpy(bin.data, node->surface, node->length);
   ERL_NIF_TERM bin = enif_make_binary(env, &bin);

というわけで全コード。

#include "erl_nif.h"
#include <stdio.h>
#include <stdlib.h>
#include <mecab.h>
#include <string.h>

static mecab_t *mecab = NULL;

static ERL_NIF_TERM tuple2(ErlNifEnv *env, const char *s1, const char *s2) {
   ERL_NIF_TERM t1 = enif_make_atom(env, s1);
   ERL_NIF_TERM t2 = enif_make_atom(env, s2);
   return enif_make_tuple2(env, t1, t2);
}

static ERL_NIF_TERM init_context(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
   if(mecab != NULL) return tuple2(env, "error", "already_initialized");
   if((mecab = mecab_new(0, NULL)) == NULL) {
      return tuple2(env, "error", "failed_to_initialize");
   }
   return tuple2(env, "ok", "initialized");
}

static ERL_NIF_TERM destroy_context(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
   if(mecab != NULL) {
      mecab_destroy(mecab);
      mecab = NULL;
   }
   return tuple2(env, "ok", "destroyed");
}

static ERL_NIF_TERM trace_node_(ErlNifEnv *env, mecab_node_t *node, ERL_NIF_TERM rest) {
   if(node == NULL) return rest;
   if( strstr(node->feature, "代名詞")) return trace_node_(env, node->next, rest);
   if(!strstr(node->feature, "名詞,"))  return trace_node_(env, node->next, rest);
   if( strstr(node->feature, "接尾"))   return trace_node_(env, node->next, rest);
   if( strstr(node->feature, "非自立")) return trace_node_(env, node->next, rest);
   ErlNifBinary bin;
   enif_alloc_binary(node->length, &bin);
   memcpy(bin.data, node->surface, node->length);
   ERL_NIF_TERM tail = enif_make_list_cell(env, enif_make_binary(env, &bin), rest);
   return trace_node_(env, node->next, tail);
}

static ERL_NIF_TERM trace_node(ErlNifEnv *env, mecab_node_t *node) {
   return trace_node_(env, node, enif_make_list(env, 0));
}

static ERL_NIF_TERM parse(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
   if(mecab == NULL) {
      return tuple2(env, "error", "context_not_initialized");
   }
   /* map ErlNifBinary to char string */
   ErlNifBinary bin;
   enif_inspect_binary(env, argv[0], &bin);
   char *input = (char*)malloc(bin.size+1);
   memcpy(input, bin.data, bin.size);
   input[bin.size] = '\0';
   enif_release_binary(&bin);
   /* parse to node*/
   const mecab_node_t *node = mecab_sparse_tonode(mecab, input);
   if(node == NULL) return tuple2(env, "error", "failed_to_parse");
   ERL_NIF_TERM ok = enif_make_atom(env, "ok");
   return enif_make_tuple2(env, ok, trace_node(env, node));
}

static ErlNifFunc nif_funcs[] = {
   {"init_context",    0, init_context},
   {"destroy_context", 0, destroy_context},
   {"parse", 1, parse}
};

ERL_NIF_INIT(mecab, nif_funcs, NULL, NULL, NULL, NULL)

trace_node_で末尾再帰しながらMeCabのnodeリストをErlangのバイナリのリストに変換していってます。ついでに名詞の振り分けとかもここでやっちゃってる。
コンパイルで大コケする。

[eric@TSUBAKI]% gcc -I$ERL_ROOT/usr/include `mecab-config --cflags` `mecab-config --libs` --undefined suppress -flat_namespace -fPIC -shared -o mecab.so mecab.c 

$ERL_ROOTはえりっくさんの環境では/opt/local/lib/erlang/でした。ちなみに便宜上環境変数で表現しただけでこういう環境変数がなにかのお陰でセットされたりすることはありません。
こうやって使う↓

1> l(mecab).
{module,mecab}
2> mecab:load().
ok
3> mecab:init_context().
{ok,initialized}
4> String = unicode:characters_to_binary("Erlang触って睡眠不足いえーい。").
<<69,114,108,97,110,103,232,167,166,227,129,163,227,129,
  166,231,157,161,231,156,160,228,184,141,232,182,179,227,
  129,...>>
5> {ok, L} = mecab:parse(String).
{ok,[<<231,157,161,231,156,160,228,184,141,232,182,179>>,
     <<"Erlang">>]}
6> lists:foreach(fun(I)->io:format("~ts~n", [I]) end, L).
睡眠不足
Erlang
ok
7> 

ツッコミ歓迎

「お前ここ遅くなるぞ」とかいろいろあったら教えて下さい。

リアルタイムにTwitterのつぶやきの話題推定をする技術「どたばたかいぎ」研究途中報告

お久しぶりです。えりっくです。実装に関しては別エントリにまとめることにします。
筑波大学大学院システム情報工学研究科産学間連携推進室にて、ぼく含め3人で研究をしています。ここでの研究は企業と連携をとり、社会に還元することを目的としています。もし実用化できれば、Twitterユーザたちにサービスとして展開することも考えています。 既にこの研究は既にニコニコ大百科(有限会社未来検索ブラジル様)、Pixiv百科事典(Pixiv様)の記事データ提供によるご協力を頂いております。

で、どういう技術なの。

タイトルの通りつぶやきからその話題を推定する技術の研究をしています。
この研究がうまくいくと、TwitterのTLに張り付く必要がなくなります。

Excelわからんー。こんなのPerlでゴリゴリ書いたら一発ですよ」

とあなたがつぶやいたら、

「Wordの出来の悪さに比べてヤツの出来はやばい。Microsoft本気出してる。」
PerlよりRubyにしませんか(´・ω:;.:... 」

みたいなつぶやきがだれかさんによってTLに流れた時に勝手にあなたに通知されるようになります。
映画サマーウォーズの1シーンにもあるように、TLのつぶやきが話題ごとにまとめられて表示されるユーザインタフェースTwitterクライアントもできるかもしれません。夢がひろがるね。

アイディア

一般的に、普通はtf-idf(単語が出てきた回数)だとか使ってその語彙分布から文章の話題を推定します。ところがTwitterの文章は140文字以内なのでこういうアプローチが使えない。じゃあどうするか。

つぶやきに含まれる特徴的な語の上位概念・関連概念を予め用意しておき、つぶやきに含まれる単語1つ1つの上位概念・関連概念を探索して取得する
っていうのをおもいつきました。例えば「Erlang」という単語には「関数型言語」「オープンソース」「並行計算」「Erlang」「プログラミング言語」が対応するように辞書を用意しておけば、「Erlang」を含むつぶやきの話題は「関数型言語」「オープンソース」「並行計算」「Erlang」「プログラミング言語」である、と推定ができます(いろいろ端折った)。っていう。仕組み自体は至極簡単でしょ。「おもいついた」っていうのが恥ずかしくなるくらい。

表記ゆれ

ところで、日本語には表記ゆれが存在しますね。「Google」「GOOGLE」「グーグル」とか。「おっぱい」「乳房」や「一次メモリ」「主記憶装置」「メインメモリ」といった同一概念のものもあります。これらを同一視させたいですね。つぶやきから特徴的な単語を抽出したあとに、それぞれを違う単語に置き換えられないか確かめ、変換します。

からのー

変換された特徴語たちを使い、データベースからそれぞれの上位概念を取得して...その先はちょっとまだ検討中です←
最終的に「このつぶやきとこのつぶやきは話題が似てる度〜%だ!」というような推定ができるようになりたいな、と思ってます。その上位概念が抱える単語数が多ければ多いほど重要度を下げたりとかいろいろ考えてるんですけどね。いままでお話したことを図で書くとこんな感じ。


理想と現実

「上位概念なんてどっから持ってくるんだよ」
うん、言うと思った。でもこれみんなよく知ってるアレを使うんですよ。
Wikipedia
ニコニコ大百科
Wikipedia
「関連項目」だとか「カテゴリ」あたりから上位概念とか関連概念を引っ張り出してきます。あと記事名も取得して持っておきます。これを文章中から特徴語を抽出するために使います。
WikipediaMySQLのダンプをPerlのようなもので殴ってデータ生成
ニコニコ大百科はデータ提供してもらって自前パースしてPerlのようなものd(ry
Pixivもデータ提供してもらってPerlの(ry
快く承諾していただいたブラジル様とPixiv様に感謝。

頑張ったお陰でいいかんじの概念データベースが出来上がりました。例えば

ももクロ百田夏菜子ちゃんが可愛すぎて生きるのが辛い。あのえくぼは本当にずるい。」

というつぶやきからは

が取得できました。

いまどこまで実装できてるの?

User Streamsからつぶやきを拾い、上位概念をつぶやきごとにリアルタイムに表示するところまでできてます。プロトタイプをPerlで書いてたんですが、途中からErlangに移行しました。別エントリに書く予定です。

今後の課題

  • 曖昧さのある単語の推定(特に略語。ACは「交流電源」なのか「公共広告機構」なのか)
  • 未知概念のオンライン学習
  • 話題推定アルゴリズムの更なる研究
  • つぶやきの話題類似度比較アルゴリズムの研究

Growlで自分の好きな通知音を設定する方法

みんな知ってるのかデフォルトで間に合ってるのか知らないけど全然情報がなかったので書いておく。
みんな大好きGrowlだけど、あれ自分で好きな効果音とかをファイルで指定とかってできないんだよね。

やり方は簡単。
/System/Library/Soundsに追加したい音をaif形式で置くだけ。
aif形式はiTunesで変換ができます。
root権限が必要みたいなのでそこらへんはぐぐっていただけると助かります。

GRUB rescueで九死に一生を得た had a narrow escape from death thanks for GRUB rescue

Debian手が滑っていれてしまった。いろいろカスタマイズして遊んでた。
パーティションいじってるときにどうやら失敗したようで起動時にこれが出た。

GRUB Loading.
Welcome to GRUB!

error: no such partition.
Entering rescue mode...
grub rescue>

へー・・・。

grub rescue>helpUnknown command 'help'
grub rescue>h
Unknown command 'h'
grub rescue>?
Unknown command '?'
grub rescue>ls
(hd0) (hd0,msdos6) (hd0,msdos5) (hd0,msdos1)
grub rescue>echo 'fu*k'
Unknown command 'echo'

f*ck!!!!!!!!
ここで@_ITF_から

insmod (h0,?)/boot/grub/normal.mod
normal

してみろって言われる。

grub rescue>insmod (h0,msdos6)/boot/grub/normal.mod
error: no such fileなんとかかんとか
grub rescue>

oh. しばらく遊ぶ。

grub rescue>ls (hd0,msdos1)/
error: unknown file system
grub rescue>ls (hd0,msdos6)/
bin boot dev etc home initrd.img lib lost+found media mnt opt proc root sbin selinux srv sys tmp usr var vmlinuz
grub rescue>ls (hd0,msdos6)/boot/grub
915resolution.mod acpi.mod affs.mod afs.mod afs_be.mod aout.mod at_keyboard.mod ata.mod ata_pthru.mod befs.mod befs_be.mod biosdisk.mod bitmap.mod bitmap_scale.mod blocklist.mod boot.img boot.mod bsd.mod bufio.mod cat.mod cdboot.img chain.mod cmostest.mod cmp.mod command.lst configfile.mod core.img cpio.mod cpuid.mod crc.mod crypto.lst crypto.mod cs5536.mod date.mod datehook.mod datetime.mod device.map diskboot.img dm_nv.mod drivemap.mod echo.mod efiemu.mod efiemu32.o efiemu64.o elf.mod example_functional_test.mod ext2.mod extcmd.mod fat.mod font.mod fs.lst fshelp.mod functional_test.mod gcry_arcfour.mod gcry_blowfish.mod gcry_camellia.mod gcry_cast5.mod gcry_crc.mod gcry_des.mod gcry_md4.mod gcry_md5.mod gcry_rfc2268.mod gcry_rijndael.mod gcry_rmd160.mod gcry_seed.mod gcry_serpent.mod gcry_sha1.mod gcry_sha256.mod gcry_sha512.mod gcry_tiger.mod gcry_twofish.mod gcry_whirlpool.mod gettext.mod gfxmenu.mod gfxterm.mod gptsync.mod grldr.img grub.cfg grubenv gzio.mod halt.mod handler.lst hashsum.mod hdparm.mod hello.mod help.mod hexdump.mod hfs.mod hfsplus.mod iorw.mod iso9660.mod jfs.mod jpeg.mod kernel.img keystatus.mod linux.mod linux16.mod lnxboot.img loadenv.mod locale loopback.mod ls.mod lsmmap.mod lspci.mod lvm.mod mdraid.mod memdisk.mod memrw.mod minicmd.mod minix.mod mmap.mod moddep.lst msdospart.mod multiboot.mod multiboot2.mod nilfs2.mod normal.mod ntfs.mod ntfscomp.mod ohci.mod part_acorn.mod part_amiga.mod part_apple.mod part_bsd.mod part_gpt.mod part_msdos.mod part_sun.mod part_sunpc.mod partmap.lst parttool.lst parttool.mod password.mod password_pbkdf2.mod pbkdf2.mod pci.mod play.mod png.mod probe.mod pxe.mod pxeboot.img pxecmd.mod raid.mod raid5rec.mod raid6rec.mod read.mod reboot.mod regexp.mod reiserfs.mod relocator.mod scsi.mod search.mod search_fs_file.mod search_fs_uuid.mod search_label.mod serial.mod setjmp.mod setpci.mod sfs.mod sleep.mod tar.mod terminal.lst terminal.mod terminfo.mod test.mod tga.mod trig.mod true.mod udf.mod ufs1.mod ufs2.mod uhci.mod usb.mod usb_keyboard.mod usbms.mod usbtest.mod vbe.mod vbeinfo.mod vbetest.mod vga.mod vga_text.mod video.lst video.mod video_bochs.mod video_cirrus.mod video_fb.mod videotest.mod xfs.mod xnu.mod xnu_uuid.mod zfs.mod zfsinfo.mod
grub rescue>

どうやら今回ほしいものはmsdos6内にあるっぽい。
ここらへんで追加情報がくる。

grub rescue>set
prefix = (hd0,msdos7)/boot/grub
root = hd0,msdos6
grub rescue>set prefix=(h0,msdos6)/boot/grub
grub rescue>set root=h0,msdos6
grub rescue>insmod (h0,msdos6)/boot/grub/normal.mod
grub rescue>normal

やったあああああああ起動したああああああああああああああああああ
というわけでみなさん「normalなんてしらねーよ!」って言われたらこの環境変数を変えるように。あと英字配列にするように(この時点ではドライバが読まれてないので英字配列入力になってる)

で、普通ならこのあとちゃんとGRUB入れ直すんだけど。
なんか悔しかったのでもう一回ハマりにいった。

GRUB Loading.
Welcome to GRUB!

error: no such partition.
Entering rescue mode...
grub rescue>set prefix=(h0,msdos6)/boot/grub
grub rescue>set root=h0,msdos6
grub rescue>insmod (h0,msdos6)/boot/grub/help.mod
grub rescue>help
(略)
grub rescue>insmod (h0,msdos6)/boot/grub/echo.mod
grub rescue>echo 'f*ck'
f*ck
grub rescue>insmod (h0,msdos6)/boot/grub/normal.mod
grub rescue>normal

(ドヤ顔


I installed Debian because of some mistake. customized various settings.
Because I tweaked some partitions, the computer failed to boot and showed me this:

error: no such partition
grub rescue>

Erlang sshモジュールで遊ぼうとした tried to play by Erlang ssh module

最初はこのモジュール簡単に使えるんじゃないかなーとか思ってたんだけどそげぶされた。。。
リファレンス読んでこんなふうにリモートにつなごうとしたんだけど標準入力がブロッキングされて詰んだ

1>application:start(crypto).
ok
2>application:start(ssh).
ok
3>{ok, Ref} = ssh:connect("example.com", 22, [{user, "user"}, {password, "passwd"}]).
New host example.com accept [y/n]?

あわわわ。Erlang Question ML探してこんなのみつけた
http://erlang.2086793.n4.nabble.com/SSH-client-example-td2106867.html
あとこのコードも参考にした
https://github.com/jj1bdx/sshrpc/blob/master/src/client_test_nonotp.erl

読んでからいざリベンジ。

1>application:start(crypto).
ok
2>application:start(ssh).
ok
3>ssh:shell("example.com", [{user, "user"}, {password, "passwd"}, {silently_accept_hosts, true}]).
>ls
Desktop
Documents
Downloads
Library
Mail
Maildir
Movies
Music
Pictures
Public
.
.
.

ははぁ、リモートマシンにつなぐときは{silently_accept_hosts, true}でやるとブロッキングされずにできるみたい。
結局ssh_channel:send/2使ってリモートマシンと通信はできなかったけど近いうちにやる。

以下英文

At first, I thought I could use this module easily. But the expectation was broken.
First of all, I read user reference page and tried to connect to remote host by as follows, but standard input was strangely blocked:

1>application:start(crypto).
ok
2>application:start(ssh).
ok
3>{ok, Ref} = ssh:connect("example.com", 22, [{user, "user"}, {password, "passwd"}]).
New host example.com accept [y/n]?

Oops. I searched in Erlang Question ML so that I found this page:
http://erlang.2086793.n4.nabble.com/SSH-client-example-td2106867.html
And, I also referred this code:
https://github.com/jj1bdx/sshrpc/blob/master/src/client_test_nonotp.erl

After reading two codes, I revenged to use ssh.

1>application:start(crypto).
ok
2>application:start(ssh).
ok
3>ssh:shell("example.com", [{user, "user"}, {password, "passwd"}, {silently_accept_hosts, true}]).
>ls
Desktop
Documents
Downloads
Library
Mail
Maildir
Movies
Music
Pictures
Public
.
.
.

Hah, when we connect some hosts, we can connect with adding option{silently_accept_hosts, true} so that standard input isn't blocked.
After all, I couldn't communicate with remote machine using ssh_channel:send/2. I'll try one of these days.