OmniAICreator/Qiita-1.07M huggingface dataset:
【Day30】積み上げ日記

##予定
■スキプラさんnote①
■WEBサービスができるまで（マコなり社長動画）

##完了
■WEBサービスができるまで（マコなり社長動画）

##学習時間
３h

##学習ポイント
■DNSからIPアドレスを取得して調べることができる。なので、WEBサイト公開にはDNSに登録しないといけない？
■サイト構築する時は、ノート上で最初に箱を作って分けて頭の中を整理しておく。

##疑問点
今回は復習ポイントがほとんどなのでなし。


##計画通り進んだか？
進まなかった。ノートに構成を書き下ろすのに時間を使いすぎた。だが、これを怠るとあとでコーディングの時に混乱するし、今後のマークアップを進めていく上でもこの整理法は必ず活きてくるはず！
NiFi | クラスタの1ノードがDisconnectedになる

# NiFiクラスタの1ノードがDisconnectedになる
NiFiを触っていたら、クラスタのある１ノードだけがどうしても同期ができず、
しまいには起動ができなくなりました。

## エラー
`/var/log/nifi`配下のログをみたところ以下のエラーがありました。

```
2020-03-16 14:47:34,377 ERROR org.apache.nifi.cluster.coordination.node.NodeClusterCoordinator:
 Event Reported for g08-wo01.internal.cloudapp.net:8080 -- Node disconnected from cluster due to
 org.apache.nifi.controller.UninheritableFlowException: Failed to connect node to cluster because
 local flow is different than cluster flow.
```

## わかったこと
NiFiのフロー用のXMLファイルに各ノードで差分が出てしまったのが原因。
確かに、あるノードAがClusterに参加して、"3/3 connected"などになる前に、
フローをいじってしまった気がする。

## 解決策
```
/var/lib/nifi/flow.xml.gz
```
のファイルを、同期ができている1つのノードからコピーして、
影響ノードのディレクトリに再配置するだけでOKでした。

