追記

Matzにっき


2014-12-22 そろそろStreemについてひとこと言っとくか [長年日記]

久しぶりの更新

GitHubの <URL:http://github.com/matz/streem> を公開したら驚くべき反響の大きさなので、本人もびっくりしている。

ので、ここでちょっとまとめておく。

  • もともとは日経Linuxの自作言語入門の連載のネタ
  • 時系列的には2015年1月号で言語仕様を決めた(原稿提出は11月中旬)
  • 2015年2月号で実装について解説(原稿提出は12月初旬)
  • 2月号原稿には「github.com/matz/streemを参照のこと」と書いた
  • 提出したその日に1月号発売
  • 原稿提出後、原稿で解説した部分を実装し(300行程度)、githubにアップロード
  • だれかが見つける
  • hackernews, redditなどでバズる
  • github issues, pull requestなどいっぱいくる
  • 私が実装する前に Go で実装しちゃう人が出る (mattn/streeem)

自分でもなにを言っているのかと思うけど、雑誌という出版物と比較して、超スピードとかでは説明のつかないネットとOSSコミュニティのバズり方を見た思いがする。

一方、雑誌連載のサンプルであるStreemだが、言語仕様についてはパッとした思いつき、 というわけでもなくて、数カ月間、このような言語はあまりないし、実用的価値もありそうと思って作っている。

特徴

  • Streamモデルにより、高い抽象度でコンカレント処理が記述できる
  • マルチコアを活用できる(ように実装できたらいいなあ)
  • 関数型、オブジェクト指向、ストリームモデルの融合
  • 「Rubyとは違う言語設計アプローチ」の実践

雑誌の連載のネタだとはいえ、今後も開発をやめるつもりもないので、ほそぼそと進歩し続ける予定。

っていうか、現在 C でタスクスケジューリングを実装することの困難さに絶望しつつあるので、 マジで streeem を参考に Go で実装するかも。

[]

2013-07-31 [長年日記]

_ mrubyのmrb_gc_arena_save()/mrb_gc_arena_restore()の使い方

Twitterで質問を受けたので、 mrubyのmrb_gc_arena_save()/mrb_gc_arena_restore()の使い方 という解説を行った。が、1つ140文字のTwitterでの解説にはどうしても無理があるので、 こっちでまとめることにする。

まずは、Twitterの発言*1はこんな感じ。

arenaの目的。利用中のオブジェクトはGCに回収されないよう保護する必要がありますが、Cのスタックはポータブルに参照できません。そこでC関数実行中に生成したオブジェクトは全部「生きている」とみなす事で保守的に保護します。 yukihiro_matz 2013-07-31 08:16:45
arenaの目的(2)。この保護のためにオブジェクトを記録しておく領域がarenaです。mrubyではデフォルトで100個のオブジェクトを登録できます。 yukihiro_matz 2013-07-31 08:19:02
save/restoreの仕事。現状arenaのサイズは固定なのでC関数実行中にあまり沢山オブジェクトを生成するとarenaが溢れます。そこで沢山オブジェクトを生成する前後にsave/restoreを置くことでarenaのサイズを復元し、溢れを回避します yukihiro_matz 2013-07-31 08:27:02
save/restoreの使い方。オブジェクトを生成する領域の前後をsave/restoreで囲みます。ただし、囲まれた範囲内のオブジェクトが保護されなくなりますから、どうしても必要なものはrestore後mrb_gc_protect()で改めて保護してください。 yukihiro_matz 2013-07-31 08:33:61

これを再度まとめてみよう。

mrubyをCで拡張していると「arena overflow error」という「謎のエラー」に悩まされることがある。 これはmrubyで「保守的GC」を実現している「GC arena」という領域があふれたというエラーだ。

GC(ガーベージコレクター)は、オブジェクトがまだ「生きている」、 つまり、プログラムのどこかから参照されているかどうかを判定する必要がある。 これはルートと呼ばれる参照から直接・間接に参照可能かどうかで判別する。 ルートには、ローカル変数・グローバル変数・定数などが含まれる。

プログラムの実行がmruby VMの中でおさまっている時にはこれは問題ない。 VMの持つルートはすべてGCからアクセス可能だからだ。

問題はCで記述された関数を実行中の時。 Cの変数から参照されたオブジェクトも「生きている」わけだが、 mrubyのGCはCの変数の内容を感知できないので、 C変数からしか参照されていないオブジェクトは死んでいると誤解してしまう。

まだ生きているオブジェクトを回収してしまうのは、GCとしてもっともやってはいけないバグだ。

CRubyでは、Cのスタック領域を無理やりスキャンすることで、 Cの変数をルートとしてチェックしている。 もちろん、Cのスタックを単なるメモリ領域としてアクセスするわけだから、 それが整数を意味する値なのか、ポインタ値を意味する値なのか判別することはできない。 しかし、まあ、そこは「ポインタのように見える値は安全側に倒してポインタだと思って処理する」という 方針で処理している。この「安全側に倒す」というポリシーのことを「保守的」と呼ぶ。

され、このようなCRubyの「保守的GC」にはいくつか問題がある。

その最大のものは「移植性のある方法でスタック領域にアクセスする方法がない」ということだ。 つまり、移植性の高さを実現しようとするmrubyのような処理系では使えないってこと。

そこで、mrubyは別の方法で「保守的GC」を実現した。

問題なのは、C関数実行中に生成されたオブジェクトで、 Rubyの世界から参照されてないオブジェクトのうち、 C変数からは参照されているのでまだゴミ扱いしてはいけないものが存在する、 ということだ。

既に述べたようにCRubyは、Cスタックをスキャンしてゴミのように見えるがゴミでないものを保護している。

しかし、その方法が使えないmrubyは、より保守的なポリシーを採用した。 つまり、C関数実行中に生成されたオブジェクトは、極端に安全側に倒して、いっそ全部生きているとみなせば、 少なくともゴミでないものを回収してしまう問題は回避できるんじゃないかと。

この結果、本当はゴミであるものを回収できないので、若干効率が下がることになるが、 移植性が高いまま、保守的なGCを実現できることになる。 CRubyで時々発生する「最適化で参照が削除されてゴミでないのにGCされた」問題とも無縁になる。

このポリシーで、「C関数実行中に生成されたオブジェクト」を登録しておくテーブルが 「GC arena」である。arenaはスタック状になっていて、 C関数の実行が終わるとその間に登録されたオブジェクトはポップされる。

原則としてはこれだけで、普通の場合は、これでめでたしめでたしなのだが、 GC arenaの存在は別の問題を引き起こすことがある。 これが前述した「arena overflow error」だ。

メモリが少ない環境でも動作することを考慮したmrubyはarenaのサイズを固定長にしており、 しかも、そのサイズはデフォルトで100とかなり小さめに設定されている。

実は当初はサイズ1000とかちょっと大きめにしていたのだが、 このテーブルサイズが厳しい環境があったのと、 後述するようなテクニックを使い、適切にarenaを管理すれば100でも普通に動くので、 現状は100にしている。

その結果、C関数の実行中に数多くのオブジェクトを生成すると、 arenaがあふれることになる。

その対策に用いるのが、表題のmrb_gc_arena_save()とmrb_gc_arena_restore()というふたつの関数である。

int mrb_gc_arena_save(mrb)はGC arenaの現在のスタック位置を返し、 void mrb_gc_arena_restore(mrb, idx)はarenaのスタック位置を保存された位置に戻す。

int arena_idx = mrb_gc_arena_save(mrb);

...なんかオブジェクトを作る処理...
mrb_gc_arena_restore(mrb, arena_idx);

というような使い方をする。

もともとのC関数の実行は、このようにsave/restoreに囲まれているのだが、 一時的にオブジェクトを作り、その後は不要になる領域を 明示的にsave/restoreを囲むことにより、arena overflowを避けるわけだ。

とはいうものの、具体例を見ないとわからないケースもあるだろう。 ここでは、Array#inspectのソースを見てみよう。