# 参考情報
[[NIFI 1.3.0] : Unable to rejoint again the cluster](https://community.cloudera.com/t5/Support-Questions/NIFI-1-3-0-Unable-to-rejoint-again-the-cluster/td-p/214527)
php artisan ui vue --authコマンドの恐怖

とある日僕はlaravelを使って作った自作アプリに、ログイン機能をつけようと思いついた。
よしよし、公式ドキュメントによると、このコード一発でログイン機能ができるらしい。。
チャカチャカ、ぽん！
php artisan ui vue --auth

ブイーーん、種ドドドドー
laravelは唸りをあげ、ログイン機能、ユーザー登録機能を一瞬で作り上げ、同時に、resoureces/以下に書いていた僕のコードも見事に書き換えてしまった。
何してくれんだ、馬鹿野郎！

laravelは言った、私は規則に従ったまでです。
何、規則だと！と、手渡されたドキュメントをよく読むと、(小さく）「このコマンドは新しくインストールしたアプリケーションでのみ実行すべきで、・・・」と書いてある。
いや、もっと早く言えよ。
僕は、laravelランドに暮れる夕日を眺めながら、吐息をついたのだった。
【GAS】clasp + TypeScript をV8ランタイムに対応させて最新のES構文を利用する

## 概要
GAS でV8ランタイムが利用できるようになりました。
[V8 Runtime Overview  |  Apps Script  |  Google Developers](https://developers.google.com/apps-script/guides/v8-runtime)

これによりES2019で追加された関数(`flatMap`, `trimStart/trimEnd` など)が利用できます。
参考: [JavaScriptの ES2019で追加された新機能まとめ - Qiita](https://qiita.com/tonkotsuboy_com/items/07f8ef98abf89250b90c)

## clasp
[Command Line Interface using clasp](https://developers.google.com/apps-script/guides/clasp)
> clasp is an open-source tool, separate from the Apps Script platform, that lets you develop and manage Apps Script projects from your terminal rather than the Apps Script editor

ざっくりいうとGASをブラウザ上ではなくローカル開発するための公式ツール

### TypeScript でGASを書く
https://github.com/google/clasp/blob/master/docs/typescript.md
こちらに従ってセットアップすれば TypeScript で開発できるようになります。

## V8ランタイムに対応する
TypeScript で作成したプロジェクトで最新のES構文を利用できるようにします。
[clasp のV8対応のプルリク](https://github.com/google/clasp/pull/739) を参考に変更します。

### ターゲットを変更
```tsconfig.json
{
  "compilerOptions": {
    "target": "ES2019"
  }
}
```

### GASランタイムをV8に変更
```appsscript.json
{
  "runtimeVersion": "V8"
}
```

## 結果
ES2019の構文が利用できるようになる

```main.ts
const threads = GmailApp.search("from:mail@example.com")
const messages: GoogleAppsScript.Gmail.GmailMessage[] = threads.flatMap(t => t.getMessages())
messages.forEach(m => {
  const body = m.getPlainBody()
  Logger.log(body.trimEnd())
})
```

## 参考
[r57ty7/toho-schedule-creator: TOHOシネマズの購入完了メールから自動で Google Calendar に登録するGAS](https://github.com/r57ty7/toho-schedule-creator/pull/1/files)
【Ruby on Rails】タグ検索機能を実装してみた

#はじめに
今回は前回追加した、タグ付機能を利用してタグ検索機能を追加します。
前回の記事（タグ付機能）
https://qiita.com/E6YOteYPzmFGfOD/items/bfffe8c3b31555acd51d

###作るもの
マイクロポストタグ付機能を利用したタグ検索機能。（題材は自分のポートフォリオです。）

###対象読者
railsチュートリアルに機能を追加したい等自分と同じ位のレベルの人を対象としています。

#作成の流れ
1.検索フォームの作成
2.コントローラーのアクション作成

#1.検索フォームの作成
今回は検索フォームをroot_path上に設けます。（自分のポートフォリオがマイクロポストの一覧をroot_path(static_pages/home)に設けているため）

```ruby:app/views/static_pages/home
<%= form_with url: root_path, method: :get, class: '自由に' do %>
  <%= select_tag :tag_id,
    options_from_collection_for_select(Tag.all, :id, :name, params[:tag_id]),
    {
      prompt: 'タグで絞り込み',
      class: ,'自由に'
      onchange: 'submit(this.form);'
    }%>
<% end %>
```
fomr_withを使って検索フォームを作ります。各指定している値を自分なりに説明します。

url: 検索した後に移動するページ。（getメソッド後の移動するページ）
method::get 　検索時はゲットメソッドを使用する。（root_urlにゲットアクションを起こすのでstatic_page_contorollerのhomeアクションに飛びます。
）
select_tag: フォームの中でセレクトタグを表示するためのメゾット
select_tag:オブジェクト名（tag_id）URLのクエリ（検索するとURLの？以降に表示されてます）
  options_from_collection_for_select(
第１引数：オブジェクトのリスト（Tag.all全件表示）
第2,3引数：取得したリストの表示。順番が大切でid,nameの順にすることによりタグnameを表示する。(idを基準に表示する。逆の順番にするとidの数字だけが表示される。）
第４引数：検索後に表示する値。params[:tag_id]とすることによりURLのクエリからidを取得して検索後もフォームにタグ名を表示します。（第２、第３の引数の値が重要です。）
）
{promt:は何も選択していないときに表示される値です。
onchange:submit(this.form)はJavaScriptを実行できるものでセレクトボックスが選択されたときにこの検索がスタートするようにしています。
}

続いてコントローラーです。

```ruby:app/controllers/static_pages_controller.rb
@microposts = params[:tag_id].present? ? Tag.find(params[:tag_id]).microposts : Micropost.all
※ページネーション等に渡してください
```
タグ検索が実行されるとparamsでURLのクエリ(tag_id)を取得してfindでテーブルの中を探し関連付けしているのでmicropostsで関連するマイクロポストを取得します。検索されていない場合は全てのマイクロポストを取得するようにしています。

#おまけ
URLのクエリとはURL上に表示されている？以降のやつです。
なんちゃら.com/?utf8=✓&tag_id=1
paramsメゾットではgetメゾット時にURLのクエリを取得できます！
※ログを見るとこんな記述もあります。
Parameters: {"utf8"=>"✓", "tag_id"=>"2"}


以上でタグ検索機能は完成となります。最後までお読みいただきありがとうございました。
アドバイス等いただけるととても喜びます。次はマイクロポストの検索機能を記事にしたいと思います。
ありがとうございました。
Lambdaプロキシ統合でmultipartのフォームデータをパースする

ファイル添付とかmultipartで送信されてくることがあるので、そのパース方法。
busboyというライブラリを次のように使うことで実現可能。

`event`はlambda関数の入力。

```
    if (event.headers['content-type'] && (event.headers['content-type'] as string).includes('multipart/form-data')) {
        console.log('IT IS MULTIPART');
        const input: CreateMeProfileInput = {};
        const busboy = new Busboy({
            headers: event.headers,
            defCharset: 'utf8'
        });
        return new Promise((resolve, reject) => {
            busboy.on('file', (fieldname: any, file: any, filename: any, encoding: any, mimetype: any) => {
                console.log('File [' + fieldname + ']: filename: ' + filename + ', encoding: ' + encoding + ', mimetype: ' + mimetype);
                file.on('data', function (data: any) {
                    util.inspect(data);
                    console.log(typeof data);
                    console.log('File [' + fieldname + '] got ' + data.length + ' bytes');
                });
                file.on('end', function () {
                    console.log('File [' + fieldname + '] Finished');
                });
            });
            busboy.on('field', function (fieldname: string, value: any, fieldnameTruncated: any, valTruncated: any, encoding: any, mimetype: any) {
                console.log(util.inspect(value));
                console.log(value.toString('utf8'));
                console.log('Field [' + fieldname + ']: value: ' + util.inspect(value) + ` encoding:${encoding}, valTruncated:${valTruncated}, mimetype:${mimetype}`);
            });
            busboy.on('finish',  () => {
                console.log('Done parsing form!');
                console.log(input);
                resolve(input);
            });
            // @ts-ignore
            busboy.on('error',  (err) => {
                console.log('busboy parse error');
                console.log(input);
                reject(err);
            });
            busboy.write(event.body); // 第二引数いらない
            busboy.end();
        });
    } 
```
Rails + jQuery + AjaxでCRUDのサンプルプロジェクト [Hello World]

React + JQuery(+Vanilla JS) + AjaxによるCRUD(作成/読み込み/更新/削除)のサンプルプロジェクトです。 ※Vanilla JSは純粋のJavaScriptです。
![jquery_crud_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/597258/6465f6de-c80e-2ff1-7ab4-acf8ebdc2e4b.png)

動作確認はChrome、FireFox、Microsoft Edge、IE11です。恐らくマックさんのブラウザでも動作するはずです。
## DEMO
<a href="https://www.petitmonte.com/rails-demo/jquery_crud">https://www.petitmonte.com/rails-demo/jquery_crud</a>

## ソース一式
<a href="https://github.com/TakeshiOkamoto/mpp_jquery_crud">https://github.com/TakeshiOkamoto/mpp_jquery_crud</a>

※学習用の為、ライセンスはパブリックドメイン

## 関連記事
<a href="https://qiita.com/petitmonte/items/e89a7c7df8cf1c5f3c24">Rails + React + AjaxでCRUDのサンプルプロジェクト [Hello World]</a>
<a href="https://qiita.com/petitmonte/items/0857ac8baf0d56187b7c">Rails + Vue.js + AjaxでCRUDのサンプルプロジェクト [Hello World]</a>
<a href="https://qiita.com/petitmonte/items/c8820525c832bb2e4664">Rails + jQuery + AjaxでCRUDのサンプルプロジェクト [Hello World]</a>
<a href="https://www.petitmonte.com/javascript/framework_comparison.html">React・Vue.js・JQueryで同じSPAを作成して比較してみた</a>
Minecraft modding 1.12.2で参考になるサイトまとめ

#導入
####intelij IDEAのプラグインを利用してコマンドを一切打たずに簡単に導入する方法
https://qiita.com/Hiroya_W/items/7ad9bad0387ef3688d1e
####動画で基本的なMOD製作が学べる(英語)
https://www.youtube.com/watch?v=rmWBP5ifDlw&list=PLDhiRTZ_vnoX4bx_BJccGV7MjpXUfVJSn
####ブロックの追加からTileEntitySpecialRenderまで、幅広く学べるサイト
https://shadowfacts.net/tutorials/forge-modding-112/
####サイトのコード
https://github.com/shadowfacts/TutorialMod
1.12.2では、setUnlocalizedNameをsetTranslationKeyにする、などの変更が必要です、またCreativeTabの追加はエラーが多いので、削除して、他のサイトをもとに作成するのがいいかもしれません。面倒な変更はありますが、非常におすすめのサイトなのでぜひチェックしてみてください。
#公開
Curse Forgeでの公開
https://qiita.com/C6H2Cl2/items/a972d6c25cee66b032c5
**プロジェクト作成はこちらのアドレスに変更されています。くれぐれもご注意ください。**
https://www.curseforge.com/project/create
ScratchでBrainfuckインタプリタを作っていたことを思い出した

#はじめに
さっきディレクトリを掃除してたら12月に作ったScratch3.0製Brainfuckインタプリタが出てきました。びっくりですよ。しかも履歴を見たところ作ったのは12月25日ですって、12月25日。クリスマス当日にScratchでBrainfuckインタプリタを作るというのは虚しさを通り越してシュールレアリスムの領域に到達しているでしょう。あまりにも無念すぎるので、供養ついでに解説します。

#仕様
- 対応命令は基本の八文字
- 制御文字はBSとLFとSPCだけ対応(後述)
- 入力は最初に入力した文字列を一文字ずつ読むタイプ
- 数値上限255

#入出力
ということでかなり最初の方に組んだ形跡がある入出力部から紹介していきましょう。
![あまりにも雑](http://u.cubeupload.com/gaqwgaqw/34706f.png)
出力先リストの名前とかいろいろ過去の自分に言いたいことはありますが、何より初期化が雑、あまりにも雑。その「入力読み文字数」とか「ソース何文字目」とかは入力フォームを出す前に初期化しろよ！！！！！

#処理纏め
次は定義「処理全般」……行う処理の定義をまとめたものです
![もうちょっとどうにか](http://u.cubeupload.com/gaqwgaqw/8991af.png)
ちょっと定義の分け方がおおざっぱすぎる気はしますが、さっきのものよりはマシです。ちなみにわざわざフラグを立てて処理しているプログラム終了条件ですが、**この後のプログラムに一切出てきません**。
なんでフラグ制にしたんですかね……？

#+-の処理
次は定義「+-処理」です。文字通りですね。
![脳味噌が±0](http://u.cubeupload.com/gaqwgaqw/515322.png)
配列上のポインタが指すところを増やしたり減らしたりしてます。
255超や0未満に数字が達してしまった場合、0や255に直しています。
地味にめんどくさいからって減算を加算ブロックでやってる。

#[]の処理
普通+-の次には<>が来ると思うんですが、なぜか「[]処理」の方が先に配置されてたのでこっちを先に解説します。(ちょっとした都合で画像を分割してます)
![](http://u.cubeupload.com/gaqwgaqw/da5919.png)
![](http://u.cubeupload.com/gaqwgaqw/bfb8e9.png)
それぞれ、「ポインタの指す値が0だった場合は対応する角括弧に飛ぶ」という機能を実装するため、「開いた[」/「閉じた]」をカウントして、両者の数が等しくなるまで飛ぶ方向に1マスずつ移動しています。

#<>の処理
ぶっちゃけ<>より><の方がかっこよくないですか？でも役割を考えると<>の方が正しいんですよね…
![](http://u.cubeupload.com/gaqwgaqw/52d55d.png)
ポインタ位置を動かしてるだけです。
何も格納されていない右端に到達しちゃったときは0を増設してます。逐次追加すれば番地の実数は1でも使う分には実質無限……！

#ASCIIリストについて
.の処理の解説の前にASCIIの話をします。
このプロジェクトでは前述の通りASCIIの制御文字はBSとLFとSPCだけ対応していますが、SPCはともかくBSとLFの入力はScratchの仕様上できません。
なので便宜上、BSは「ｂ」(全角のb)とLFは「ｅ」(全角のe)[^1]を代用文字として使用しています。SPCは直接半角スペースを入れてます。
ちなみにその他の表示できない制御文字には「あ」を使っており、なんだか気持ち悪いリストになっています。
![](http://u.cubeupload.com/gaqwgaqw/ASCII.png)

#.の処理
出力です。行数が多い
![](http://u.cubeupload.com/gaqwgaqw/b736d6.png)
「もし」を入れ子にしてるところとか汚いですね。
notにさらにelseをつけるあたりとかバカすぎてさすがに擁護しきれないですがそれはともかくコードの解説です。
BSは後ろの一文字を削除(でしたよね)なので、後ろの文字が改行の場合はそれを取り消し、通常文字の場合は削除しています。Scratchは文字列操作系が充実してないのでわざわざ「削除する文字以外を一から連結しなおす」という面倒な方法をとっています
LFは普通に改行ですね。

#,の処理
入力からの読み込み(そしてポインタの指す場所の置換)。
![](http://u.cubeupload.com/gaqwgaqw/12f8c1.png)
普通に頭から読み込んでます。特筆すべき点は特にありませんが、強いて言えば3.0になってから登場した「～中の～の場所」ブロックを使ってます。実質的にサーチなので普通に2.0でも実装できますけどね…

#総括
クリスマスは有意義に過ごそう

[^1]: なんでeなんですかね……ひょっとしてEnter？バカなの？
二次元配列の格納方法

こんちは！
今日はrails上で二次元配列の格納方法を記載します。


### 理由
この内容が容易に見当たらなかったため、他の方の助けになればと思います。

### 一次元配列の格納方法
イメージとしては、[1,2,3,4,5,6]
という風に格納したい場合、railsではコントローラーに以下のように記載するとできます。

```rails:tests_contoroller.rb
def idex
  @test = [] #配列の宣言
  
  6.times do |i = 0| #6回読み込ませる、そしてiには0を格納している。iは初期化式
    @test[i] = i + 1 #初期化式で宣言したiに１足した数字を各配列に代入している。
    i += 1　#iに１を足してはじめに戻る。何もしないままはじめに戻ると同じ配列[0]を六回繰り返すだけだから
  end
  # 配列[i]になぜ１を足さないかは、配列の初期値は[0]だから
```

### 二次元配列の格納方法
次は二次元配列です。
イメージとしては[[1,1],[2,1],[3,1]]
と格納したい場合は以下の通りになります。

```rails:tests_contoroller.rb
def idex
  @test = [] #配列の宣言
  
  3.times do |i = 0| #3回読み込ませる、そしてiには0を格納している。iは初期化式
    @test[i] = [i + 1,1] 
    i += 1　
  end
```
@test[i]　←の部分は、一緒です。
その配列の中に、さらに配列を入れるイメージです。
|1|1|
|2|1|
|3|1|

これを使った応用で、以下のようなコードが表示が実現できます。

```
<select name="exp_year" id="exp_year"><option value="">--</option>
<option value="2020">20</option>
<option value="2021">21</option>
<option value="2022">22</option>
<option value="2023">23</option>
<option value="2024">24</option>
<option value="2025">25</option>
<option value="2026">26</option>
<option value="2027">27</option>
<option value="2028">28</option>
<option value="2029">29</option>
<option value="2030">30</option></select>
```
HTML上表示したいものは、1つめの配列に格納されています。
valueの値は、2つめに格納したものがです。

格納例としては、以下の通り
|20|2020|
|21|2021|
|22|2022|
|23|2023|


これらは以下のコードをコントローラー側に入力すると、vew側で表示でます。

```rails:tests_controller.rb
  def index
    year = 2020
    @year = []
    11.times do |i = 0|
      @year[i] = [year - 2000,year]
      year += 1
      i += 1
    end
  end
```

vewには以下の一文追加してね。

```rails:tests/test.html.haml
= select_tag 'exp_year',options_for_select((@year),class: "exp_year"),prompt: "--"
```

追加したら以下のように見れるはずです。（CSSは適当に付けてみるとよいでしょう）
[![Screenshot from Gyazo](https://gyazo.com/9a55dac64b1d2a8ed0f55363e995dee4/raw)](https://gyazo.com/9a55dac64b1d2a8ed0f55363e995dee4)

以上です！
またこう言った、見当たらなかったものをあり次第、アップしていきます！

ほなねー。
初心者から始めるJava、継承

追記2020/3/16
クラス名のつけ方で間違いがあったことを、コメントで指摘いただいたので訂正。

#はじめに
この記事は備忘録である。
参考書レベルの内容だが、本記事に掲載するコードについては、
~~**間違えた**ものが中心となる。これは実際にコーディング中に間違えた部分を掲載し、自分で反省するために投稿するという目的によるもの。~~
また、後日にJavaSilver試験問題の勉強を兼ねて復習するため、深い部分の話はここでは触れない。

##環境
言語：Java11、JDK13.0.2
動作環境：Windows10

#クラスの拡張
今まで書いてきたクラスはどれも独立して書かれたものだったが、毎回メンバ（フィールドとメソッド）を設定する必要があった。`Cat`クラス程度ならば頑張れば作れるだろうが、膨大なメンバ（フィールドとメソッド）を持つクラスを毎回すべて書くのは現実的ではない。
Javaは、既存のクラスが持っているメンバをそのまま引き継ぎつつ、独自のクラスを作るための**クラスの拡張(extend)**機能がある。

```Java:extendedHousecat
class WildCat
{
  protected double weight;
  protected double height;
  protected String name;

  public static int sumCats = 0;

  public wildCat()
  {
    weight = 0.0;
    height = 0.0;
    sumCats++;
    System.out.println("ニャーゴ、猫をまた一匹見つけたよ。");
  }
 
  public WildCat(double we,double he)
  {
    weight = we;
    height = he;
    sumCats++;
    System.out.println("ニャーゴ、猫をまた一匹見つけたよ。");
    System.out.println("見つけた猫は、体重" + weight + "kg、身長" + height + "cmみたい。");
  }

  public void measureWeightHeight(double w,double h)
  {
    weight = w;
    height = h;

    System.out.println("この猫を計測してみました。");
    System.out.println("体重は" + weight + "kg、身長は" + height + "cmあります。");
  }

  public static void countCats()
  {
    System.out.println("全部で" + sumCats + "匹の猫を見つけたよ。");
  }
}

//ヤマネコ(Wildcat)のクラスをベースに、イエネコ(Housecat)のクラスを作ろう。

class HouseCat extends WildCat
{
  private String collorColor;
  private String nickname;

  public void callNickname(String s)
  {
    nickname = s;
    System.out.printlm("この猫に、新しく" + nickname + "ってニックネームを付けたよ。");
  }
}
```
ヤマネコ(`WildCat`)クラスを拡張して、イエネコ(`HouseCat,Cat`……色々呼び方はある)クラスを作った。このとき、`Wildcat`と`HouseCat`は親と子の関係になり、それぞれ`super class`と`sub class`になる。

##スーパーなのかサブなのか
`WildCat`クラスを拡張した`HouseCat`クラスには、親である`WildCat`クラスが持っていたメンバ（フィールドとメソッド）が引き継がれているので、

`HouseCat cat1 = new HouseCat();`
`cat1.measureWeightHeight(5.0,50.5);`

とすることで、体重5.0kgで身長50.5cmの`HouseCat`オブジェクトを生成できる。
もちろん、collorColor(首輪の色)とnickname(あだ名)フィールドも持っているし、
`public void callNickname()`メソッドであだ名をつけることもできる。

###あえて親のコンストラクタを使いたい
`HouseCat`クラスにはコンストラクタがないが、`sub class`でコンストラクタを用意しなかった場合、`super class`のコンストラクタのうち**引数のないコンストラクタ**が、`HouseCat`オブジェクトを生成したときに自動的に呼び出される。今回は`public WildCat()`の方だ。
だが例えば、`super(8.0,60.8)`としてコンストラクタ内で呼び出してやれば、8.0kg、60.8cmのイエネコとして呼び出されることになる。

##privateより内向的で、privateより社交的
`WildCat`クラスのフィールドがいつもと違うのに気が付いただろうか？（実はここまで書き進めてから直した）。`protected`は、「同じクラスか、子であるサブクラスからであればアクセスできる」という意味の修飾子になる。
サブクラスをどんどん作って発展させたいスーパークラスになると予想できるときは、`protected`にしておくと後から扱いやすいだろう。
アクセス制限としてはパッケージも控えているが、ここでは割愛。

#終わりに
継承後のサブクラスが持っていなければならないもの、スーパークラスのメンバがどこからまでのアクセスを認めているのか。こういった問題にまだ悩まされているので、ここの理解はまだまだ甘いのが現状。
以前扱った[Java11のリファレンス](https://docs.oracle.com/javase/jp/11/docs/api/index.html)も、少し覗いただけで`extends`がわちゃわちゃと出てきている。この家系図を理解したとき、本当のJavaが見えてくるのだろう、多分。

#参考
出来るだけ自分で変数や式を書いてコンパイルしているので、完全に引用する場合はその旨記述する。

[やさしいJava 第7版](http://mana.on.coocan.jp/yasaj.html)
[Java SE11 Silver 問題集](https://book.impress.co.jp/books/1118101186)（通称黒本）

[Java® Platform, Standard Edition & Java Development Kit
バージョン11 API仕様](https://docs.oracle.com/javase/jp/11/docs/api/index.html)
PythonでPowerPointの各ページを画像ファイルにする

トレーニング用の資料作るときに、僕だけがうれしい機能です。PowerPointのページ単位で画像ファイルに変換します。PowerPointを開いて、ファイル→エクスポート→ファイルの種類の変更を選ぶのと同じ事を、Pythonで自動化しました。

comを使ってPowerPointを操作し、ついでにファイル名がスライド1.PNGといろいろ嫌なので、slide1.pngに変換するようにしました。

読み込むPowerPointのファイル名と出力先をファイルの先頭で指定しています。当然、PowerPointがインストールされていないと動きません。試してみたければ、とりあえずtest.pptxのパワポファイルを用意すれば動くと思います。

```python
PPT_NAME = 'test.pptx'
OUT_DIR = 'images'
```

全ソース

```python

import os
import glob
from comtypes import client

PPT_NAME = 'test.pptx'
OUT_DIR = 'images'

def export_img(fname, odir):
    application = client.CreateObject("Powerpoint.Application")
    application.Visible = True
    current_folder = os.getcwd()

    presentation = application.Presentations.open(os.path.join(current_folder, fname))

    export_path = os.path.join(current_folder, odir)
    presentation.Export(export_path, FilterName="png")

    presentation.close()
    application.quit()


def rename_img(odir):
    file_list = glob.glob(os.path.join(odir, "*.PNG"))
    for fname in file_list:
        new_fname = fname.replace('スライド', 'slide').lower()
        os.rename(fname, new_fname)


if __name__ == '__main__':
    export_img(PPT_NAME, OUT_DIR)
    rename_img(OUT_DIR)
 ```
ざっくりdocker-composeでsinatraとredisを連動させてみよう


# 前回の記事 
[dockerについて](https://qiita.com/BinaryWoo/items/02aa2120376396b7faef)

# この記事で得られるもの(目的)
- docker-composeで二つのDocker Containerを繋がって起動させる方法

# この記事で扱わないこと
- Docker-composeの歴史

# Agenda
- 作りたいものの全体像
- ファイル構造
- 実行コマンド
- ざっくりした説明
- 呟き

# 作りたいものの全体像
SinatraサーバーContainerとRedis Containerを連動させて、Redisに保存されてるデーターを引っ張ってくるもの。

# ファイル構造
workspace
ㄴ app.rb
ㄴ Gemfile
ㄴ Dockerfile
ㄴ docker-compose.yml

##app.rb
```
#!/usr/bin/env ruby
#
require 'sinatra'
require 'redis'
require 'json'

r = Redis.new host: ENV["REDIS_HOST"], port:"6379"

get '/create_dummy_data' do
  {
    'test1': 'this is test 1',
    'test2': 'this is test 2',
    'test3': 'this is test 3',
    'test4': 'this is test 4'
  }.each do |key, value|
    r.set key, value 
  end

  'create successfully dummy data'
end

get '/fetch/:key' do
  data = r.get params[:key]
  return 'empty data' if data.nil?

  data
end
```

##Gemfile
```
source 'https://rubygems.org'

gem 'sinatra', '2.0.8'
gem "redis"
```

##Dockerfile
```
FROM ruby:2.6.5
MAINTAINER jinument@gmail.com

ENV WORKSPACE /app

ADD ./Gemfile* $WORKSPACE/
WORKDIR $WORKSPACE
RUN bundle install

ADD . $WORKSPACE
```

##docker-compose.yml
```
version: "3"
services:
  redis:
    image: redis
    ports:
      - "6379"
  web:
    build: .
    command: bundle exec ruby app.rb -o 0.0.0.0
    volumes:
      - .:/myapp
    ports:
      - "4567:4567"
    depends_on:
      - redis
    environment:
      - REDIS_HOST=redis
```

#コマンド
上のファイルを置いたDirectoryで以下のコマンドを実行する。

`docker-compose build`
→　docker-compose.ymlファイルの各servicesをbuildする。

`docker-compose up -d`
→buildされてるservicesたちを順に合わせて起動させる。
→　`-d`はdaemonモードで起動させるOption。

`docker-compose down`
→　起動されてるdocker-composeのservicesを停止させる。

#ざっくりした説明
上の`docker-compose.yml`ファイルを見ながら`docker-compose.yml`の基本構造を見てみよう。

`version`で`docker-compose.yml`のversionを指定する。

`services`の配下には実行される各Containerについての仕様が書いてある。
ここでは`redis`と`web`Containerを起動するつもりだ。

`redis`配下の`image`と`port`は**Dockerfile**のコマンドと同じ意味でどういうDockerイメージを使うかと開放するportは何番にするかについて書く。

`web`配下の`depends_on`はこの`docker-compose.yml`の内のContainerとの依存性を設定することで、これを指定することによって`web`から`redis`というHost名で`redis`Containerへのアクセスができることになる。


#呟き
- 大体`Dockerfile`のコマンドと意味が似っているので、dockerを理解していれば、そこまで嵌らないとおもう。
- 現状docker-composeの`links`は使われない。(docker offical documentから)
　→　代わりに`depends_on`を使おう。
【Rails】flashメソッド

#flashメソッド
ユーザーの登録成功や失敗をメッセージ形式で知らせてくれるメソッド。

##実行例

```controllers/users_controller.rb
  def create
    @user = User.new(user_params)
    if @user.save
      flash[:success] = "Welcome to the Sample App!"
      redirect_to @user
    else
      render 'new'
    end
  end
```
上記ではユーザーの登録に成功した時に、`flash[:success] = "Welcome to the Sample App!"`が実行され成功メッセージが表示されるようになっています。
しかしビューの方でも設定を行わないと表示されるようにはなりません。

```erb:app/views/layouts/application.html.erb

＜省略＞

  <body>
    <%= render 'layouts/header' %>
    <div class="container">
      <% flash.each do |message_type, message| %>
        <div class="alert alert-<%= message_type %>"><%= message %></div>
      <% end %>
      <%= yield %>
      <%= render 'layouts/footer' %>
      <%= debug(params) if Rails.env.development? %>
    </div>

＜省略＞
```
`<% flash.each do |message_type, message| %>`でflashの数だけメッセージが表示されるようになっております。

bootstrapを使用していると`<div class="alert alert-<%= message_type %>">`でメッセージの表示を変更されることができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/597913/b9f2aaaf-20cd-ad54-d0b2-4e38c6ec128e.png)
bootstrapには上記の性質があり、今回のコードで登録に成功すると`flash[:success]`が実行され` <div class="alert alert-<%= message_type %>">`の`<%= message_type %>`が`success`に変わり緑色のメッセージが表示されます。
【iOS】SDWebImageで画像のリサイズと角丸を実現






## URLから取得した画像を編集して表示したい

LINEやinstagramのDMように、アップロードしたオリジナル画像をリサイズして角丸をつけて表示する、画像送信機能付きのチャット画面のようなものを作りたいことがあります。

手動でもやれると思いますが、URLの画像への変換まで一気通貫でやりたいケースを想定し、ライブラリを使います。いくつかの代表的なものの中から
今回は[SDWebImage](https://github.com/SDWebImage/SDWebImage)を使います。

特に角丸の実装方法が、[SDWebImage](https://github.com/SDWebImage/SDWebImage)の公式ドキュメントからは見つかりにくかったので書いておきます。


## 前提条件

画像を表示するための基本的なしつらえ(tableViewのレイアウトやdelegateメソッドの用意、imageViewの用意など)は完了している

## tranformerを使って画像のリサイズと角丸実装

例えばこんな感じで書きます。




```swift:viewController.swift

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

let cell = // cellの生成は省略。imageViewが乗っかったcellを想定。

let url = // 省略。固定URLや、データベースなどから取得したURLを変数に代入。

// 画像のリサイズ。任意のサイズを設定。
let sizeTransformer = SDImageResizingTransformer(size: CGSize(width: 200, height: 200),scaleMode: .aspectFill)

// 角丸をつける。任意の数値や色を設定。
let roundCornerTransformer = SDImageRoundCornerTransformer(radius: 18.5, corners: .allCorners, borderWidth: 2.0, borderColor: UIColor.clear)

// 上記2つのtransformerをまとめて1つにする
let pipeLineTransformer = SDImagePipelineTransformer(transformers: [sizeTransformer, roundCornerTransformer])

cell.imageView.sd_setImage(with: url, placeholderImage: nil, context: [.imageTransformer: pipeLineTransformer])

}

```
公式の読み込みも大変だと思うのでご参考になれば幸いです。

## 最近の話

この前母親が週に2回だけママをやっているスナックに行きました。スナックって味があっていいですね。母の作るハイボールは濃くて美味しかったです。

今回初投稿でしたが、自分が苦しんだものを中心にまた書きたいと思います。
firebase functionsはregionを間違えてもCORSになる

# 発生したエラー
```js
Access to fetch at 'https://us-central1-twohundred-dcb3e.cloudfunctions.net/createMeetings' from origin 'https://twohundred-dcb3e.web.app' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: Redirect is not allowed for a preflight request.
```
```js
POST https://us-central1-twohundred-dcb3e.cloudfunctions.net/createMeetings net::ERR_FAILED
```
```js
Error: internal
    at new e (3b338370d3d4d0f079e3.js:2)
    at 3b338370d3d4d0f079e3.js:2
    at t.<anonymous> (3b338370d3d4d0f079e3.js:2)
    at 3b338370d3d4d0f079e3.js:2
    at Object.next (3b338370d3d4d0f079e3.js:2)
    at c (3b338370d3d4d0f079e3.js:2)
```

# やったこと
Nuxt+Vueでwebアプリを作るとき、firebase functionsをAPIとして利用した。
### API
functions/index.js

```js
exports.createMeetings = functions
  .region('asia-northeast1')
  .https.onCall(async (data, context) => {
    // 省略
    } catch (e) {
      console.error(new Error(e));
      return new functions.https.HttpsError('internal', e.message);
    }
  });
```
### クライアント
store/index.js

```js
async ADD_MEETING_URL({ commit }, { lunch }) {
    const store = firebase.firestore();
    // 正しくない
    // const functions = firebase.functions();
    // 正しい
    const functions = firebase.app().functions('asia-northeast1');
    const response = await functions.httpsCallable('createMeetings')(body);    
    await store
      .collection('Lunches')
      .doc(lunch.id)
      .set(
        {
          startURL,
          joinURL
        },
        { merge: true }
      );
  },
```

# エラー原因
- API側ではregionをnortheastに設定した
- にもかかわらずクライアント側でfunctionsのregionを指定してなかった
- デフォルトのus-centralにアクセスされてしまいCORSになった

公式ドキュメントにちゃんと注意書きされてた。。。
https://firebase.google.com/docs/functions/locations?hl=ja
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221630/4ac74497-a6eb-3f8a-b9e4-12263ccf0b3d.png)

# 勘違いポイント
「functions cors」とぐぐるとこういう記事が出てくる
https://qiita.com/qrusadorz/items/40234ac0b5c5c2315cad
> FirebaseのCloud Functionsには2つの関数があります。
1. functions.https.onCall
2. functions.https.onRequest
1はSDKが用意されているAndroid,iOS,Javascriptから呼び出されるタイプ。
https://firebase.google.com/docs/functions/callable?hl=ja
2はSDKがない場合、汎用のWebAPIとして作成するタイプ。
https://firebase.google.com/docs/functions/http-events?hl=ja
タイトルのCORSが~といわれるのは2のタイプで作成していて、レスポンスにCORSのためのヘッダーが設定されていないため。
1を利用した場合、その辺の面倒な部分は内部で処理して利用者が意識しなくていいようです。

あれ、でも自分は`onCall`を使ってるからCORSにはならないはず、、？

そうか、開発環境でlocalhostからアクセスしてるからか！と思いきや

```js
if (process.env.NODE_ENV === 'development') {
      functions.useFunctionsEmulator('http://localhost:5001');
    }
```
API側を上記のように修正してもエラーに変化なし。`onCall`は優秀だからlocalhostでもCORSにはならないはず

結局regionの違いに気づいたのはコンソールを見てた時
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221630/b455fbf6-b902-50bf-43aa-f5bbc6f6e3f6.png)
あれ、northeastに設定したはずなのにエラーはus-centralになってる、、？
Scala School/Basics 学習メモ

## はじめに

おそらくネット上にあるもっとも優れたScala教材の一つであろう[Scala School](https://twitter.github.io/scala_school/)について、
気になったことや試したことなどを**部分的**に忘備録としてメモしておこうと思います。
Scala Schoolは説明が非常にさっぱりしているのでその補足になればいいかなと思います。
Lessonsごとに記事は分けます。まずは最初のlessonであるbasicsから。


## 本編

### Functions

まずは関数定義の基本の形。

```scala:リスト1
def addOne(m: Int): Int = m + 1
```
戻り値の型(ふたつめの`: Int`の部分)は省略して書けるらしい。(リスト3など)


### Anonymous functions

```scala:リスト2
val a = (x: Int) => x + 1
a(5) //結果は6

val b = (x: Int, y: Int) => x + y //複数の引数ももちろんOK
b(5,6) //結果は11

val c = (x: Int)(y: Int) => x + y //NG. 匿名関数で引数を2つのかっこに分ける形はできない

val d = (x: Int) => (y: Int) => x + y //どうしても匿名でcurriedの形で書きたい場合はこうする
d(3)(7) //結果は10
```
scalaではパターンcのような引数を複数のかっこに分けて書く形をcurried functionとしています(後述)が、本来的にはdの書き方のほうがクロージャを利用した正統なcurried functionなのかもしれません。
匿名でないcurried functionについては後述。


### Partial applicaiton

```scala:リスト3
def adder(m: Int, n: Int) = m + n //まず定義(戻り値の型を省略しています)

val addTwoA = adder(2, _:Int) //これで部分適用できる
val addTwoB = adder(2, _)     //型指定を省略してもOK
val addTwoC = adder(_, 2)     //最後の引数だけでなくどの引数でもワイルドカードにできる

addTwoA(3) //結果は5
```


### Curried functions

```scala:リスト4
def multiply(m:Int)(n:Int): Int = m * n //関数を定義

multiply(2)(3) //もちろん同時に両方のパラメーターを入力してもOK. 結果は6

val timesTwoA = multiply(2) _      //OK
val timesTwoB = multiply(2)(_)     //OK
val timesTwoC = multiply _(2)      //これはエラー
val timewTwoD = multiply(_)(2)     //これもエラー
val timesTwoE = multiply(_:Int)(2) //型指定を入れればOK

timesTwoA(3) //結果は6
```

パターンDはmissing parameter typeというエラーになりますが理由がよくわかりません。
stackoverflowで聞いてみてはいますが、まだ回答なし。(わかる方いたらお願いします:bow_tone1:)


### Variable length arguments

```scala:リスト5
def capitalizeAll(args: String*) = {
  args.map { arg =>
    arg.capitalize
  }
}
```
個人的に少しひっかかったこのコード。実は引数は{}でも入力することができるようです。
実際

```scala
println{"asdf"}
```
これでも動きます。
式そのものも、オブジェクト・値としてあつかうのでこのようになっているのかもしれませんね。javaの習性であれ？と思いました。


### Classes

基本的なクラス定義の書き方。

```scala
class Calculator {
    val brand: String = "HP"
    def add(m: Int, n: Int): Int = m + n
}

val calc = new Calculator //Javaと同様にnewでインスタンスを作る
calc.add(1, 2) //メソッドの呼び出しも同じ感じ
calc.brand //フィールドへのアクセス. 文字列HPが返ってくる
```

### Constructor

クラス内のインスタンスメソッド定義の外側に書いたコードがコンストラクタとみなされるようです。


### Abstract Classes

Javaと同じような感じで抽象クラスもあります。`extends`するのも同じ感じ。

```scala
abstract class Shape {
    def getArea(): Int
}

class Circle(r: Int) extends Shape {
    def getArea(): Int = {r * r * 3}
}
```


### Traits

フィールドと振る舞いをまとめたインターフェース的なもの。
トレイトは複数extendsできるので、抽象クラスよりこっちを使うほうが基本的にはよいとのこと。

```scala
trait Car {
  val brand: String
}

trait Shiny {
  val shineRefraction: Int
}

class BMW extends Car with Shiny {
  val brand = "BMW"
  val shineRefraction = 12
}
```

scala schoolは残念ながらscala3には対応していないようですが、
scala3では以下のように`with`を使わずシンプルにカンマつなぎで複数extendsができる!


```scala
class BMW extends Car, Shiny {
  val brand = "BMW"
  val shineRefraction = 12
}
```


### Types

型パラメーターは`[]`で囲むらしい。
Rustで書かれたゲームエンジンamethyst勉強記 - 番外編

### はじめに

　これは、AmethystというRust製のゲームエンジンの`v0.12.0`から`v0.14.0`への変化についてメモ的に書かれています。というのもわたしは以前Amethystについての記事を書いていましたが、リアルが多忙になった故次第に更新をやめてしまいました。最近は時間ができたため、またAmethystのバージョンが新しくなっていたこともあり最初から書いてみようと思ったのですが、ちょいちょい躓く部分があったので、同じような境遇の方向けに書いていこうと思った次第です。メモ的というのは、いつかちゃんとした記事としてまとめられたらいいなぁ...という願望です。随時更新していくかもです。

## 1. `Cargo.lock`をいじる

現在`amethyst`クレートを使用したプロジェクトをビルドする際、`amethyst`が依存しているクレートの一つに`quote`というものがあり、これのバージョン互換性に因る次のようなエラーが発生します（※2020/03/16時点）。

```sh
error[E0433]: failed to resolve: could not find `__rt` in `quote`
   --> /~~~/.cargo/registry/src/github.com-XXXXX/err-derive-0.1.6/src/lib.rs:145:63
    |
145 | fn display_body(s: &synstructure::Structure) -> Option<quote::__rt::TokenStream> {
    |                                                               ^^^^ could not find `__rt` in `quote`

error: aborting due to previous error

For more information about this error, try `rustc --explain E0433`.
error: could not compile `err-derive`.
warning: build failed, waiting for other jobs to finish...
```

[こちら](https://stackoverflow.com/questions/60576277/rust-amethyst-error-e0433-failed-to-resolve-could-not-find-rt-in-qu)にてすでに議論されており、以下のような調査結果が出ています。

> `err-derive-0.1.6`で`quote-1.0.2`を依存関係として使用していますが、`Cargo.toml`で次のように宣言されているためにこのエラーが発生しました。
>> [dependencies.quote]
version = "1.0.2"

> これは、最新のマイナーアップデートを使用することを意味するため、`quote-1.0.3`がリリースされた場合そちらを使用します。
> ここでの問題は、`quote-1.0.3`が`quote-1.0.2`に由来する後方互換性を壊しているということです。

これを回避するために、一度ビルドを失敗させた後で`Cargo.lock`の依存および依存先が`quote-1.0.3`となっているもののバージョンを全て`1.0.2`に書き換えました。これをした後は`cargo update`しないように注意。

## 2. ronファイルのフォーマット変わりました？

以前の記事にてronファイルの書き方の説明をしました（→[こちら](https://qiita.com/9laceef/items/380ac0944199de7aad8e#ron%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB)）が、`v0.14.0`で使用する場合以前の書き方では実行時にエラーが発生します。

### `v0.12.0`

```ron:display_config.ron
(
  title: "amethyst: 01_create_window",
  dimensions: Some((500, 500)),
)
```

### `v0.14.0`

```ron:display_config.ron
DisplayConfig (
  title: "amethyst: 01_create_window",
  dimensions: Some((500, 500)),
)
```

はい。変換先の構造体の型の名前を省略できません。これはAmethyst側の変更ではなくおそらく`ron`クレートの仕様変更です。省略できないのは一番上の構造体の型名だけ（上記の場合`DisplayConfig`）で、それ以外は省略可です。`ron`クレートのGitHubの`README.md`ではOptionalと書かれていますがおそらく修正漏れでしょう。

ちなみにAmethystのサンプルプロジェクトでは`/*! ~~~ */`で囲まれた部分がありますが、これは必須ではなく省略可能です。
IAMロールとEC2でcronからAWS CLIを実行

IAMロールをアタッチしたEC2で、cronからシェルスクリプト実行でハマった話。

# 環境
+ RHEL7.7
+ aws cli/1.18.8
+ IAMロール（S3アップロード権限有）

# やりたいこと
cronからS3アップロード処理を記載したシェルスクリプトを実行し、EC2にあるデータをS3にアップロードしたい。

# エラー内容
EC2にSSHでログインし手動でシェルスクリプトを実行可能だが
cronから実行すると「aws コマンドが見つかりません」でエラーとなる。

# 解決方法
+ whichコマンドでAWS CLIのフルパスを確認し、コマンドはフルパスで記載する。
+ シェルスクリプトの冒頭の呼び出しシェルに「-l」オプションを追加

```sh:sample.sh
#!/bin/bash -l

/usr/local/bin/aws s3 cp ローカルファイルパス　S3バケット
```

# 参考記事
+ [cronでaws cliを実行することが出来ません](https://teratail.com/questions/111370)
戻り値を変数に保存して扱う方法

#最近PHP触りはじめたよーて人向け

といっても僕もまだまだ勉強中なので間違った点があればご指摘下さい、、
メモ程度です。

関数て最初慣れるまで理解しにくいですよね。。。
引数とかスコープとか:expressionless:

そんな方の助けになればとなんとなく理解しにくかったところを解説させていただきます！！！

```
1. function fullname($lastname, $firstname) //6行目の引数を受け取る
2. {
3.   　$result = $lastname.$firstname; //1行目で受け取った引数を処理して$resultへ
4.     return $result;  //値を変数$resultへ返す
5. }
6. $result = fullname("山田", "太郎");  //関数fullname()を呼び出し＆戻り値を受け取る
7. echo "私の名前は" . $result . "です。"　//表示

```
##ポイントは変数 = 関数名(引数)です！
コメントアウトで処理の流れを簡単に記しましたが、６行目のように変数 = 関数名(引数)を作ってあげて変数に値を保存してあげることです！！！


慣れるまではスコープや引数はややこしいですが、意外と単純なので頑張りましょう:punch:
個人アプリ制作

video
animation
BGM
の実装ができなくて何回も検索して、見たやり方試したが、反映されない。
自分なりに検索の仕方を変えてやったが、だんだん同じものしか出てこないくなり、どういう検索仕方をしたら良かったのかもわからなくなってしまった。
コードの記述、やり方も良くなったのかもしれないので、相談していきたい。
自走能力がどういう風に上がるのか？これから考えないといけない。
Go の json.Marshal の思いがけない仕様

# 結論

`json.Marshal` は、`uint8` 型のスライスを base64 文字列にする。
`int8` 型だったり スライスじゃなくて配列だったりすると配列になるけど。

# ソースコードと実行結果

```golang:golang
package main

import (
	"encoding/json"
	"fmt"
)

type S struct {
	U8Array  [3]uint8
	U8Slice  []uint8
	S8Array  [3]int8
	S8Slice  []int8
	U8SliceP *[]uint8
	PU8Slice []*uint8
	IFSlice []interface{}
}

func main() {
	a:=uint8(1)
	b:=uint8(2)
	c:=uint8(3)
	o := S{
		U8Array:  [3]uint8{1, 2, 3},
		U8Slice:  []uint8{1, 2, 3},
		S8Array:  [3]int8{1, 2, 3},
		S8Slice:  []int8{1, 2, 3},
		U8SliceP: &[]uint8{1, 2, 3},
		PU8Slice: []*uint8{&a, &b, &c},
		IFSlice: []interface{}{uint8(1),uint8(2),uint8(3)},
	}
	bytes, _ := json.Marshal(o)
	fmt.Println(string(bytes))
}
```

実行するとこうなる：

```json:json
{
  "U8Array":[1,2,3],
  "U8Slice":"AQID",
  "S8Array":[1,2,3],
  "S8Slice":[1,2,3],
  "U8SliceP":"AQID",
  "PU8Slice":[1,2,3],
  "IFSlice":[1,2,3]
}
```

## "AQID" について

base64 でデコードすると、下記の通り `[1, 2, 3]` になる。

```ruby:ruby
require "base64"
Base64.decode64("AQID").bytes
# => [1, 2, 3]
```



# まとめ

`json.Marshal` でシリアライズすると下表のようになる。

|go上の型|json|
|:--|:--|
|`uint8` の配列|数値の配列|
|`uint8` のスライス|**base64文字列**|
|`int8` の配列|数値の配列|
|`int8` のスライス|数値の配列|
|`uint8` のスライスへのポインタ|**base64文字列**|
|`uint8` へのポインタのスライス|数値の配列|
|`interface` のスライスに `uint8` だけを詰めたもの|数値の配列|

思いがけない仕様で大変驚いた。
驚きは2点

* `uint8` のスライスが base64文字列になる点。
* `uint8` の **スライス** が base64文字列になるのに、`uint8` の **配列** は数値の配列になる点。
【Rails】assert_differenceメソッド

#assert_differenceメソッド
処理実行時の値の変化を検証するメソッド。

##実行例

```rb
assert_difference 'User.count', -1 do
  delete user_path(@non_admin)
end
```
`assert_difference`の第一引数として与えられている`User.count`が、ブロック内で変更されているかを検証しています。
第二引数には第一引数の変更される値を示しています。何も指定しないと`+1`になります。

#assert_no_differenceメソッド

```rb
assert_no_difference 'User.count' do
  delete user_path(@user)
end
```
これも`assert_differenceメソッド`と似たメソッドで、
違いは第一引数である`User.count`がブロック内の処理によって値が変化していないことを検証しています。
Atcoder AGC020 B - Ice Rink Game 別解集

このゲーム スケートリンクでやる必要あった？
#累積和的なヤツ？

後ろ側から順番に見ていき、highとlowを更新していく
今の順番の数字がその時点のhighより大きい、lowより小さい、またはその中間かで対応が違う
lowは毎回更新されるが、highはそうとも限らないのが引っ掛かったポイント

```python:math.py
K=int(input())
A=list(map(int,input().split()))

if A[-1]!=2:
    print(-1)
    exit()

low=2
high=3
for item in A[::-1]:
    #print(low,high)
    if high<item:
        print(-1)
        exit()
    elif item<low:
        low=(-((-low)//item))*item
        if low>high:
            print(-1)
            exit()
        high=max(low+item-1,high+item-1-high%item)
    else:
        low=item
        if low>high:
            print(-1)
            exit()
        high=low+item-1
print(low,high)
```

#二分探索
ラウンドが精々10**5くらいなので人数を決め打ちしてシミュレーションしてもlogNくらいなら大丈夫
なのでゲーム開始前の人数を二分探索で探せばよい
実現できないラウンド設定の場合はバグるので最後にhighとlowをシミュレーションにかけて正しい答えになるか確かめようね

最初のころは終了条件とかmiddleの値を2で切り捨てるかどうかで迷ってた
試行錯誤したけど今の書き方が気に入った
にぶたんは初期設定の範囲をばかでかくしてTLE寸前にするとハラハラしてたのしい

```python:bisect.py
K=int(input())
A=list(map(int,input().split()))

def func(num):
    for item in A:
        num=num//item*item
    return num

ok=10**20
ng=0

while ok-ng>1:
    mid=(ok+ng)//2
    if func(mid)>=2:
        ok=mid
    else:
        ng=mid

low=ok

ok=10**20
ng=0

while ok-ng>1:
    mid=(ok+ng)//2
    if func(mid)>=4:
        ok=mid
    else:
        ng=mid

high=ng

if func(low)==2 and func(high)==2:
    print(low,high)
else:
    print(-1)

```
基本情報２２週目(3/16)

##目標と結果##

##目標##
•参考書の理解。
•アルゴリズムへの理解度を深める。
•平成過去問道場午後問題を解く。

##振り返り##

__TRY__

__KEEP__

__PROBLEM__
　
##次週 and more...##
[3/9](https://qiita.com/Comitakato0515/items/fd7ca301e289ebfe22e1)
sylpheed の vCard + dropbox によるアドレス帳同期

# sylpheed でのアドレス帳同期

sylpheed でアドレス帳を同期するにはLDAPサーバを使う方法がある(らしい。使ったことないのでわからないが機能はあるっぽい)。個人でアドレス帳同期するのにLDAPサーバを立てるのは面倒なので、vCard と dropbox を使ったアドレス帳同期について説明する。

# vCard とは？

https://ja.wikipedia.org/wiki/VCard を参照のこと。google コンタクトのエクスポートにvCard 形式がある。

例えば、下記のような vCard形式ファイル address.vcf を用意する。

```address.vcf
BEGIN:VCARD
VERSION:3.0
FN:hogehoge FUGAFUGA
EMAIL:fugafuga@fugafuga.net
END:VCARD

BEGIN:VCARD
VERSION:3.0
FN:surname familyname
EMAIL:surname@familyname.com
EMAIL:surname2@familyname.com
END:VCARD
```

BEGIN:VCARD と END:VCARD で挟んだ情報が一人分の情報になる。FN: のところにアドレス帳に表示させたい名前を入れる。EMAIL: のところにメールアドレスを入力する。2つ以上のメールアドレスを登録したいときはEMAIL: を並べて書けば良い。

google コンタクトからダウンロードした場合

```contacts.vcf
item1.EMAIL;TYPE=INTERNET:hogehoge@fugafuga.net
```

のように、item1. などがついている場合があり、この場合にsylpheed はメールアドレスを読み込まない。item1. などを削除すれば、sylpheed で認識できるようになる。

# sylpheedのアドレス帳にvCardを取り込む

ツール -> アドレス帳 として、vCard をクリックしてから、ファイル -> 新規vCard とする。名前を適当に入力して、ファイルでvCardのありかを指定する。このときに、dropboxなど、同期ができるファイルに vcardファイルを入れておけば、アドレス帳が同期できるという仕組み。

# うまく行かなかった方法

http://sylpheed-support.good-day.net/bbs_article.php?pthread_id=386
にある、シンボリックリンクでアドレス帳を同期させようとしたが、どうもうまく行かなかった。というのも、シンボリックリンクでアドレス帳のデータをリンクさせても、アドレス帳に変更があったときに、sylpheed がアドレス帳のファイルをオリジナルファイルで上書きしてしまう様子。おそらくは、古いアドレス帳ファイルをバックアップして、新しいアドレス帳ファイルを生成してしまうので、こちらの求める挙動にはなってくれない様子。
基本情報２１週目(3月9日)


##目標と結果##

##目標##

•アルゴリズムの構造をしっかりと理解する。
•表計算の勉強(速習言語)p264ページ参照
•独習ゼミを使用する。
##振り返り##
過去問題をやってみたのですが、やはり解説がないと未だ解けないです。自分のわかる原因としては、計算間違い、そして、言語の理解だと思います。これらを気をつけつつ、引き続き頑張ります。
__KEEP__
1日必ず参考書に触れ、隙間時間に勉強します。
__TRY__
空いてる日は、時間をもっと有効活用すること。
__PROBLEM__
確保できる時間が足りない。

##次週and more...##

3/1
VMware上のUbuntuでマウスの戻るボタンを使えるようにする

VMware Workstation 15 playerにUbuntu18.04をインストールできたが、ブラウザ使用時にUSBマウスの「戻る」ボタンが使えなかった。そのためいろいろ試したところ、ゲストOSのフォルダにある".vmx"ファイルに、下の文を追加すれば使えるようになった。

```
mouse.vusb.enable = "TRUE"
mouse.vusb.useBasicMouse = "FALSE"
usb.generic.allowHID = "TRUE"
```

全てのUSBマウスで使えるかどうかはわからないが、まずはお試しあれ。

---
動作環境
ホストOS:Windows10Home
VMツール:VMware Workstation 15 Player 15.5.2 build-15785246
ゲストOS:Ubuntu 18.04.4 LTS
TypeScriptとTSLintをなるべく基本から

プログラミング歴半年の素人が書いています。

間違いのないようご自身でも良く調べた上でお願いいたします。


# はじめに

**『TypeScript...やってみたい！』**

でも、私のような初心者にとって結局のところ複雑性が増すことって避けがちなんですよね...。わかります、わかります。

そこで今回は、なるべく基本からTypeScriptをさらって行きたいと思います。
もちろん、互換性のあるTypeScriptのことですから、いきなり既存のプロジェクトやフレームワークに混ぜ込みながら使うこともできるのですが、なるべく小さい構成で、物事がどんな風に動いているのか基本を着実に理解していくことが大切だと思う、今日この頃です。

[こちらは私が密かに尊敬(?)する岡部さんのTypeScriptに関するご意見:　読むとTS使ってみたくなる。](https://jp.quora.com/%E4%BB%8A-TypeScript%E3%82%92%E5%AD%A6%E3%81%B6%E3%81%B9%E3%81%8D%E3%81%A7%E3%81%99%E3%81%8B-%E3%81%9D%E3%82%8C%E3%81%A8%E3%82%82%E6%9A%AB%E3%82%89%E3%81%8F%E3%81%AFJavaScript%E3%81%AE%E3%81%BE%E3%81%BE%E3%81%A7/answers/157861440?ch=99&share=c3cf8806&srid=NGuuH)


[また、こちらの記事には大変お世話になりました。](https://uncle-javascript.com/valid-typescript-chapter2)



# TypeScriptのコンパイル

まず、TypeScript（以下TS）は、JavaScriptにコンパイル（トランスパイルという人もいる）してはじめて使うことができる言語です。「コンパイルする」とは簡単に言えば「変換する」ということ。

TSを実行するには、JavaScriptに変換することが必要です。


※つまり、TypeScriptはあくまでも「人間のための言語」なんだな、って思います。機械語（JavaScript）に変換しないと実行できない。



# 環境構築

## Node.jsのインストール

なにはともあれNode.jsがないとお話になりませんので用意します。


## `npm init`してパッケージ管理の準備をする


```bash
$ npm init
```

`npm init`すると`package,json`が自動生成され、パッケージ管理できるようになります。


## TypeScriptと仲間たちのインストール

```bash
$ npm install save-dev typescript  # TypeScript
$ npm install save-dev tslint      # TSLint
$ npm install save-dev @types/node # 型システム
```

## `tsconfig.json`の作成

TSを使用するときは、この設定ファイルが必ず必要です。プロジェクトルートに作成します。

```json:tsconfig.json
{ 
  "compilerOptions" : { 
    "lib" : [ "es2015" ], 
    "module" : "commonjs" , 
    "outDir" : "dist" , 
    "sourceMap" : true , 
    "strict" : true , 
    "target" : "es2015" 
  }, 
  "include" : [ "src" ] 
} 
```


設定ファイルは、大きく2つに分かれます。

`"compilerOptions"`は、その名の通り、コンパイル時にどういう変換をさせるのかを指定しています。

- lib: あなたがどのバージョンのJSを書いているのか
- module: TSがコンパイルする際にどの module system を使用するか
- outDir: コンパイルされたコードをどのディレクトリに出力するか
- sourceMap:ソースマップ は変換後のソースと元のソースを関連付けるファイル（デバッグに使える）
- strict: 厳しく型システムを使うか、優しめにするか
- target: TSがどの JavaScript のバージョンにコンパイルして出力するかの設定

`"include"`は、`.ts`ファイルを置く場所になります。TSコンパイラはこのパスを元に`.ts`ファイルを探してきて、コンパイルします。


## `tslint.json`の作成

こちらは、TSLintの設定ファイルです。TSLintは、簡単にいうとコーディングのルールを定めてくれるライブラリです。
TSLintにしたがってコードを書くことで、一貫性のある規則にしたがった美しいコードに一歩近ずくことができます。


以下のコマンドを実行することで、デフォルトのTSLintの設定を適用することができます。

```bash
$ npx tslint --init
```


```json:tslint.json
{
    "defaultSeverity": "error",
    "extends": [
        "tslint:recommended"
    ],
    "jsRules": {},
    "rules": {},
    "rulesDirectory": []
}
```


# TypeScriptのコードを書いてみる

## `index.ts`の作成

では、**`.ts`**ファイルを作ります。

先ほどコンフィグで`src`内に`.ts`ファイルを記述することを指定したので、そのようにします。

ここまでで、以下のような構成になっています。

```
プロジェクトルート/
├──node_modules/
├──src/
│ └──index.ts
├──package.json
├──tsconfig.json
└──tslint.json 
```


`index.ts`の中身はなんでも良いのでとりあえずわかりやすくコンソールに出力しときます。

```typescript:index.ts
console.log('Hello TypeScript!')
```


# コンパイルする！

ついにコンパイルの時間がやって来ました！
このままの`.ts`ファイルでは実行できませんので、`.js`に変換します。

変換は、以下のコマンドで一発です。

```bash
$ npx tsc
```


すると、`dist`というディレクトリと、その中に`index.js`が自動で生成されました！
これがコンパイル...！

早速実行してみます。


```bash
$ node dist/index.js

Hello TypeScript!
```

無事、実行できました！


# まとめ

端折らずに、TSのコンパイラの動きを確認することで、よりTypeScriptが馴染みのあるものになりました。

あとは存分にTSの型システムを楽しむだけ！やった〜。
Glide.jsでスライドショーを作る

##Glide.jsとは
https://glidejs.com/

無料で使用できるオープンソースプロジェクトです。
他のライブラリに依存することなく、軽量なことが特徴です。

##インストール
###npm
```
npm install @glidejs/glide
```
###GitHub
https://github.com/glidejs/glide/releases/tag/v3.4.1

##読み込み
![スクリーンショット (23).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/533114/ae1dd2ed-cf26-53af-12de-3fc477f22ee4.png)
以下の二つをHTMLで読み込みます。

```html
<link rel="stylesheet" href="./@glidejs/glide/dist/css/glide.core.min.css">
```

```html
<script src="./@glidejs/glide/dist/glide.min.js"></script>
```

スライドショーを配置する位置へ以下を記入します。

```html
<div class="glide">
  <div class="glide__track" data-glide-el="track">
    <ul class="glide__slides">
      <li class="glide__slide">画像１</li>
      <li class="glide__slide">画像２</li>
      <li class="glide__slide">画像３</li>
    </ul>
  </div>
</div>
```

以下を記入し、初期化します。

```html
<script>
    new Glide('.glide', {
      autoplay: 2000
    }).mount()
</script>
```

autoplayは指定の時間で自動変更してくれます。上の例では2秒で移ります。

##サンプル

![ezgif.com-video-to-gif.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/533114/4452b4f2-4f5f-ecc9-90d7-5fc1b4621586.gif)

---
Glide.jsのサイトのDOCSからその他様々な仕様を見ることができます:slight_smile:
正規表現 先読み、後ヨミ


前提としてライブラリ`re`をインポートしている状態です。

```python
import re
```

下記の記法は全てテキスト部分のみ抽出をするもので、抽出時の条件がグループ()で示されています。
肯定はグループ内のテキスト条件も一致していた場合に抽出。
否定はグループ内のテキスト条件が一致していなかった場合に抽出。

| 名称 | 記載方法| 概要 |  
|:---|:---|:---|
| 肯定先読み | テキスト(?=xxx) | xxxが一致したときにテキスト部分を取得 |
| 否定先読み | テキスト(?!xxx) | xxxが一致しなかったときにテキスト部分を取得 |
| 肯定後読み | (?<=xxx)テキスト | xxxが一致したときにテキスト部分を取得 |
| 否定後読み | (?<!xxx)テキスト | xxxが一致しなかったときにテキスト部分を取得 |


# 肯定先読み

抽出したいテキストに続けて`(?=xxx)`を入れることで抽出したいテキストが一致 且つ `xxx`部分も一致していた場合にテキスト部分を抽出

```python
re.findall('AB(?=CDEF)', 'ABCDEF') #['AB']
re.findall('AB(?=DEF)', 'ABCDEF') #[]
re.findall('AB(?=CD)', 'ABCDEF') #['AB']
re.findall('.+(?=CD)', 'ABCDEF') #['AB']
re.findall('AB(?=[A-Z]{2,3})', 'ABCDEF') #['AB']
```

# 否定先読み
否定先読みでは抽出したいテキストの後ろに`(?!xxx)`を記載。
テキスト部分が一致 且つ `xxx` 部分が一致していない場合にテキスト部分を抽出

```python
re.findall('AB(?!CDEF)', 'ABCDEF') #[]
re.findall('AB(?!DEF)', 'ABCDEF') #['AB']
re.findall('AB(?!CD)', 'ABCDEF') #[]
```

否定しているので先読みとは逆の結果になります。


# 肯定後読み

`(?<=xxx)`に続けて抽出したいテキストを記載することで`xxx`部分が一致 且つ テキストが部分も一致した場合にテキスト部分を抽出

```python
re.findall('(?<=ABCD)EF', 'ABCDEF') #['EF']
re.findall('(?<=BC)EF', 'ABCDEF') #[]
re.findall('(?<=)EF', 'ABCDEF') #['EF']
```


# 否定後読み

`(?<!xxx)`に続けて抽出したいテキストを記載することで`xxx`部分がしていなくて 且つ テキストが部分も一致した場合にテキスト部分を抽出

```python
re.findall('(?<!ABCD)EF', 'ABCDEF') #[]
re.findall('(?<!BC)EF', 'ABCDEF') #['EF']
re.findall('(?<!)EF', 'ABCDEF') #[]
```


## 肯定先読みの応用

```python
text = 'Python python PYTHON'

re.findall('py(?=thon)', text) #['py']
re.findall('Py|py(?=thon)', 'Python python PYTHON') #['Py', 'py']
re.findall('py(?=thon)', 'Python python PYTHON', re.IGNORECASE) #['Py', 'py', 'PY']
```

## スクレイピングでありそうな使用方法

```python
text = '住所:東京都新宿区〇〇 〇〇タワー\r地図はこちら'
re.findall('(?<=:).*(?=\r)', text)[0] #東京都新宿区〇〇 〇〇タワー
```


【参考サイト】
[正規表現の先読み・後読みを極める！](https://abicky.net/2010/05/30/135112/)
setParamをつかってOREMOきりたんになりたい！（2020年春版）

setParam を使って個人が歌唱データをラベリングできるようになりました。

# 操作方法が変わりました。（追記：2020/03/27）

- 本項追記時の oto2lab 最新版は v1.0.0 です。
- exe形式で配布するようになりました。**[配布場所](https://github.com/oatsu-gh/oto2lab/releases)**
- Pythonが不要になりました。
- Excelが不要になりました。
- 使い方はReadmeをご覧ください。（記事準備中）


#ここから旧記事（2020/03/26以前）です↓

Pythonで oto2lab ってツールを作った（**[GitHub](https://github.com/oatsu-gh/oto2lab)**）ので紹介します。

## 注意

- きりたんにはなれません。
- [OREMO](http://nwp8861.web.fc2.com/soft/oremo/index.html) は使いません。
- ~~歌唱DBを配布しても歌唱ソフトに採用される可能性は**極めて低い**です。~~
    -  追記(2021-03-03)：NNSVSの登場により、個人でも歌唱合成用モデルが作れるようになりました。

## 要点

- [NEUTRINO](https://n3utrino.work/) と [東北きりたん歌唱データベース](https://zunko.jp/kiridev/login.php) が 2020年2月に話題になった。
- [setParam](http://nwp8861.web.fc2.com/soft/setParam/index.html) を使って個人が歌唱データをラベリングできるようにした。（無料）
- [Python3](https://www.python.jp/install/windows/install_py3.html)
 が必要。（無料）
- Excel が必要
- ラベル作成フローは【 UTAU(.ust) → Excel VBAで変換 → setParam(.ini) → oto2labで変換 → 完成(.lab) 】

## oto2lab について

本題です。
oto2lab と言いつつ使うのは同梱ファイルの ust2ini2lab です。紛らわしくてすみません

### 作業フロー
UST
↓ ust2ini2lab で変換（Excel VBAツール自動実行）
INI（未編集）
↓ setParamで音素ラベリング
INI（編集済み）
↓ ust2ini2lab で変換
LAB（完成）

### 環境構築
1. Python3 をダウンロードしてインストール。
2. PowerShell を起動して `pip install pywin32` を実行。
3. oto2lab > ust2ini2lab にあるxlsmファイルを一度開いてマクロ有効化しておく。

### 操作方法

1. 環境構築をする。
3. MIDIからの変換 または 手動でUSTをつくる。
4. USTまたはMIDIに合わせて歌って録音する。
5. 開始タイミングがUSTと合うように、録音ファイルを編集する。
6. USTのブレス部分に「息」ノートを入れる。
6. USTファイルを oto2lab > ust2ini2lab > ust フォルダに入れる。
7. WAVファイルを oto2lab > ust2ini2lab > ini フォルダに入れる。（16bit-44100Hz）
7. ust2ini2lab.py をダブルクリック。
8. コマンドラインが表示されるので UST→INI の機能を選択。
9. oto2lab > ust2ini2lab > ini フォルダのINIファイルをsetParamで編集。
7. ust2ini2lab.py をダブルクリック。
8. コマンドラインが表示されるので INI→LAB の機能を選択。
9. 音素ラベリングファイル LAB の完成です！



## おわりに
技術紹介が目的のため、環境構築方法や setParamでの詳細な操作は省略します。
実際の操作方法・環境構築・ラベリング説明は動画をご覧ください。
[setParamで音素ラベリングしたい！【oto2lab】](https://www.nicovideo.jp/watch/sm36575071)
【2022年版】Unityをやっているけれど、clusterをやってみたいとき

アバターをアップロードしたい方は、下記自分の記事へ遷移お願いします。
**【爆速メモ】clusterでとにかくアバターをアップロードしたいとき**
https://qiita.com/sanpeita/items/ceb57e9eb8e55f6ba495

---

2022年5月に更新しました。
公式サイトのリンク集と思ってもらえれば幸いです。
Unityをふだんさわっていて、clusterをやってみたいな、と思った方の切り口になれば幸いです。

自分でなにかUnityで作品をつくっていて、それをclusterに反映できたらいいな、という場合は、下記のような手順を個人的にオススメします。
1. clusterのテンプレートプロジェクトをダウンロードして、それを自分のclusterアカウントでアップロードしてみる。
2. アップロードのフローがつかめたら、自分のUnity作品を、clusterのUnityバージョンに合わせて調整して、アップロードしてみる。

# Unityのバージョンなど、環境について
- スクリプトの記載は反映されないので、お気をつけください。

## 調べもののトップページになるところ。
- クリエイターズガイド
https://creator.cluster.mu/

下図のようなページが開かれます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191635/f9c53e7f-98bf-7af4-86f0-ab72026bdd62.png)

## 細かい説明が書いてあるページ。
- Cluster Creator Kit ドキュメント
https://docs.cluster.mu/creatorkit/

下図のようなページが開かれます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191635/ac1c4394-6b68-0162-1047-b3a5b2195df6.png)

## Unityの導入
- 「Creator Kitのセットアップ」内の「Unityの導入」に記載があります。
- Unity 2019.4.22f1

下図のようなページで表記されています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191635/3b1412e1-a12d-2517-d446-7d27097e20d2.png)

- Unityに追加するモジュールについて。

下図のように表記されています。追加でインストールしましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191635/51c49775-eb14-212b-e12f-1959b75a0d23.png)

## Creator Kitの導入
- 「Creator Kitのセットアップ」内の「Creator Kitの導入」に記載があります。

下図のように表記されています。
導入手順は、[記載されているとおりに設定しましょう。](https://docs.cluster.mu/creatorkit/installation/install-creatorkit/)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191635/c65c6e9f-da00-c06e-2348-ae130400b0c7.png)

---

以下の古い文言については取り消し線を引きます。

~~以下、本記事。~~

~~爆速とはいえども、やはり公式最強。~~
~~ブラウザで、~~

~~公式　すぐ出来る！ワールド作りの始め方~~
~~https://creator.cluster.mu/2020/02/27/helloworld/~~

~~を開きつつ、~~
~~・unity(2019でバージョン指定あり!!)~~
~~・Git~~
~~をインストールすべし。(詳しくは上記の公式を見たほうが早いです。わかりやすいです)~~

cluster用のワールドを練習で作りたいとか、初めてアップロードしたいとかだったら、
クリエイターキットのパッケージをインストールしたり、
そもそもunityのインストールでアドオン多かったりするので、
作業時間は多めに見積もるべし。
(どのくらいか？　オフ日に10時くらいにまったり始めて、1時間は環境設定であれこれしていると思ったほうが良い)

あとmacの場合は、結局はxcodeが必要なので、unityやっている上で
「xcodeは容量食うから普段消してるぜ!!」という方は、覚悟してください。

ワールドのアップロードは、ぼーっと待っているだけだと時間がかかるので、
switchでデッドセルズやったり、スイーツ食べたりしていてください。

 ~~

公式サイト
https://cluster.mu/

公式　クリエイターズガイド
https://creator.cluster.mu/

公式　すぐ出来る！ワールド作りの始め方
https://creator.cluster.mu/2020/02/27/helloworld/

そんなこんなで、今日息子と作ったワールドがこちら。練習用です。
https://cluster.mu/w/0cec517b-b4ba-4246-9e7f-f39989cf3b53

<img width="1016" alt="スクリーンショット 2020-03-16 16.59.34.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191635/7efb63a1-8967-d8d5-0310-96e4cebf857d.png">