static mrb_value
inspect_ary(mrb_state *mrb, mrb_value ary, mrb_value list)
{
  mrb_int i;
  mrb_value s, arystr;
  char head[] = { '[' };
  char sep[] = { ',', ' ' };
  char tail[] = { ']' };

  /* check recursive */
  for(i=0; i<RARRAY_LEN(list); i++) {
    if (mrb_obj_equal(mrb, ary, RARRAY_PTR(list)[i])) {
      return mrb_str_new(mrb, "[...]", 5);
    }
  }

  mrb_ary_push(mrb, list, ary);

  arystr = mrb_str_buf_new(mrb, 64);
  mrb_str_buf_cat(mrb, arystr, head, sizeof(head));

  for(i=0; i<RARRAY_LEN(ary); i++) {
    int ai = mrb_gc_arena_save(mrb);

    if (i > 0) {
      mrb_str_buf_cat(mrb, arystr, sep, sizeof(sep));
    }
    if (mrb_array_p(RARRAY_PTR(ary)[i])) {
      s = inspect_ary(mrb, RARRAY_PTR(ary)[i], list);
    }
    else {
      s = mrb_inspect(mrb, RARRAY_PTR(ary)[i]);
    }
    mrb_str_buf_cat(mrb, arystr, RSTRING_PTR(s), RSTRING_LEN(s));
    mrb_gc_arena_restore(mrb, ai);
  }

  mrb_str_buf_cat(mrb, arystr, tail, sizeof(tail));
  mrb_ary_pop(mrb, list);

  return arystr;
}

実際のコードをそのまま引用してきたので、若干複雑になっているが、 Array#inspectの処理の本質は、 配列の各要素をinspectメソッドを用いて文字列化した上で、 それらを結合して配列全体のinspect表現を作ることにある。

全体のinspect表現の文字列を作ってしまえば、 処理途中に生成した各要素の文字列はもはや不要になる。 ということは、GC arenaにこれらのオブジェクトを登録しておく必要もない、ということだ。

そこで、ary_inspect()関数では、

  • mrb_gc_arena_save()でインデックスを保存
  • 要素のinspect表現文字列を取得
  • 生成中の配列inspect表現文字列に結合
  • mrb_gc_arena_restore()でインデックスを復旧

という手順により、arena領域の消費を抑えている。

ここで注意すべき点は、最終結果となる配列inspect表現となる文字列は、 mrb_gc_arena_save()の呼び出しよりも前に生成していることである。 こうしないと、必要なオブジェクトがGCで回収されてしまうことになる。

処理のパターンとしては、さまざまな一時オブジェクトを生成した上で、 そのうちの一部だけを参照し続けるというケースも考えられる。 このようなケースでは、ary_inspect()のように既存のオブジェクトに結合するような手は 使えないので、mrb_gc_arena_restore()の呼び出しの後に mrb_gc_protect(mrb, obj)を呼び出して、そのオブジェクトをarenaに再登録する必要がある。 ただし、mrb_gc_protect()は注意して用いないと、これ自身がarena overflow errorの原因になることがあるので 注意するように。

などということを、Twitterだけで説明するのは現実的じゃないよなあ。

追記

あ、そうそう。

このmrubyのAPIには、改善が必要だなと思ってる点があって、 その最大のものは、トップレベルでmrb_funcall()を呼ぶと GC arenaに戻り値が登録されるのでそのうちarena overflow errorになることだ。

戻り値を使わないmrb_funcall()のようなものを用意すればいいんだと思うんだけど。 いい名前が思いつかないんだよなあ。

*1  tDiaryにTwitterの発言を引用するプラグインが欲しいなあ

本日のツッコミ(全1件) [ツッコミを入れる]

_ おんがえし [つい最近そのmrb_funcall()の問題ではまってarena_saveとarena_restoreで囲んで対処し..]

[]

2013-06-12 「ちょっと待った!小中学校でのプログラミング教育」 [長年日記]

先日、Webronza というところに寄稿したのだが、有料登録しないと後半が読めなくなっていた。で、交渉して公開許可を頂いたので、ここで全文掲載。

「ちょっと待った!小中学校でのプログラミング教育」

現代社会はもはやコンピュータがなければ成り立ちません。そして、コンピュータは誰かが作ってソフトウェアがなければ、まったく役に立ちません。コンピュータは自発的に仕事をしてくれないどころか、誰か人間がソフトウェアという形でどのように仕事をすれば良いのか教えてやらなければ、なんの働きもできないのです。コンピュータが社会に役に立っているのは、ソフトウェアがあるからです。

どんなに賢いように感じられるコンピュータでも、自らソフトウェアを開発することはできません。コンピュータは単純な計算をものすごく速く行うことができますし、それを積み重ねることで人間を越える能力を備えていますが、その一方で、なにか新しいことを創りだすなどの創造的な活動は苦手です。はっきりいうとまったくダメだと言ってもいいでしょう。当面の間は人間がソフトウェアを作って、コンピュータに仕事を教えてやるしかないのです。

社会におけるコンピュータの重要性は明らかで、そのコンピュータがソフトウェアがなければ役に立たず、そのソフトウェアは人間にしか作れないとなれば、ソフトウェアを開発する人間こそが真に重要だということになります。しかし、現状、誰でもがソフトウェアを開発することができない以上、ソフトウェアを開発する人、プログラマを養成することは急務です。とは言うものの、どのような教育を行えば、優秀なプログラマを育成できるのかについて誰でもが合意できる方法はまだ見つかっていないようです。

最近、注目されているのが若い人たち、特に小学生や中学生へのプログラミング教育です。確かに優秀なプログラマは若い頃からその才能を発揮している人が多いようです。また、プログラミング能力はあまり年齢に関係ないようで、天才と呼ばれる小学生プログラマがいると思えば、70歳をはるかに超えて現役で活躍する方もいらっしゃいます。

そこで、若いプログラマを育てるために、小学校や中学校での情報処理の教育やプログラミング教育に力を入れようという動きもあるようです。しかし、自分自身のプログラマとしての経験から考えると、これにはなかなか困難がつきまとうように思えます。第一の課題は「誰が教えるか」という点です。学校をプログラミング教育の現場にするためには、当然のことながらプログラミングを教える教師が必要です。しかし、現在の小学校・中学校の教員でプログラミングの能力を持つ人はごく少数でしょう。もちろん、教科書通りに教えることができる人は短期間で用意できるかもしれませんが、それでは子供たちにプログラミングに前向きな気持ちを伝えることは困難でしょう。中学生時代にプログラミングをはじめた私自身も含めて、若い頃からプログラミングに「はまった」人たちは、結局、コンピュータを使いこなすのが楽しいからこの道に進んだようなもので、教科書に書いてあるから、あるいは学校の授業だからという理由でプログラミングをはじめた人など見たことがありません。プログラミングを教えるというのであれば、少なくとも教える人はプログラミングの楽しさを自覚している人でなければ成果をあげられないと思いますし、そのような人をそれぞれの学校に配備するのは大変な困難ではないかと思います。

第二の課題は「どのように評価するか」ということです。学校の授業であるということは、なんらかの評価をする必要があるわけですが、これがまた困難です。まず、プログラミングの能力は、創造性をともなうという点である種芸術に似ています。そういう点では美術の授業に似ているのですが、問題はプログラミングの場合、人によっては非常に短期間で上達するため、小学生であってもプロを越える作品を完成させることがたびたびあることです。人によって出来栄えが10倍、100倍あるいは1000倍も違うようなものを学校の成績としてどのように評価したらよいのか途方にくれます。

第三の課題は「なにを教えるか」ですが、この点は最初のふたつの課題に比べればなきに等しいものです。

では、学校教育はプログラマ養成にふさわしくないのであれば、いったいどうすれば未来を担うプログラマを養成することができるでしょうか。

正しい答えは私自身も持っていないのですが、私の知っている優秀なプログラマのほとんどが自学自習でプログラミング能力を身につけている現実を考えると、あるいはプログラマとは、養成されるものではなく、発見されるものなのかもしれません。

ある調査によれば、大学におけるプログラミング教育の受講者の内6割程度はプログラミングの基本的な部分の理解に困難を感じ、それは他の学科の成績に必ずしも相関しなかったのだそうです。だとすると、世の中にはプログラミングに向いた性格の人がいて、成績その他では区別することができないことを意味します。であるならば、少しでもたくさんに人にプログラミングに触れる機会を与え、そしてそれに興味を持てた人、才能の片鱗を見せた人にはより豊かな機会を与えるようなプロジェクトを総合的に設計することで、未来のプログラマを「発掘」できるのかもしれません。そして、そのような才能あふれる人たちに適切な待遇を与えることが、このIT社会の競争力を強める最大の方策なのかもしれません。

本日のツッコミ(全21件) [ツッコミを入れる]

Before...

_ 大学生 [僕の高校では、特別なカリキュラムが組まれていて、ある日2日連続で、すごいプログラマーの人が来て講師をしてくださり、そ..]

_ pmint [授業外で活用できる、普段でも(アプリの利用で)触れる、アートとしてでなくても評価できるなどの点から、英語や美術よりも..]

_ 宮松利博 [ゲームばかりして、なかなか勉強しない小学生の甥に、ゲームを使う側から、作る側になってみては?とパソコンと一緒に一冊の..]

_ (´ε`;)ウーン… [いいことだとは思うけど、 例えばゲームプログラミングであれば今は中間ライブラリなしに本格的なものは作れないし、そう..]

_ 千代子 [MatzさんやIT企業の人からみると、もっと優秀なプログラマは必要だ!というのはわかりますが、3児の親としての立場か..]

_ (´ε`;)ウーン… [あ、でも プログラ授業に反対意見ってわけじゃないです。 どうせ今の最低な学校教育なるものが国を滅ぼすのは時間の問題..]

_ 千代子 [2回目です。上の投稿は脱字がありました。「もっと大事で優先させたいことがあるのが本音です」に訂正します。小学校での情..]

_ 参考に [>私は元々プログラミング教育が前提にしている「教育によって才能のない人が優秀なプログラマになることができる」という仮..]

_ (・(ェ)・) [>第一の課題は「誰が教えるか」という点です。学校をプログラミング教育の現場にするためには、当然のことながらプログラミ..]

_ Tori [ものづくりの点では別に単一のプログラミング言語による習得は重要ではないと思います。特に子供の頃にC言語を覚えても創造..]

本日のTrackBacks(全1件) []

_ GUNMA GIS GEEK:プログラミング教育はプログラマーの育成を目的としなくていい ちょっと待った!小中学校でのプログラミング教育 小中学校での..


2011-09-29 [長年日記]

_ RubyConf 2011 New Orleans

一年ぶりの更新か。「年刊Matzにっき」だな。

今年もニューオーリンズで開催されたRubyConf。同じ都市で二度開催は初めて。

で、しょっぱなが私のキーノート。

まあ、あんまり語ることはないので。スライドを見てもらおうか。

こんな感じ。

角谷さんオススメのspeakerdeck.comも使ってみた。

[]

2010-11-14 [長年日記]

_ [Ruby] RubyConf 2010 キーノート(3)

で、最後に「Diversity(多様性)」である。

初日のDave Thomasのキーノートでも3つの重要なこととして、 Diversifyをあげていた。多様性は重要なのである。

とはいえ、多様性はいいことばかりでもない。 Rubyにおける多様性といえば、昨今数々登場している別実装である。

  • CRuby (1.9, 1.8)
  • JRuby
  • Rubinius
  • IronRuby
  • MacRuby
  • MagLev

などなど、多くのRuby実装がある。これら以外にも「Rubyっぽい言語」まで含めると 本当にいくつあるのか見当もつかない。

昔はPythonの人たちに「Ruby(とPerl)は複雑すぎて、別実装は登場しそうにない。 Pythonを見てみろ、CPythonとJytonとIronPythonがある」などと言われたものだが、 今や別実装の数ではRubyの方がしのいでいる。Pythonの方もPyPyとか新しいものも登場してるが。

が、一方、このような多様性にはコストがかかる。 まあ、プラットフォームの違うJRubyはおいておくとしても、 CRubyとRubiniusとMacRubyで分散しているリソースを集約すれば、 もっと早く言語(実装)が進歩するような気もしないでもない。

しかし、オープンソースプロジェクトでは結局はそれぞれの参加者がやりたいように関わって モチベーションを維持することの方がはるかに重要だ。

多様性は善で、コストは必要経費であるというのが私の認識である。

さて、多様性は善であるので、さらにそれを豊かにするために 私自ら新たな処理系を送り込もうと思う。

それは RiteVM であり、組み込みなど小規模なデバイス向けをターゲットとした処理系である。

現在のRubyは元々Unixをベースにして開発されたものであり、 UnixやPOSIX APIを提供しないような小さなデバイスや、 アプリケーションへの組み込みなどはあまり重視されてこなかった。

しかし、一方、組み込み分野などではデバイス性能の向上で ソフトウェアの比重が高まりつつあり、 実行速度やリアルタイム性がそれほど要求されない分野で Rubyのような「高級」な言語を使いたいという要求はそれなりにあるようだ。

そこで、以下のような処理系を新規に開発する

  • 小規模なRuby言語処理系
  • 機能はほぼRuby標準規格を満たす最小限。 さらにファイルI/Oなどは取り除く(後で追加可能)
  • 実装はLuaを意識
  • VM構造体を提供。グローバル変数を使わない
  • 機能はコンポーネントとして提供。必要に応じて外せる。 たとえばコンパイラを外してevalもなし、などが実現できる
  • ターゲットの要求に合わせてコンパイル時にさまざまに設定可能。 たとえば浮動小数点数をdoubleにするかfloatにするか、 Fixnumをintにするか、longにするか、long longにするか、など。 逆にいうと「どこでも同じように動く」は追求しない
  • 浮動小数点数はimmediate(shootout対策w)。
  • VMは32ビットワード命令、レジスタベース。命令セットもLuaに類似。
  • GCはレイテンシを重視。インクリメンタルアルゴリズムを採用。 世代別についても検討したい

このVM開発のプロジェクトコードネームは Rite と称することにする。 RiteVMの開発は、経済産業省 平成22年度「地域イノベーション創出研究開発事業」の一環として行われる。

これにより、たとえば

  • ゲームの組み込みスクリプト
  • デジタル家電のソフトウェア開発
  • 組み込み機器やロボットの非リアルタイム制御

などにRuby(のサブセット)が使えるようにする。

もちろん、今すぐにそうなるとは思っていないが、 今から準備すれば数年後には現実にできると考えている(ビジネス上の成功は別だけど)。

と、ぶちあげてしまったので、もう後に引けなくなったな。

FAQ

いつ Rite が使えるようになるの?
わかりません。が、上述の通り、経済産業省の事業なので事業が終了する2011年度末には なんらかの成果をあげないと、いろいろまずいことに...。
RiteVMはオープンソースになるの?
はい。MITライセンスを考えています。ただし、今回(とその周辺)の開発で ビジネスモデルを確立する必要があるので、あるいはGPL+商用ライセンスの MySQLモデルになるかもしれません。 いずれにせよ、オープンソースになることは期待して良いでしょう。
RiteVMが登場したらCRubyはお蔵入り?
そんなことはありません。Riteは分野限定の小規模実装ですから、 フル機能実装であるCRubyの代替にはならないでしょう。
C APIはどうなるの?
今までのCRubyのAPIとは異なるものになります。CRubyのAPIは非常に使いやすいけれども 組み込みにはあまり向かないからです。技術的には不可能ではなさそうですが、 互換レイヤーを導入する予定は当面ありません。
RiteVMはM17Nを提供しますか?
いいえ、コンパイル時にASCIIかUTF-8を選択してください。 エンコード変換機能も(標準では)提供しません。
native threadをサポートしますか?
いいえ、RiteVMそのものはスレッドをサポートしません。 native threadを活用したい時には各スレッドにVMを割り当ててください。 fiberはVMで提供するかもしれませんが、予定は未定です。
RiteVMはYARV/JRuby/Rubiniusより高い性能が出ますか?
たぶんそんなに性能は出ません。ただし、Floatの即値化とかのおかげで いくつかのベンチマークでは良い性能がでるかもしれません。
RiteVMの開発に貢献できますか?
オープンソース化されるまで待ってください。 githubで公開されると思います。gitの勉強しないとな
Riteって聞いたことあるんだけど
2003年のRubyConfキーノートでRuby 2.0の実装コードネームとして提案した名称です。 結局、新しいVMはYARVが採用されたわけですが、まさかこんな形で復活するとは。
まつもとさんはCRubyの開発から引退するんですか?
今でも十分貢献できてないんですが、引退するつもりはありません。 CRubyはRubyの第一実装であり続けますし、 私もRubyの設計者であり、コミュニティーのリーダーであり続けます。
本日のツッコミ(全5件) [ツッコミを入れる]

_ ささだ [RiteVM を (C)Ruby 2.0 のベースにしたほうが、色々幸せになれそうな気がします。性能とかも。]

_ とりまん [ゲームに組み込むならバインダー周りの整備も期待したいです。]

_ まつもと [バインダーってなんでしょう? swigとかtoluaのようなもの?]

_ morita [たぶんそうでしょうね。< バインダ IDL をつかわずテンプレートでちょこっと細工すると C++ のネイティブメソッ..]

_ yachi [組込み、期待してます!スクリプトの再利用、機器間移動、クロス開発などが容易なようにプロファイルみたいな仕組みもできる..]

[]

追記

track feed Matzにっき Creative Commons License This work is licensed under a Creative Commons License.