OmniAICreator/Qiita-1.07M huggingface dataset:
まずodooの概要について(odoo13)

# はじめに
pythonに慣れている方ですと、Flask、Djangoなどのフレームワークには触れたことがあるかと思いますが、Odooというpython世界にあるフレームワークにふれる機会はなかなかないのではないでしょうか。実はこのOdooという企業系のソリューションのフレームワークというか、ソフトとうか、っていうのが非常に強力なツールなのです。pythonに慣れていてしかも企業系ソリューションを探しているのであれば、このフレームワークに触れないのはもったいないのではないかなと思います。

私の場合、Odooはdjangoに触ってから初めて触るフレームワークなので、色々勉強がてらアウトプットとして記事を書いていきたいと思い、記事を書きます。
このフレームワークは最初はわけが分からず戸惑うかもしれません。というのも資料がほんとになくて、困り果てるかと思います。自分の場合、英語や中国語の資料を読み漁って、やっとというところでした。日本語ですとほんとに資料がないんです。そこはどうしようも有りません。英語の記事を頑張って読むしかないかなと思います。

# odooとは
まずはオフィシャルな内容について書くと、OdooとはオープンソースのビジネスシーンのAll in oneみたいなソリューションです。ソリューションパッケージは企業のすべてのニーズに対応できます。企業の販売、CRM、HR、経費、購入、品質管理、採用、休暇、昼食管理、内部フォーラム、内部チャット、顧客クレーム管理、VOIP、EC、企業ウェブサイト、財務、銀行帳簿管理、HR給料管理、WMS倉庫管理、POS、コミュニティショップ、PLMなどなど色々あります。

ざっくりいうと、OdooはERPアプリケーションの一種のソリューションです。同時に、非常に多くのモジュールと呼ばれる補足機能が使用でき、二次開発にも用いられる。Odooの最も大きな特徴はオープンソースとモジュール化です。

### オープンソースの意味合い
オープンソースの意味は言うまでもなく、ソースコードはGithubにて公開しております。即ち、誰もがソースコードにアクセスができ、無料でOdooコミュニティ版（企業版もありますが、有料です）を利用できます。

### モジュール化とは
Odooにおけるモジュール化とは、Odooの最も特筆すべき特徴です。この特徴はその他のEPRソリューションと大きく違う点だと思います。開発者はかんたんに既存のモジュールを継承し、あるいは拡張し、様々なニーズに対応することができます。

# 最後に
私はこれまでプログラミングについて一年間程度独学でやってきました。が、その結論としてやはり実践なしでは勉強にならないことがわかりました。何かを勉強しましたじゃ話にもなりません。
以下にその勉強したらどれくらい知識が身につけたかについて感覚的に纏めてみます。

勉強しました　20%（2割り程度身につけた） 
言語化しました  30% 
なにかを作りました　50%
人に教えました 60% 

という感じではないでしょうか。ということで、結局は何をアウトプットしないと意味がないんじゃないかなと思います。閉じこもってやってられないし、人と共有しない限り、インターアクティブが生まれません。そうするとやる気も続かないのです。とことん自分のわかってる勉強できた知識を言語化して人の役に立つことを発信していくことの大切さを改めて痛感したところです。
さてさてまたね。
Teamsのメンバー一覧をエクスポートする（一般ユーザーで）

[Power Automate でOffice365の各グループにメンバーを追加できるか検証してみた](https://qiita.com/drafts/a5a4b1cf18ee4ee24f4b/)で調べたことに関係して、「チームのメンバーを一括でエクスポートしたいんですけど、どうしたらいいですか」って質問がきてたので調べてみた。

Teamsのメンバー管理、メンバーが数名のうちはGUIで十分なんだけど、メンバー数が数十を超えてくると画面上での管理がつらくなる。EXITしてる方を探すのに、目で見るのは結構キツイ。

管理者なら、Azure AD 管理センターから一括ダウンロードすればいいけど、ユーザーにはちょっと触らせられない。（PowerShellでエクスポートは今回は除外）

というところで、Power Automate で実施できたのでまとめてみた。


1.エクスポート用のエクセルファイル作成
2.フローを作成する
3.まとめ


#エクスポート用のエクセルファイル作成
OneDriveにエクセルファイルを1つ作成して、列タイトル（今回はUPNと表示名の2列)とダミーデータを1つ入れる。

作成した領域を選択して、挿入→テーブルからテーブルに変換。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/237698/87981ab8-4c24-cff2-18fc-74ef607ceeae.png)



#フローを組む

ざっとこういうイメージ。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/237698/ee96ff4a-e87b-dd7e-fe94-e61e17862b8a.png)



1．トリガー
手動トリガーを作って、ポチっとしたら起動させる。別にタイマー起動でもOK。


2.アクション - Office 365 グループ - グループメンバーの一覧表示

対象のチームを指定する。
所有しているチームが表示されるのでそこから選択する。

デフォルトは100名までしか取得してくれない。100名以上いる場合は、「上」に999までの値を設定する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/237698/254c8b0d-5be7-5561-3ecb-62b7691cca06.png)


上って何？機械翻訳？ってことで英語にしてみたらTopでした。取得する最大と考えることにします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/237698/1e243c9b-ec7a-d7e3-cd0c-2e1e71fa00a5.png)


3.アクション - 表を作成する　
Excel Online ( Business ) - 表に行を追加する、を使う。
このアクションを選ぶと、自動でApply to eachが入る。繰り返し実行するので必要。勝手に入るけど気にせずOK.
エクセルファイルの保存先、ライブラリ、ファイル、テーブルと順に指定する。

すると、テーブル内の列が表示されるので、動的なコンテンツから、[グループメンバーの一覧表]から、[ユーザープリンシパル名][表示名]をそれぞれ選択する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/237698/35000093-18a4-def8-9b14-e4c06ad96ec6.png)



保存して、テストと。
エクスポートできたら完了。
先ほど作成した際のダミーデータは行削除しましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/237698/6d4b177e-d57c-ebcf-6e3e-f869d37b136a.png)


#まとめ

ユーザーでも実施できます。人数が多いチームには便利そうです。
999名以上いるようなグループは、改めて考えてみます。

2020/07/26追記
一括インポートも手順まとめてみました。
[Teamsのメンバーを一括登録する（一般ユーザーで）](https://qiita.com/hisssa0102/items/95bc2d168825213c316f)
G検定を受験した感想を忘れないうちに


# はじめに
2020年７月に受験しましたので、忘れないためにも記事にまとめてみました。
参考程度に流して頂けたら嬉しいです。無事合格しました


# G検定とは？
一般社団法人日本ディープラーニング協会が主催しているAIの知識を問う資格試験です。年に３回実施。
一つ上の段階でエンジニア向けのE資格という資格試験があります。G検定が取得できたらE資格も続けて受ける方もいるそうです。

####
受験概要
・受験資格
→特になし

・実施概要
→制限時間：２時間
→選択問題２２０問程度

・受験方法
→試験申し込みサイトから申し込み、自宅or職場等のパソコンからログインし受験する形式
*受験当日は、試験中にわからない問題があったら、ネット等調べながら回答はできますが、全く勉強していない状態で受験した場合、時間が到底足らなくなるので要注意。

# 使用した教材
１）[徹底攻略 ディープラーニングG検定 ジェネラリスト 問題集 徹底攻略シリーズ](https://www.amazon.co.jp/dp/B07NDVCN99/ref=cm_sw_em_r_mt_dp_U_BezcFb4ZPZ3T3)

通称黒本とよばれるメインとなる本。試験直前には正答率を８割超えるまで
やりました。

2)[深層学習教科書 ディープラーニング G検定(ジェネラリスト) 公式テキスト](https://books.rakuten.co.jp/rb/15618087/?msclkid=779ed510be3111ec85f2ebd4f1718876)
通称白本。

３）[これ1冊で最短合格 ディープラーニングG検定ジェネラリスト 要点整理テキスト&問題集](https://www.amazon.co.jp/dp/4798057304/ref=cm_sw_em_r_mt_dp_U_4izcFbGZY9E76)

最近出た本です。黒本と白本では正直足らないため、購入して、繰り返しました。

経験が浅い自分が行ったやり方としては、
1)白本をざっとはじめ流し、知識を少しづつ入れ
2)黒本の問題を解きながら身につけ
3)改めて整理することを目的に要点整理テキストに手をつけました。
→大学数学などでわからないところは、youtubeの動画などを探して流し見してました。


最後にこれとは別にウェブ上の模擬試験を受け、８割を目指すようにしてました。
（ただ、これでもまだ足りないようで試験当日はとても苦労しました。）

模擬試験サイト（study-ai）：http://study-ai.com/generalist/



# 自分がよく間違えた箇所について
演習で間違えた箇所はノートにまとめ、隙間時間に眺めてました。およそ２冊ほど。
自己満足ですが、自分がよく間違えていた箇所についてまとめてみようかと思う。（誰得
用語整理中心です。こんな内容が出るということで参考になったらいいなぁということで。

・AIの歴史について
第一次AIブーム　：「推論と探索」　トイプロベレム
第二次AIブーム　：エキスパートシステム

・教師あり学習
１）回帰（regression）→出力値（数値）の予測
２）分類(Classification)→あらかじめ設定したクラスにデータを割振る
　　　（クラス分類、例えば画像に写っている犬や猫の識別）

回帰→線形回帰（単回帰分析、重回帰分析）
分類→サポートベクターマシン、決定木、ランダムフォレスト、ロジスティック回帰、KNN法
クラスタリング→似たデータがなす「クラスタ」を抽出する
　　　　　　　（クラスタはデータから自動的に導かれる）
　　　　　　→k-means法
次元削除→主成分分析
　　　　　データから「主成分」という新たなデータを求める。
　　　　　線形な次元削減の手法を指す

正規化→データの大きさを適切にスケーリング
標準化→データの平均を０、分散を１に変換する
正則化→過学習を抑制する方法

サポートベクターマシン（SVM）
→「マージンの最大化」というコンセプトのもと、２つのクラスを線形分離するアルゴリズム
スラック変数：誤分類を許容するための工夫

サポートベクターマシンは、線形分離可能でないデータ（直線で分類しきれない）に対してもカーネル法という手法を組み合わせることで決定境界を求めることができます。
膨大な計算量が必要なため、カーネルトリックという手法で計算量を現実的に抑えつつ、非線形分離を
実現。

決定木→不純度が最も減少（情報利得が最も増加）するように条件分岐を作り、データを振り分けする。

ロジステック回帰→線形回帰を分類問題に応用したアルゴリズム

バーニーおじさんのルール
→学習には、調整が必要なパラメーター数の約１０倍のデータが必要であるという経験則

ノーフリーランチの定理
→あらゆる問題に対して万能なアルゴリズムは存在しないという定理

醜いアヒルの子定理
→機械学習における定式化によって「普通のアヒル」と「醜いアヒル」の区別ができないという定理

モラベックのパラドックス
→機械としては、高度な推論よりも１才児レベルの知恵や運動スキルを身につけるほうがはるかに難しいという
パラドックス。

・局所最適解→その周辺では、誤差の値が小さいが最小値を実現するわけではない解
・大域的最適解→誤差の値を最も小さくする解
・停留点→局所最適解でも大域的最適解でもないが匂配が０になる点

重みの更新のタイミング
・エポック→訓練データを何度学習に用いたか
・イテレーション→重みを何度更新したか

・画像認識に適したもの→畳み込みニューラルネットワーク（CNN）
・時系列データに適したもの→再帰型ニューラルネットワーク（RNN）

アンサンブル学習→弱学習器を組み合わせて精度をあげる手法
 - バキング→各モデルを並列に学習
 - ブースティング→各モデルを逐次的に学習

物体検出とは？
→対象物がどこにあるかをボックスに切り取り、対象物を推定するタスク

物体セグメンテーション
→対象物体を背景をピクセルごとに詳細に切り分けて、そのピクセルごとが示す意味を推定するタスク

# 感想
練習段階では、1時間ちょいで終わっていましたが、本番での回答終了時間は、試験終了の３０秒前でした。

ネットでも騒がれているように、公式テキスト以外も多く出題します。
技術も覚えるだけではなく、理解するのもとても重要。
ただ、テキスト内容も３〜４割程度出題するので、基本を頭に入れる意味でも公式テキストを
やりこむのは必須です。ふむー。

G検定の資格勉強をきっかけに、大学数学や統計も少しかじる機会があり、視野がすこ〜し広がりました。
この資格取得をきっかけに、仕事の幅が広がるといいなと思います。
Git submodule 参照先を更新する手順

Git submodule 参照先（コミットID）を更新する手順。

```
cd <submoduleディレクトリ>
git checkout <コミットID>
cd <リポジトリディレクトリ> ※ submoduleの親ディレクトリ
git add .
git commit -m "<コミットメッセージ>" 
```
GitHub Actions でプルリクのマージでワークフローを実行する

**2020/07/11** [コメント](https://qiita.com/okazy/items/7ab46f2c20ec341a2836#comment-5b11432f6d5376f635c6)でご指摘いただきまして内容を修正しました。ありがとうございます。

GitHub Actions にはプルリクがマージされた際のイベントは用意されていません。
プルリクがクローズされた際のイベントとプルリクがマージされているかどうかの条件を組み合わせることでプルリクのマージ時にのみワークフローを実行する設定が可能です。

```yaml
on:
  pull_request:
    branches:
      - master
    types: [closed]

jobs:
  tag:
    runs-on: ubuntu-latest
    if: github.event.pull_request.merged == true
```

マージされたプルリクエストは常にプッシュになるため、 `push` イベントを利用してもプルリクエストのマージ時にワークフローの実行が可能です。

```yaml
on:
  push:
    branches:
      - master
```

ただしこちらの場合は、直接 `master` ブランチにプッシュした際もワークフローが実行されますのでご注意ください。
フローの使用開始

１．フローを作成すべきであるのはどの状況ですか?
２．Lightning フローと Flow Builder の違いは何ですか?
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634241/6ba5961b-74cb-e44c-470b-555773bc6201.png)
DJ機材を使ってDI(依存性注入)を完全に理解した（前準備編）

# はじめに
最近 symfony(php) を仕事で使うようになって出てくるようになったDIをまとめる。
例によって3分程度で読む記事です。この記事の目的は、DI自体を理解するための前準備です。DIの記事には単体テストしたいよねという記事がよく出てくるが、そもそもDIに紐づく『インターフェース』がよくわかってなかったんだよな。妙に遠回りするような物言いで。なら実際のもので置き換えてみようと思いました。

# DJ機材の中心といえばこれ
https://www.soundhouse.co.jp/products/detail/item/226510/
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/94562/2da7639a-8a7e-16d9-d743-844879ee91be.png)
DJ機材にものすごく入れ込んでるときはチャンネル数が多いものを『いいものだ』と思ってどんどん買い換えようとするんだけどスキルがこなれるほど2chでいんじゃね？ってなるよね。まぁそれはどうでもいいんだけど

# キー・アイテムはこれ
[NEUTRIK ( ノイトリック ) / NDJ](https://www.soundhouse.co.jp/products/detail/item/166973/)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/94562/598402c3-a440-1e97-cd6f-c2cf5a5ba315.png)
そう、別名ダミーキャップだ。

# インターフェースとは
インターフェースとはギアスです。最大に効果を発揮する場面は、大規模開発で人がたくさんいるような場合に、取り決めだけを作ることができるということです。取り決めをしたメソッドが無いような場合に、コンパイラが「エラーを出すことができる（そんな命令ねーよ！）」これがインターフェースの最大の利益です。人為的なコンパイルエラーを作ることができる、と。

```c#:symfonyでいい例が見つからないからこれはC#だけどね。ほら、メソッド名と戻り型しかかいてないでしょ？
public interface IDataGenerator
{
    int[] Generate();
}
```

# ダミーキャップの目的とインターフェース、DIの関係
さてダミーキャップは、機材を守るという意味もあるが、今回のダミーキャップと機材の関係の本質は「あたかもそこに機材がつながっているように振る舞う」ことです。プログラミングで使われる「インターフェース」とは、『端子の構造（＝型）を守れという抽象的な取り決め』だ。プラグの型さえ合っていれば、たとえ今はダミーで意味はなくてもそこに『phone端子のなにかとつながった！』という関係性が成立します。全く意味はないけどそういうふうに作れば、phone端子の先にアイロンがくっついててもいいわけです。

# Dependency Injection（DI）について
`DI`は「依存性の注入」と書かれますが、これは非常にわかりにくいことで有名な表現です。`DI`の本質は「オブジェクトを（クラスの中に）インストールする」ことです（別の言い方をすると責任の外だし）。「依存性の注入」を別のものに例えると「ロックマン」です。敵の能力を`DI`（武器をロックマン用に合わせ（`interface`）こんで）して、敵の武器（`method`）を扱います。これが`DI`の勘所であります。責任を外出しするという表現が使われるのは、抽象的な概念（`interface`）しかそこにはないからです。

```c#:symfonyでいい例が見つからないからこれはC#だけどね。ほら、メソッド名と戻り型しかかいてないでしょ？
public interface IDataGenerator
{
    int[] Generate();
}
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/94562/87812a0a-9e7f-8881-d5f2-d438e37176f9.png)


# ここで学んだあとに見るURL
[DI (依存性注入) って何のためにするのかわからない人向けに頑張って説明してみる](https://qiita.com/okazuki/items/a0f2fb0a63ca88340ff6)
Rust でテキストファイルのレコードを削除

こちらで作成したテキストファイルのレコードを削除します。
[Rust でテキストファイルの作成](https://qiita.com/ekzemplaro/items/fa21c2fb7123cbad3c6c)

```rs:text_delete.rs
// --------------------------------------------------------------------
/*
	text_delete.rs

						Jul/17/2020
*/
// --------------------------------------------------------------------
use std::env;
use std::error;
use std::fs::File;
use std::io::{BufRead, BufReader};
use std::collections::HashMap;
use std::io::{Write};
// --------------------------------------------------------------------
fn text_read_proc(fname_in: String) -> HashMap<String,HashMap<String,String>>{
	let mut dict_aa = HashMap::new();
	let file = File::open(fname_in).expect("file not found.");

	for line in BufReader::new(file).lines() {
		let line = line.unwrap();
		let vvv: Vec<&str> = line.trim ().split_terminator('\t').collect();
		let mut unit_aa:HashMap <String,String> = HashMap::new ();
		unit_aa.insert("name".to_string(), vvv[1].to_string());
		unit_aa.insert("population".to_string(), vvv[2].to_string());
		unit_aa.insert("date_mod".to_string(), vvv[3].to_string());

		dict_aa.insert(vvv[0].to_string(), unit_aa);
	}

	dict_aa
}

// --------------------------------------------------------------------
fn text_write_proc (fname_in: String, dict_aa: HashMap<String,HashMap<String,String>>) {
	let mut file = File::create(fname_in).expect("file not found.");

	for (key,value) in dict_aa.iter() {
		let str_out = key.to_string () + "\t" + &value["name"]
			+ "\t" + &value["population"]
			+ "\t" + &value["date_mod"] + "\n";
		print!("{}", str_out);
		file.write (String::from(str_out).as_bytes()).expect("cannot write.");
	}

}

// --------------------------------------------------------------------
fn main () -> Result<(), Box<dyn error::Error>> {
	println!("*** 開始 ***");

	let args: Vec<_> = env::args().collect();

	let ref fname_in = args[1];
	let key_in = &args[2];

	println! ("{}",fname_in);
	println! ("{}",key_in);

	let mut dict_aa = text_read_proc(fname_in.to_string());

	dict_aa.remove(key_in);

	text_write_proc (fname_in.to_string(),dict_aa);

	println!("*** 終了 ***");

	Ok(())
}

// --------------------------------------------------------------------
```

```text:Makefile
text_delete: text_delete.rs
	rustc text_delete.rs
clean:
	rm -f text_delete
```

コンパイル

```text
$ make
rustc text_delete.rs
```

実行

```bash
./text_delete cities.txt t2385
```

## 確認したバージョン

```text
$ rustc --version
rustc 1.75.0 (82e1608df 2023-12-21) (built from a source tarball)
```
WSLでUbuntu 20.04 + RStudio Server + R4.0

WindowsのRStudioで日本語のdataを扱おうとするとコンソールにちゃんと出力されなかったりするので、RStudio Serverを入れて解決。

# 必要なもの
- Windows 10 Professional (May 2020 update 適用済み)の入ったパソコン

# Windows Subsystem for Linux 2のインストール

WSL2が入っていないとUbuntu 20.04で動かない機能があるの、インストールしないといけない。これは、Windows 10 version 2004から可能。私の場合はすでにWSL1にUbuntu 20.04が入った環境で始めたので、アップデートが必要だった。

まず、cmdでWSLのバージョンを確認。

```
wsl -l -v
```

出力がこうなっていたらWLS1。

```
  NAME            STATE           VERSION
* Ubuntu-20.04    Stopped         1
```

## WSL2を使えるようにする

"Virtual Machine Platform"を有効にしないといけないので、管理者として開いたPowerShellで、

```
dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart
```
この後マシンを再起動。

次に、WSL2をデフォルトにする。管理者権限で起動したPowerShellで、

```
wsl --set-default-version 2
```

## UbuntuのWSLのバージョンを変える

再びPowerShellで

```
wsl --set-version Ubuntu-20.04 2
```

こんなメッセージが出たら成功

```
Conversion in progress, this may take a few minutes...
For information on key differences with WSL 2 please visit https://aka.ms/wsl2
Conversion complete.
```

一応cmdで確認

```
C:\Users\****>wsl -l -v
  NAME            STATE           VERSION
* Ubuntu-20.04    Stopped         2
```

# R4.0のインストール

Ubuntuのシェルを起動して

1. 諸々アップデート

    ```
sudo apt-get update
sudo apt-get upgrade -y
    ```
2. R4.0の使えるUbuntu 20.04のリポジトリを登録

    ```
sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys E298A3A825C0D65DFD57CBB651716619E084DAB9
sudo add-apt-repository 'deb https://cran.r-project.org/bin/Linux/ubuntu focal-cran40/'
    ```
    この、リポジトリの登録が、WSL1だと動かないので、WSL2が必要になる。

3. Rのインストール

```
sudo apt install -y r-base r-base-core r-recommended r-base-dev gdebi-core build-essential libcurl4-gnutls-dev libxml2-dev libssl-dev
```

# RStudio Serverのインストール

```
wget https://rstudio.org/download/latest/stable/server/bionic/rstudio-server-latest-amd64.deb
sudo gdebi rstudio-server-latest-amd64.deb
```

私の環境だとインストールしたら、サーバーが立ち上がっていたけど、一応起動コマンド

```
sudo rstudio-server start
```
ここまですれば、後はWindowsのブラウザから`http://localhost:8787`で接続できるはず。
LPIC level1について軽くまとめてみる(101編)

#まえがき(挨拶)
本日LPIC102を取得しLPIC level1に認定されたのでちょっとしたまとめを書こうと思います。
#取得した経緯
取得した経緯ですが、現役でインフラエンジニア(ネットワーク強め)をやっていてネットワーク周りの知識は大分深まってきていると感じていますが、OSやサーバインフラ周りの知識が殆ど無かったので取得しようと思いました。
#勉強期間とスコア
・LPIC level1 全体：約3ヶ月
・LPIC101：約2ヶ月

・スコア：550点
・内訳
　システムアーキテクチャ：62%
　Linuxのインストールおよびパッケージ管理：75%
　GNUコマンドおよびUnixコマンド：76%
　デバイス、Linuxファイルシステム、ファイルシステム、階層標準：64%
#試験内容
・システムアーキテクチャ
システムの起動順序やBIOSで設定できる内容、デバイスファイルやランレベルに関する内容
ここは自作PCを作成したことがある人は得意かもしれません。

・Linuxのインストールおよびパッケージ管理
各ディレクトリの役割(/home：一般ユーザが利用するファイルが入っている、/var：ログファイルやメールスプールなどのファイルが入っている等)パーティションの考え方、Debian系、Red Hat系のパッケージ管理についてなど

・GNUコマンドおよびUnixコマンド
Linuxのコマンドラインでの操作(cd、cp、rmなど)、ファイルの編集(viエディタの使い方)など

・デバイス、Linuxファイルシステム、ファイルシステム、階層標準
パーティションの作成、ファイルの検索やマウントのやり方など
#感想
101は基本的にコマンドの暗記がメインになりました。特にパッケージ管理コマンド(dpkg、rpm)のオプションが多すぎて途中でキレそうになりましたw
1番勉強していて面白かったのはコマンドラインでの操作です。やっぱりプロンプトでの操作をしているとOSを細かく操作できている気分になるので面白かったです(小並感)
「君がデータサイエンティスト？百年速い」といったあいつを見返すまで ～Win 10 Home上にDocker作って「データサイエンス100本ノック(構造化データ加工編)」のSQL版を起動するまで、編～

# すべてのはじまり
奴：「君がデータサイエンティスト？百年速いんじゃない？」
・・・いいだろう。やってやろうじゃないか。

（その日の深夜）下調べは十分だ。どうやらPython(パイソン),R,SQLが使える必要があるらしい。ふふふ、勝ったな。SQLなら昔、かじったことがある。そのためには、この「[データサイエンス100本ノック(構造化データ加工編)](https://github.com/The-Japan-DataScientist-Society)」が一番の近道だということも分かった。よ～し、さっそくこの愛機、無銘(:中華ノートPC)へインストールするぜ！

# Dockerのインストール（for Win 10 Home）
ふむふむ、まずはDockerが必要、と。
よし、ダウンロードOK!実行！っと。

ん？なんだこのエラー？ 
`Docker Desktop requires Windows 10 Pro/Enterprise (15063+) or Windows 10 Home (19018+).`
Windows 10 Homeのかたは、Ver.19018以上にしなさいってことか。そういや、しばらく、Windows Updateしていなかったかもな。

・・あれ？Windows Updateを最新化したのに、まだ、同じメッセージだ。
そういえば、DockerってWin10Proじゃないとだめって聞いたことがあるような。データサイエンス100本ノックではDockerToolboxが必要って書いてあったな。あれ？そんなのDockerにないな。
ヤバイ。詰んだ。。。
くっ、このままでは、あいつにまた馬鹿にされる。底辺ネット民のGGR力を舐めてもらっては困るな。

# WSL2へのいざない
・・・ふむふむ。
[Windows 10 Home で WSL 2 + Docker を使う](https://qiita.com/KoKeCross/items/a6365af2594a102a817b)なら、そもそも、Powershellでコマンド実行が必要やったのね。
お、もっとわかりやすいのが[ここ](https://qiita.com/tomokei5634/items/27504849bb4353d8fef8)に。

# パワポルートからの逸脱
あれ？そしたら、データサイエンス100本ノックのInstall手順↓からはずれるぞ。

```$ git clone [Repository URL] 
$ cd 100knocks-preprocess
$ docker-compose up -d --build
```

どうやったらいいんだ？
そだそだ、こういう時こそ、おちついて[公式ドキュメント](https://github.com/The-Japan-DataScientist-Society/100knocks-preprocess/blob/master/docker/doc/100knocks_guide.pdf)だ。

# 公式ドキュメントを熟読
ふむふむ。わかったぞ。以下が公式pdfに書かれている手順だ。
1. Gitをインストールする。
2. Dockerをインストールする。
3. 100本ノックリポジトリをクローンする。
4. ターミナル等でdocker-composeファイルのあるディレクトリまで移動
5. ターミナル等でコンテナ作成コマンドを実行する。

だけど、 *Win 10 Home* の場合は、
1. WSLをインストールする。
2. Dockerをインストールする。
3. 100本ノックリポジトリを *ZIPダウンロード* して自分のホームディレクトリ配下に展開する。
4. ターミナル等でdocker-composeファイルのあるディレクトリまで移動(cd 100knocks-preprocess)
5. ターミナル等でコンテナ作成コマンドを実行する。(docker-compose up -d --build)
ということだと理解。早速試してみよう...

おや？５の段階でエラーがでたぞ。
![C__WINDOWS_system32_cmd.exe 2020_07_11 20_20_51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/98166/d789a74d-7721-bea6-f992-2d3b1fb6ebab.png)

# 再び公式ドキュメントを深堀
そういや、そういった場合は、Dockerのコンテナを再起動して再実行として書いてあったな。
Docker Desktopにいって、(Stop)停止っと。そして起動(Start)。
![Container list 2020_07_11 20_22_28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/98166/29a17894-1658-545d-a921-3a69f8b8b48c.png)


そんで、`docker-compose up -d --build` の再実行！

と、おお！エラーがきえた！ふふふ、よっしゃー！きたこれ！
`http://localhost:8888` （[ここ] (http://localhost:8888) からもいけるようにしておくよ）
![JupyterLab - Google Chrome 2020_07_11 20_37_46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/98166/9a709098-1754-ed76-6516-8cdc95ab73a9.png)

おう、!なんか開いた！このworkの下やな。
![JupyterLab - Google Chrome 2020_07_11 20_39_54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/98166/c3ca660d-1821-308d-d945-4439a2696efd.png)

たぶん、このpreprocess_knock_SQL.ipynbてやつをダブルクリックやな！
![JupyterLab - Google Chrome 2020_07_11 20_41_35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/98166/4a9c7287-123c-a656-d834-58e67e3bb8fa.png)

# 「データサイエンス100本ノック(構造化データ加工編)」のSQL版を起動
きたきた！これで、あとはSQLをつかいこなすだけだぜ～。
メモ：Swift5で初回起動判定

n番煎じのネタだと思いますが、自分用のメモ。

```Swift
func setup() {
    //UserDefaults.standard.set(false, forKey: "visit") //リセット用
    let visit = UserDefaults.standard.bool(forKey: "visit")
    if visit {
        //二回目以降
        print("二回目以降")
    } else {
        //初回アクセス
        print("初回起動")
        UserDefaults.standard.set(true, forKey: "visit")
    }
}
```

`setup()`をAppDelegateとかSceneDelegateに追加するだけです。
端末保守

# TODO
- [x]  特定ファイルのサイズ監視　※ここにサンプルコード含めて書く!!⇒csvファイル出力(先頭行ファイル名のテンプレ用意)
- [ ]  今までの対応ねた思い出し...(できたら追記)

# はじめに
開発する際には保守が重要!!忙しい時に限って、問題が多発するので...

## ネットワークの疎通確認
```terminal:network.bat
ping localhost
ping 127.0.0.1
```
```powershell:network.ps1
# コマンド結果の「TcpTestSucceeded」の値が「True」の場合は、指定したポートでの疎通はできている
Test-NetConnection [サーバ名(IPアドレス)] -Port [ポート番号]
```

## 一定時間Sleepさせる

```terminal:troubleshooting.bat
powershell sleep 10

timeout 10

```

## 特定ユーザーのプリンター情報設定＆取得

```terminal:troubleshooting.bat
REM 特定ユーザーに切替
runas /noprofile /user:WAKASAMASP2\wakasama cmd
WAKASAMASP2\wakasama のパスワードを入力してください:
cmd をユーザー "WAKASAMASP2\wakasama" として開始しています...

REM ★この後指定ユーザーのコマンドプロンプトが起動される
REM プリンター設定切替
rundll32.exe printui.dll,PrintUIEntry /y /n "Microsoft XPS Document Writer"

REM デフォルトプリンター情報取得
powershell -Command "Get-ItemProperty HKCU:""HKEY_CURRENT_USER\Software\Microsoft\Windows NT\CurrentVersion\Windows"""

```

## 特定ファイルのサイズ監視

```terminal:troubleshooting.bat
REM -----------------------------------------------------------------
REM 監視対象ファイルのサイズ情報をcsv出力

REM ファイルサイズ情報をテキスト出力
REM   ※監視対象のファイルだけ出力されるように要工夫!!
dir C:\Users\wakasama\Desktop  D:\test.ps1 | findstr "png ps1" > tmpResult.txt

REM 今日の日付を取得
for /f %%a in ('wmic os get LocalDateTime ^| findstr \.') DO set LDT=%%a
set CUR_DATE=%LDT:~0,8%

REM tmpResult.txtからスペースまで3列目(ファイルサイズ)をaに格納,4列目(ファイル名)をbに格納
REM 遅延環境変数定義をすることで、FILESIZEINFOに順次情報が追記される
REM   ※サイズのみだと違うファイルが選択されていたときに気づかないのでファイル名も出力
setlocal enabledelayedexpansion
set FILESIZEINFO= 
for /f "tokens=3,4 delims= " %%a in (tmpResult.txt) do (
set FILESIZEINFO="%%b","%%a",!FILESIZEINFO!
)
set FILESIZEINFO=%CUR_DATE%,!FILESIZEINFO!
echo !FILESIZEINFO! >> fileSizeInfo.csv
REM -----------------------------------------------------------------
```

## 簡易HDD容量チェック

```terminal:troubleshooting.bat
wmic /node:xxx.xxx.xxx.xxx,yyy.yyy.yyy.yyy logicaldisk where drivetype=3 get DeviceID,FreeSpace,Size,SystemName
ECHO 結果を確認してください!!
PAUSE
PAUSE
```

## Windows 10のバージョン確認

```terminal:troubleshooting.bat
> winver
```

## ポート番号を利用しているプロセス番号特定

```terminal:troubleshooting.bat
REM 一覧
> netstat -ano
REM ポート番号指定
> netstat -ano | findstr 443
```
複合キーと複数カラムのユニークキー指定の違い

レコードを一意制約したいときに、主キーを複数指定する**複合キー**を使う必要がある、と上司から教えてもらったのだが、ユニークキーの複数カラム指定との違いが分からなかったので、調べてみた。

## 複合キーとは
複数のカラムをプライマリーキーに指定し、その複数のカラムでレコードを一意に指定できるキー。

商品番号、商品、色をプライマリーキーに指定した場合

|商品番号(PK)| 商品(PK)             | 色(PK)　            |  在庫数             |店舗|
|:--|:-----------------|:------------------|:------------------ |:--|
|001| 椅子             |              青|        3        |池袋|
|032| 机           |            茶 |       4      |茅ヶ崎|
|101| 本棚            |              白 |        8       |品川|
|332:point_left_tone1:| クッション  :point_left_tone1: |  緑:point_left: |       20      |新宿|
|332:point_left_tone1:| クッション  :point_left_tone1: |  赤:point_left: |       48      |初台|

商品番号332、クッションが同じでも、色が異なればデータの格納ができる。

##ユニークキーとは
同じカラム内に同じデータを格納することができないキー。

商品番号、商品、色をユニークキーに指定した場合

|商品番号(UQ)| 商品(UQ)             | 色(UQ)　            |  在庫数             |店舗|
|:--|:-----------------|:------------------|:------------------ |:--|
|001| 椅子             |              青|        3        |池袋|
|032| 机           |            茶 |       4      |茅ヶ崎|
|101| 本棚            |              白 |        8       |品川|
|332:point_left:| クッション:point_left:|  緑 | 12         |五反田|
|~~332~~:point_left:| ~~クッション~~:point_left: |  赤 |   20      |新宿|


商品番号332、クッションの色が各カラムで既に存在するデータであれば、データの格納はできない。

##まとめ
**複合キーの場合**
PK指定のカラムの値が全て同じである場合、DBに格納できない。

**複数カラムのユニークキー指定の場合**
各カラム内で格納できない値が決まるため、複数のカラムのうちいくつかは同じデータの重複を許してレコードを一意に指定することができない。
FlutterにFirebaseのIn-App Messagingを入れるとiOSビルドが失敗する

FlutterアプリにFirebaseのIn-App Messagingを入れようとして、iOSビルドが出来なくてハマったのでその解決方法をメモとして共有します。

# 環境など

|ツールなど|バージョンなど|
|:--|:--|
| MacBook Air Early2015|macOS Mojave 10.14.6|
|Android Studio |3.6.1|
|Java |1.8.0_131|
|Flutter|1.12.13+hotfix.9|
|Dart |2.7.2|
|Xcode |11.3.1|

# 導入手順

In-App Messagingは、基本的にライブラリを導入するだけで、コーディングはする必要が無いものです。(受け取って標準的な表示をするだけなら)

なので、以下だけでやりました。

## 1.依存関係を追加

Flutter用のパッケージはこちらにあります。
https://pub.dev/packages/firebase_in_app_messaging


```pubspec.yaml
  firebase_in_app_messaging: ^0.1.2
```

pub getして、ビルドしました。

## 2.キャンペーンを作成

Firebaseの以下のページからキャンペーンを作成します。

![inappmessaging.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103886/708e2e1e-71bb-69b9-1dcd-ea794d20281a.png)

「新しいキャンペーンの作成」をクリックすると、以下のような画面になります。

![iam_campagin.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103886/6a1d6b5d-e526-3f80-850b-c6f3796f7e19.png)


画像が必須なので頑張って何か入れてください。
(横向き用に画像が潰れるのはなんとかならないのか・・・)

ところで、In-App Messagingって、まだベータ版なんですね・・・

Androidは、これで基本的には上手くいきます。
私は`Service fetch error: PERMISSION_DENIED: Firebase In-App Messaging API has not been used`というエラーが出てしばらく表示されなかったのですが、`google-services.json`をダウンロードし直してきたら直り、無事表示が出来ました。


# エラー内容

問題は、iOSで表示しようとビルドしたときです。
以下のようにビルドエラーが出ました。

```console
duplicate symbol '_OBJC_CLASS_$_ "FIRIAMDefaultDisplayImpl'"
```

どうやら、以下のパッケージで同じクラス定義がありシンボルが重複しているというエラーのようです。

- FirebaseInAppMessaging
- FirebaseInAppMessagingDisplay

# 解決方法

いろいろググって辿り着いたのが、FirebaseのIssuesページです。

https://github.com/FirebaseExtended/flutterfire/issues/2151

こちらにある、FirebaseとIn-App Messagingのバージョンを強制的に指定することで解決しました。
※ダウングレードしていることになるので、他のFirebaseのパッケージが整合性取れなくなる可能性があります。対応にはご注意下さい。


具体的には、以下のバージョンを強制的に指定することにします。

- Firebase (6.15.0)
- FirebaseInAppMessaging (0.16.0)

### (1)Podfileを編集する
どうするかというと、`Podfile`ファイルを編集します。

```Podfile
# avoiding to duplicate symbol error
pod 'Firebase', '6.15.0'
pod 'FirebaseInAppMessaging', '0.16.0'
```

### (2) `Podfile.lock`を削除

`Podfile.lock`はプロジェクトフォルダの`ios`フォルダ下にあります。

![Podfile.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103886/09bc1b0e-41f8-b897-f378-9fc1f4752a23.png)


### (3) `flutter clean`を実行

```console
$ flutter clean
```

### (4) `pod install`を実行

```console
$ pod install
```

### (5) Flutterでビルド、実行する

これで無事ビルドが通り、メッセージもちゃんと表示出来ることを確認しました。

## 2.修正状況

関連の修正PRは出ているようですので、注視しておくと良いかも知れません。

https://github.com/FirebaseExtended/flutterfire/pull/1957
https://github.com/FirebaseExtended/flutterfire/pull/2701


# In-App Messagingのススメ

Push通知(Firebase Cloud Messaging)と違って、アプリを起動したときにしか表示してくれませんが、Pushよりずっと楽に導入できるので、アプリのアップデートの案内とか、アップデートした後の新機能の紹介とか、アプリを起動した上でのメッセージ表示で十分な場合は、かなりオススメです。

特にiOSの場合、証明書の更新とかも不要になるので、運用的にかなり助かるのではないでしょうか。

と言うことで、頑張ってPush通知を導入するより、In-App Messaging導入、いかがでしょうか？


今回、In-App Messagingを入れることにしたのは理由があって、アプリの強制アップデートのために[Remote Configを使っている](https://qiita.com/kasa_le/items/a7bae1b9aef6dfde2504)のですが、iOS9.3のiPadで、一度読み込んだらその後値を一切再取得してくれないという不具合に気付き、そこで、iOS10未満の端末向けに、最初はPush通知を入れようかと思ったのですが、証明書やらでハードルが高いので、お手軽そうなIn-App Messagingを試してみた、という次第です。

というか、これで、自前の強制アップデートダイアログの表示も不要になりますね。
ナンテコッタイ＼(^o^)／


まあ、まだベータなので・・・というところが、業務で導入するには躊躇うところでしょうか^^;
別で起動したdockerコンテナをdocker composeのコンテナに認識させる

## 紹介する内容
- docker-compose.ymlにないdockerコンテナをdocker composeのコンテナに認識させます
   - docker-compose.ymlはdockerコンテナ2つ立てる設定にしておいて、別でdockerコンテナ立ててdocker-compose psに3つに見える例を見せます


## 結論
### docker composeはdockerコンテナのlabelを基準として仲間を判定している
- 筆者の調査不足かもしれませんが、公式ドキュメントで該当する内容は発見できませんでした。
   - ですが、docker composeのソースコードからlabelが関わっていることを確認しました。
   - https://github.com/docker/compose/blob/4bf623d53da363d576bfb4e57d139df97032f004/compose/project.py#L330 

### Docker Engine SDKsで作業しながら、動的に立てたdockerコンテナをdocker composeに編入したい時に応用できます
- docker composeが立てたコンテナのlabelを確認して、動的に立てる予定のdockerコンテナのlabelを同じくすれば可能です

### labelを同じくしてdocker composeの仲間扱いされたdockerコンテナは一緒にdocker-compose downできます


## 紹介始めます
### ディレクトリ構成
全体ソースコードは https://github.com/cheekykorkind/qiita-example/tree/master/docker-compose/allow-raw-docker-as-compose で確認できます

- 全体図
![allD.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/247584/1f3af233-b7b9-49fe-28cc-e11310f67b79.png)


- 動的で立てるdockerコンテナが使うlabel設定ファイル部分
![labelD.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/247584/23133536-22af-74a0-7466-d9e87cb02308.png)



### まず、docker composeのdockerコンテナがどのようなlabelを持っているか確認します
以下のコマンドでdocker composeで立てたコンテナ名を確認して、labelを確認します。

```
docker ps
docker inspect コンテナ名
```
![inspectCommand.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/247584/0b048de4-93be-e8df-1120-511b4804496d.png)


目標であるlabelは`Config`配下の`Labels`で確認できます。
必要な部分は以下の3行です。後で動的に立てるdockerコンテナのlabel付ける時に使います。

```
"com.docker.compose.oneoff": .....
"com.docker.compose.project": .....
"com.docker.compose.service": .....
```
![inspectLabelPart.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/247584/c7ea6d56-76c5-5977-5830-ef84fc0123eb.png)

https://docs.docker.com/engine/reference/commandline/inspect/

   
### 動的に立てるdockerコンテナのlabelをdocker composeのdockerコンテナと同じくします
上のdocker inspectから確認したlabel中身の3行を持ってファイルを作ります。
`./labels`ファイルになります

```
com.docker.compose.oneoff=False
com.docker.compose.project=allow-raw-docker-as-compose
com.docker.compose.service=compose-postgres11.7
```

### label設定を適用して動的にdockerコンテナを立てます
- `docker run -d --label-file ./labels nginx:1.19.0-alpine`
   - コマンドを説明すると`docker run -d --label-file label設定ファイルパス dockerイメージ名`です
- 同じ動作できるコマンドを追加で紹介します
   - `docker run -d --label com.docker.compose.oneoff=False --label com.docker.compose.project=allow-raw-docker-as-compose --label com.docker.compose.service=compose-postgres11.7 nginx:1.19.0-alpine `
- https://docs.docker.com/engine/reference/commandline/run/#set-metadata-on-container--l---label---label-file


### 例を見せます
1. docker composeがあるデレクトリーに移動します 
  - `cd qiita-example/docker-compose/allow-raw-docker-as-compose`
2. docker composeのコンテナたちをバックグラウンドで起動します
  - `docker-compose up -d`
3. docker composeのコンテナだけあることを確認します
  - `docker-compose ps`
4. docker composeではないdockerコンテナを起動します
  - `docker run -d --label-file ./labels nginx:1.19.0-alpine`
5. 別で起動したdockerコンテナがdocker composeのコンテナに認識されました
  - `docker-compose ps`

![allow-container-as-compose.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/247584/56d13441-a46f-d815-8132-856a5ec09620.gif)
Dockerのお勉強

#はじめに
今回の題材はDockerです。会社の新人研修でLinuxやVMware等の仮想マシンについて学んだので、自分でDockerにも手を出してみようと思い、取り組んでみました。個人的な話でも、仕事でIoT/ネットワーク等のインフラ設計構築を行うので、コンテナ技術は絶対に身に付けたいという思いもあります。なので、今回はDockerの概要をアウトプットしていきたいと思いヤース。

#Dockerとは
Wikipediaより
>Dockerは、コンテナ仮想化を用いてアプリケーションを開発・配置・実行するためのオープンソースソフトウェアあるいはオープンプラットフォームである。 Dockerはコンテナ仮想化を用いたOSレベルの仮想化によりアプリケーションを開発・実行環境から隔離し、アプリケーションの素早い提供を可能にする。

言わずもがなですね。

#仮想マシンとコンテナ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/644352/60215382-0098-42be-df11-eb5a9a024772.png)
これは渋谷のコンテナストアです。行ったことないです。
まあこんな感じです（適当）

仮想マシンとコンテナはよく比較対象として取り上げられることが多いので、振り返ってみます。
###仮想マシン
仮想マシンは、ハードウェアに実際に搭載されているプロセッサやメモリなどの物理的なリソースを細かく分割し、それをグループにして複数の独立したサーバーのように機能させる技術のことです。なので、効率的にハードウェアのリソースを活用することができます。これを実現するソフトウェアがハイパーバイザーと呼ばれるもので、自分はVMwareのESXiを学習しました。

以上のようにコンテナ(Docker)と比較すると、コンテナの方が動きが軽いと言われています。

では、Dockerの概要について触れていきます。


#ライフサイクルについて
まずは、Dockerのライフサイクルの概要についてです。
最初はVirtualBox上にCentOSをインストールして、そこでDockerを扱ってみることにしました。ゴールとしては、ブラウザからコンテナのNginxにアクセスすることです。


<img width="770" alt="スクリーンショット 2020-07-11 16.10.54.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/644352/24ed3c92-7b73-f63b-62e0-e9b5e4766801.png">
DockerHubから使いたいWebサーバーのDockerイメージを取得してきます。
(今回はNginxを使うことにしました。)
取得してきたイメージをもとに、コンテナを作成・起動させ、ポートを設定して、ブラウザからアクセスできるようにします。

"localhost"とブラウザで入力して、以下のnginxの画面が開くようになればOKです。
<img width="612" alt="スクリーンショット 2020-07-07 20.50.45.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/644352/f40d8756-9283-7b65-6436-de41dd36b372.png">

#構成
ここからはDocker Desktop for Macを使って、学習しました。構成としては、以下になります。<img width="770" alt="スクリーンショット 2020-07-11 19.24.00.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/644352/ba917d49-58e6-79b2-2870-419307c6421a.png">


#Dockerfile

上の例では、DockerHubからイメージを取得していましたが、自前でイメージを作成することも可能です。
その場合はDockerfileでイメージを作成します。


>＃step1 ... make Ubuntu Image
FROM ubuntu:latest
＃step2 ... install nginx
RUN apt-get update && apt-get install -y -q nginx
＃step3 ... copy html file
COPY index.html /var/www/html
＃step4 ... expose port no 80
EXPOSE 80
＃step5 ... start nginx
CMD ["nginx","-g","daemon off;"]

こんな次第でDockerfileを記述し、UbuntuやNginxイメージを取得して、HTMLファイルをコピーして、ポートの設定をしたりします。
これをbuildコマンドで実行すると、イメージが作成されます。

ここでは、コンテナの/var/www/htmlに配置したHTMLファイルを表示させることをゴールにしていきます。

#コンテナの生成・起動
イメージを生成したら、いよいよコンテナの生成・起動です。これはrunコマンドで一気に出来ちゃいます。
コンテナ名や、使用するイメージ名を指定して実行します。

コンテナを生成・起動したら、docker execコマンドでバックグラウンドで動いているUbuntuにコマンドを実行して、コンテナが起動していることを確認します。
ここでは、Dockerfileで実行したように、htmlファイルが/var/www/htmlにコピーされていることを確認します。

ポート80でアクセスすると、nginxのポート80にフォワードされ、以下のような画面が表示されれば、OKです。
<img width="793" alt="スクリーンショット 2020-07-11 10.29.29.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/644352/2fe1d09c-a66f-f50c-4822-3e4bcdb5b9fe.png">

試しに、別のポート番号(8080)を設定したコンテナを別で作成して、アクセスすると無事アクセス出来ました。

#終わります
本当はDocker Composeも勉強したのですが、お時間が来たので終わりたいと思います。
お疲れさん。
p5.jsで詰まったこと　【シーンの切り替え方がわからない】

#はじめに
初めまして！Life is Tech!メディアアートメンターのきゃみです！
今回p5.jsで作品を作らなければいけない案件ができたのですが、何個か詰まった点があったのでQiitaにまとめてみました。
今回はシーン切り替え編です！

#背景
p5.jsを使ってVJ映像を作りたいと思いたつも、二次元的な映像と三次元的な映像のシーンの切り替え方がわからず悩んでいたので、記事にまとめてみました。

#考えられるシーンの切り替え手法一覧
僕が実装を考える中で、シーンを切り替える方法が何点か思いついたので、まずはそれについて書いていこうと思います。
特に用途によって有効な手法が違うと思いますので、メリット・デメリットも書いていこうと思います。

###p5のライブララリを使う方法
p5には[SceneManager](https://github.com/mveteanu/p5.SceneManager)というライブラリが公式に存在します。
本日の本題とはずれるので、詳しい書き方とかはReadmeなどをみていただければと思います。
個人的な印象ですが、二次元と三次元が入り混じっている場合この手法は適切ではないです。二次元の座標系が、WEBGL空間だとズレが生じるからです。特に、カメラが動いてしまう場合はもうどうしようもないです。(テクスチャを使ってゴニョゴニョすればいけないことはないのでしょうが、僕は実装できませんでした。)
今回の僕の作品ではShaderを多用していて、かつシーンの数も二個しかなかったのでこれは不採用としました。

###二つのテクスチャを交互に表示する方法

```javascript:doubleTexture.js
let firstTexture;
let secondTexture;

function setup() {
    background(0);
    createCanvas(500, 500);
    firstTexture = createGraphics(500, 500);
    secondTexture = createGraphics(500, 500, WEBGL);
}

function draw() {
    // firstTextureに一つ目のシーンをレンダリング

    // secondTextureに二つ目のシーンをレンダリング

    if (frameCount % 1000 < 500) {
        image(firstSfirstTexturecene, 0, 0);
    } else {
        image(secondTexture, 0, 0);
    }
}
```

などとしてあげると、二つの異なる座標系の画面を交互に切り替えることでシーン切り替えが実現します。
しかし、最初の方法で書いたように、今回はShaderを適用させます。
特に、二つのシーンには同じShaderを適用させたいので、この方法ではコードを冗長化させてしまいます。
というわけでこちらも却下です。今回は、三つ目の方法を採用することにしました。

###一つのテクスチャに対して、書き込む内容を変える
一つだけテクスチャを用意し、条件によって書き込む内容を変えることでシーン切り替えを実現できます。
これはこれでかなりコードは冗長化してしまいますが、複数のシーンに同じShaderを適用させたい人はこれが最適になるのかなと思います。
カメラが動く場合も、二次元と三次元のシーンが入り混じる場合も、次のようにすれば実現可能となります。

```javascript:singleTexture.js
let twoDTexture;
let mainTexture;

function setup() {
    background(0);
    createCanvas(500, 500);
    twoDTexture = createGraphics(500, 500);
    mainTexture = createGraphics(500, 500, WEBGL);
}

function draw() {
    //先にここで二次元のシーンをtwoDTextureにレンダリングしておく

    if (frameCount % 1000 < 500) {
        mainTexture.clear();
        mainTexture.camera(hoge, fuga, hogefuga, 0, 0, 0, 0, 1, 0);
        // mainTextureに三次元のレンダリング
    } else {
        mainTexture.clear();
        mainTexture.camera(0, 0, hogehoge, 0, 0, 0, 0, 1, 0);
        // mainTextureに２次元のレンダリング
        mainTextrue.texture(twoDTexture);
        mainTexture.plane(300);
    }

    // mainTextureを描画
    image(mainTexture, 0, 0);
}
```

ここから、このコードによって懸念点だった部分がどのように解消されているのかを書いていこうと思います。

##二次元と三次元をどのように両立させるか
今回においては、三次元のシーンは通常通りレンダリングし、二次元のシーンはplaneのテクスチャとして描画することにしました。
これにより、shaderを適用させる場合においても、同じテクスチャ内で実装できます。
普通、二次元と三次元では座標系が異なるので、カメラを動かす場合には描画においてズレが生じてしまいますが、シーンごとに別々のカメラ座標を持っておくことによってズレを防いでいます。
plane全体を映すのは、その時のテクスチャのサイズなどで変わると思いますので、環境ごとに自分で試行錯誤しながら設定してもらえればいいかなと思います。

しかし、これでももう一つの問題が生じてしまいます。
やっていただくとわかると思うのですが、シーンを切り替えているはずなのに一つ前のシーンが残ってしまうのです。
これについては、次のやり方で解消しています。

##clear()メソッドを使う
これは、テクスチャに現在描画されている色情報を、全て無に初期化するという機能です。
一見して何の役に立つかわからないこの関数ですが、今回のような場合には効果覿面です。
さっきの方法では、前のシーンのレンダリングが残ってしまっていました。
ゆえに、各シーンのレンダリング直前の部分に、clear()メソッドを入れ込むことによって、直前のシーンを残さずに切り替えを行うことができます。

#最後に
僕が今回作った作品は[こちら](https://editor.p5js.org/kyami/sketches/Y8x66NWMx)になります。
Shaderの内容や、その設定方法についてはまた別の記事でまとめようと思いますので、気になる方はそちらも参照してみてください。
最後まで読んでいただき、ありがとうございました！
Railsでのorderメソッドの説明


<p>ツイート機能やタイムライン機能をwebアプリケーションに実装した時、新しく投稿すると下に表示されてしまいます。</p>


<p>その順序を並び替えるのに「orderメソッド」を使用します。その使い方を説明します。</p>


<h2>orderメソッド</h2><br>

<p>テーブルから取得してきたインスタンス群を並び替えることができるメソッドです。</p>

<p><p>引数に「テーブルカラム名、並び替える順序」を記述して変化させる。</p><br></p>

<h2>書き方例</h2><br>


<!-- wp:loos-hcb/code-block {"fileName":"tweets_controller.rb"} -->
<div class="hcb_wrap"><pre class="prism undefined-numbers lang-plane" data-file="tweets_controller.rb"><code>def index
  @tweets = Tweet.order(&quot;created_at DESC&quot;)
end</code></pre></div>
<!-- /wp:loos-hcb/code-block -->

<!-- wp:paragraph -->
<p>上の記述でツイートを作成順に逆から並べると言う意味になります。</p>
<!-- /wp:paragraph -->

<!-- wp:heading {"level":4} -->
<h4>並び替える順序</h4>
<!-- /wp:heading -->

<!-- wp:list -->
<ul><li>ASC　：　昇順</li><li>DESC　：　降順</li></ul>
<!-- /wp:list -->

<!-- wp:paragraph -->
<p></p>
<!-- /wp:paragraph -->
GCP Cloud Logging で構造化ログを扱う

# 構造化ログとは

下記のように JSON 等のデータ形式で出力されたログのこと。
GCP では JSON 形式のログは自動的にパースされ、検索クエリで利用できるようになり便利。
(Cloud Run では確認済み)
改行も JSON としてエスケープされるので、副次的に複数行のログも扱いやすくなる。

```
{"level": "INFO", "message": "hello\nworld", "timestamp": "2020-07-01 00:00:00"}
```

# Python でログを JSON で出力するサンプル


Pythonでは logger に独自のフォーマッターを設定することでログを JSON 形式で出力することができる。

```
$ python -V
Python 3.8.0
```

```logger.py
import sys
import logging
import json
import traceback


class JsonFormatter(logging.Formatter):
  def format(self, log):
    return json.dumps({
      "level": log.levelname,
      "message": log.getMessage(),
      "timestamp": self.formatTime(log, self.datefmt),
      "traceback": traceback.format_exc() if log.exc_info else []
    })
    

formatter = JsonFormatter(datefmt="%Y-%m-%d %H:%M:%S")

stream = logging.StreamHandler(stream=sys.stdout)
stream.setFormatter(formatter)

logger = logging.getLogger('your-logger-name')
logger.setLevel(logging.INFO)
logger.addHandler(stream)
```

設定した logger を読み込んで利用する。


```sample.py
from logger import logger


logger.info("hello\nworld")
logger.info({"foo": "foo", "boo": "boo"})
```

下記のような JSON 化されたログが出力される。

```
{"level": "INFO", "message": "hello\nworld", "timestamp": "2020-07-01 00:00:00", "traceback": []}
{"level": "INFO", "message": {"foo": "foo", "boo": "boo"}, "timestamp": "2020-07-01 00:00:00", "traceback": []}
```

# Cloud Logging

ロギング -> ログエクスプローラ画面から検索することができる。
ログとして出力したデータは `jsonPayload` に格納されており、クエリ上で検索することができる。

```
resource.type="cloud_run_revision"
jsonPayload.level="INFO"
jsonPayload.message.foo="foo"
```

下記のようにログが検索結果としてでてくる

```
{
  "insertId": "xxxxxxxxxxxxxxxxxxxxxxxx",
  "jsonPayload": {
    "message": {"foo": "foo", "boo": "boo"},
    "traceback": [],
    "timestamp": "2020-07-07 15:33:28",
    "level": "INFO"
  },
  ...
}
```
terraformでforeachを使う方法


## バージョン
```bash

$ terraform --version
Terraform v0.12.24
```

## 変数

- map型で作成

```tfvars.tf
albs = {
  demo = "vamdemic-development-demo-alb"
  dev2 = "vamdemic-development-dev2-alb"
}
```

## foreachで取り扱うソース

- リソース内に`for_each`を使うことで、その要素分ループする
- `each.value`でvariablesで定義した値を使うことができる
- `each.key`でリソース本体を取得
- `data.aws_lb.lb["${each.key}"].arn`のようにすることで、data型で取得したリソースのarnを呼び出している

```wafv2.tf
# Get ALB arn
data "aws_lb" "lb" {
 for_each = var.albs
 name = each.value
}

# WAFv2 assosiation to ALB
resource "aws_wafv2_web_acl_association" "main" {
  for_each = data.aws_lb.lb
  resource_arn = data.aws_lb.lb["${each.key}"].arn
  web_acl_arn  = aws_wafv2_web_acl.example.arn
}
```
【関数】【c言語】 c言語で関数を作る




プログラムを書くときには私達はいつも関数を使っていますよね。
例えばこのコード。

```c:tatoe.c
#include<stdio.h>
int main ()
{
printf("hello world!!");
return 0;
}
```

`printf()`も関数の一つです。~~`return`だってそうですね。~~(2020/07/12)修正
関数って作ってみたりしたいですよね。
でもなんか難しそう...なんて思ってませんか。でも実は簡単な部分もあります。
いますぐ作りましょう。



##環境
 - ubuntu 20.04 LTS


##作る


関数というものを作る練習をしましょう。
戻り値や関数の名前を指定します。

```text:kakikata.c
型名 関数名 (引数)
{
  コード内容
}
```

###引数
引数は関数についてくる数字や文字列のことです。
例えば`printf()`の引数は`""`の中の文字ですね。
これは変数の宣言で表します。


```text:test.txt
あいうえおabcdefg
```

(2020/07/12)修正
`int fileR (const char *filename const char *type)`⇒`int fileR (const char *filename)`、(2020/07/14)修正`return`を追加

```c:kannsuu.c
#include<stdio.h>
#include<stdlib.h>


int fileR (const char *filename)
{
//ファイル読み込みコード
	FILE *fp;
	char str[30];
	fp = fopen(filename,"r");
	if(fp==NULL){
        printf("ファイルオープン失敗\n");
        return -1;
}
    
    while((fgets(str,30,fp))!=NULL)
	{
	
        	printf("%s",str);
        	
        }
	return 0;
}

int main ()
{
	fileR("test.txt");
	return 0;
}
```




これで完成です。

###実行結果

```
あいうえおabcdefg
```
MySQLのダンプファイルをDockerコンテナで復元する

# 概要
コンテナを使うことでローカル環境を汚さず
使い終わったらコンテナごと削除されます。

ダンプファイルはMySQLが提供しているサンプルを使用しています。
[Other MySQL Documentation - Example Databases](https://dev.mysql.com/doc/index-other.html)
使用しているダンプファイル: world database

# 環境
- Docker version 19.03
- MySQL 5.7

### MySQLのコンテナを実行する

```zsh
# コンテナを実行する
$ docker container run --rm --name some-mysql -e MYSQL_ROOT_PASSWORD=password -d mysql:5.7
27b05b9a3337d930941c24e6a4ae507d206619de879e7067ef3855f6bc9710b5

# コンテナが実行されていることを確認する
$ docker container ls --filter "name=some-mysql"
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                 NAMES
27b05b9a3337        mysql:5.7           "docker-entrypoint.s…"   51 seconds ago      Up 49 seconds       3306/tcp, 33060/tcp   some-mysql
```

### ダンプファイルからデータを復元する
```zsh
# ホストにあるダンプファイルからコンテナにあるMySQLにデータを流し込む
$ docker container exec -i some-mysql /bin/bash -c 'mysql -uroot -p"$MYSQL_ROOT_PASSWORD"' < /file/to/path/world.sql
```

### データが復元されているか確認する
```zsh
# コンテナに接続
$ docker container exec -it some-mysql /bin/bash

# MySQLに接続
root@container_id /# mysql -uroot -p$MYSQL_ROOT_PASSWORD -Dworld

# データーベースの確認
mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sys                |
| world              |
+--------------------+
5 rows in set (0.00 sec)

# テーブルの確認
mysql> show tables;
+-----------------+
| Tables_in_world |
+-----------------+
| city            |
| country         |
| countrylanguage |
+-----------------+

# レコードの確認
mysql> select * from city;
+----+----------+-------------+----------+------------+
| ID | Name     | CountryCode | District | Population |
+----+----------+-------------+----------+------------+
|  1 | Kabul    | AFG         | Kabol    |    1780000 |
|  2 | Qandahar | AFG         | Qandahar |     237500 |
...
| 4078 | Nablus | PSE         | Nablus   |     100231 |
| 4079 | Rafah  | PSE         | Rafah    |      92020 |
+------+--------+-------------+----------+------------+

4079 rows in set (0.00 sec)
```

### 実行したコンテナを削除する
```zsh
# コンテナを停止する
$ docker container stop some-mysql
some-mysql

# コンテナが削除されていることを確認する
$ docker container ls --filter "name=some-mysql"
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
```

# 参考
[Docker Hub - MySQL Description](https://hub.docker.com/_/mysql?tab=description)
原油の製油の最適化

## これなに

「[OR-Toolsで学ぶ最適化　【線形計画：製油しようぜ】](https://qiita.com/e-yudana/items/289f49b9fff1167ac26a)」をpandasを使ったモデルで解き直した記事です。

## 定式化

```
変数：原油種類ごと、製品種類ごとの作成量
目的関数：購入費用合計 ー 販売額合計 → 最大化
制約条件
・原油の購入上限
・製品ごと需要の上下限
・製品のオクタン価
```

## Pythonで解く

### データ設定

原油と製品の表を作成

```py
from io import StringIO
from ortoolpy import pd, model_max, lpDot, lpSum

dfoil = pd.read_csv(StringIO("""\
原油,原油_オクタン価,所有量,費用_バレル
R0,99,782,55.34
R1,94,894,54.12
R2,84,631,53.68
R3,92,648,57.03
R4,87,956,54.81
R5,97,647,56.25
R6,81,689,57.55
R7,96,609,58.21"""))

dfprd = pd.read_csv(StringIO("""\
製品,製品_オクタン価,需要下限,需要上限,売価
F0,88,415,11707,61.97
F1,94,199,7761,62.04
F2,90,479,12596,61.99"""))
```

### 変数表作成

変数表は、原油と製品の直積で作成

```py
df = pd.DataFrame(
    [
        [*row1, *row2]
        for row1 in dfoil.itertuples(False)
        for row2 in dfprd.itertuples(False)
    ],
    columns=dfoil.columns.tolist() + dfprd.columns.tolist(),
)
df[:2]  # 先頭2行
```

|    | 原油   |   原油_オクタン価 |   所有量 |   費用_バレル | 製品   |   製品_オクタン価 |   需要下限 |   需要上限 |   売価 |
|---:|:-------|------------------:|---------:|--------------:|:-------|------------------:|-----------:|-----------:|-------:|
|  0 | R0     |                99 |      782 |         55.34 | F0     |                88 |        415 |      11707 |  61.97 |
|  1 | R0     |                99 |      782 |         55.34 | F1     |                94 |        199 |       7761 |  62.04 |


### モデル化＆結果表示

```py
m = model_max(df=df)
for _, dfs in df.groupby("原油"):
    m += lpSum(dfs.Var) <= dfs.所有量.iloc[0]
for _, dfs in df.groupby("製品"):
    m += lpSum(dfs.Var) >= dfs.需要下限.iloc[0]
    m += lpSum(dfs.Var) <= dfs.需要上限.iloc[0]
    m += (lpDot(dfs.原油_オクタン価, dfs.Var) ==
          lpDot(dfs.製品_オクタン価, dfs.Var))
m.solve(objs=["-費用_バレル", "売価"])

dfr = df.pivot_table("Val", "原油", "製品").round(2)
dfr = pd.concat([dfr, dfr.sum().to_frame("計").T])
dfr["計"] = dfr.sum(1)
dfr
```

|    |      F0 |      F1 |     F2 |   計 |
|:---|--------:|--------:|-------:|-----:|
| R0 |    0    |  782    |   0    |  782 |
| R1 |  894    |    0    |   0    |  894 |
| R2 |  465.29 |   30.08 | 135.63 |  631 |
| R3 |  330.04 |    0    | 317.96 |  648 |
| R4 |    0    |  956    |   0    |  956 |
| R5 |    0    |  621.59 |  25.41 |  647 |
| R6 |  689    |    0    |   0    |  689 |
| R7 |    0    |  609    |   0    |  609 |
| 計 | 2378.33 | 2998.67 | 479    | 5856 |

（何故かOR-Tools の元記事とは違いますね）

## モデル化のポイント

- ortoolpyの0.2.36以降で可能です。
- 最大化モデルは`model_max`、最小化モデルは`model_min`で作成します。
    - モデル作成時に、下記の引数にDataFrameを指定すると変数としてVar列を作成します。
        - df：非負連続変数
        - dfb：0-1変数
        - dfi：非負整数変数
- `solve`時に`objs`で列名のリストを指定すると、その列を目的関数の係数として使用します。
    - 列名に「`-`」がついていると、-1倍します。
- モデルにDataFrameが結びついていると、solve後に結果を`Val`列として追加します。

以上
【Vue】配列の追加・削除には注意が必要👮 

[【Vue】オブジェクト追加・削除には注意が必要👮 ](https://qiita.com/_masa_u/items/d87c5aea5ecd12006005)の配列版です。
オブジェクトと同じく、参照するだけなら普通のJSと同だが、要素の追加・削除で嵌るポイントがあった。
既に同様の記事はあるが自分用の備忘録という意味を含めて残すことに。
↓の記事も参考に。

- [Vue.jsは気難しい（配列編）](https://qiita.com/tmak_tsukamoto/items/e303328681f20a036530)
- [リアクティブの探求
](https://jp.vuejs.org/v2/guide/reactivity.html#%E5%A4%89%E6%9B%B4%E6%A4%9C%E5%87%BA%E3%81%AE%E6%B3%A8%E6%84%8F%E4%BA%8B%E9%A0%85)

次のようなVueコンポーネントの`data()`関数で`charas`という空の配列を返すとする。
つまり、このコンポーネントの初期状態ではステートとして`charas`配列が存在することになる。

```js:fuga.vue
// 初期状態のステート
export default {
  data() {
    return {
      charas: []
    }
  }
}
```

## 要素を追加する
オブジェクトでは`$set`を使ったが、配列では追加するときは末尾であれば通常通り`push()`でOKらしい。先頭に追加などは試していないのでわからず。

```js
// いつも通り`push`を使えばOK
this.charas.push('範馬刃牙')
```

### 配列を追加したい
要素をまとめて追加したい場合、既にある配列をステートに追加するという場面はよくあるだろう。
この場合はスプレッド演算子`...`を使って配列を展開した要素を`push()`で追加すればまとめて追加できる。

配列でない場合は`Array.prototype.push`は複数の引数を受け取ることができるので、そのまま渡せば良い。

```js
// 配列を追加する
this.charas.push(...['範馬勇次郎', '烈海王'])
this.charas.push('範馬勇次郎', '烈海王')
```

## 要素を変更する
要素を変更したい時、いつも通りインデックスを使ってしまいたくなるがこれだとリアクティブにデータが反映されない（＝データ更新しても画面（HTML）上に反映されない）。

`splice()`を使う。

構文は`<配列>.splice(<始まりのインデックス>, <変更する要素数>, <変更後の要素>)`と書くとのこと。
（書き方をいつも忘れてしまう）

見ての通り複数個まとめて変更することもできる。

```js:NG
// これはリアクティブにならない（＝ステート変更を行った時にHTMLに変更が反映されない）
this.charas[0] = '範馬勇一郎'
```

```js:OK
// これだとリアクティブになる
this.charas.splice(0, 1, '範馬刃牙')
```

## 要素を削除する
変更のときと一緒で`splice()`を使う。

書き方は`<配列>.splice(<始まりのインデックス>, <削除する要素数>)`
見ての通り複数の要素をまとめて削除できる。

ちなみに戻り値は削除した要素を含む配列で破壊的メソッドとして働く。

```js
// リアクティブにデータを削除
this.charas.splice(0, 2)  // => インデックス0, 1の要素を含む配列が戻り値
```


### 全削除したい

通常通り、`arr.length = 0`のイディオムを使いたくなるが、これだと配列の長さを変える操作なのでうまくいかないらしい。
（一見、動いているようにみえるケースもあったが、Vue作者もそう言っているので使うのはやめた方がよさそう）

```javascript:NG
// これはリアクティブにならない（＝ステート変更を行った時にHTMLに変更が反映されない）可能性がある
this.charas.length = 0
```

要素をまとめて削除できる`splice()`を使う。第二引数に配列の長さを渡せば全削除できる。

```javascript:OK
// これでリアクティブに全削除できる。
this.charas.splice(0, this.charas.length)  // => []
```

### 要素を全て入れ替えたい

配列を一度空にしてからまとめて追加すればよい

```js
// 一旦、全削除して要素を入れ替える
this.charas.splice(0, this.charas.length)
this.charas.push(...['範馬刃牙', '範馬勇次郎', '烈海王'])
```

## 配列自体を削除したい
あまり使うケースは無さそうだが、要素ではなく配列自体を削除したい場合はどうするか？

この場合はオブジェクトと同じで`null`を入れればよいみたい。

```js
// charasを削除する
this.charas = null
```
eslint-plugin-jsx-ally@6.0.3 postinstall: `node ./postinstall.js`エラー解決方法

めちゃくそしょうもないエラーに久しぶりに引っかかったので、戒めのために記事を残しておく

## エラー内容
ReactNative + ExpoのUdemy講座を進めている時にnpm installでライブラリをインストールする場面があり、
講座では
`eslint-plugin-jsx-ally`をダウンロードしろとのことだったので、

以下コマンドを実行
`npm install --save--dev eslint-plugin-jsx-ally`

すると以下のエラーに遭遇

```
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! eslint-plugin-jsx-ally@6.0.3 postinstall: `node ./postinstall.js`
npm ERR! Exit status 1
npm ERR! 
npm ERR! Failed at the eslint-plugin-jsx-ally@6.0.3 postinstall script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR!     /Users/UserName/.npm/_logs/2020-07-11T10_28_15_941Z-debug.log
```

講座を何度も見直しても原因がわからない。

## 解決方法
`eslint-plugin-jsx-ally`→`eslint-plugin-jsx-a11y`
でした。。

動画教材だとコマンドとかをコピペできないので、こう言うことが起こりがち・・。

以下コマンドを実行で無事ダウンロードできました。
`npm install --save--dev eslint-plugin-jsx-a11y`

しょーもないミスに時間取られないようにちゃんとしよ・・。
syntax error, unexpected end of file が出たので原因を探した

使用しているPCはMacbook
エディタはvscodeです。

`syntax error, unexpected end of file `

やったこと
ターミナルで
`php artisan make:controller　~ `
を入力した際に上記エラーが出た

エラーの上に
> In web.php line 20:

が記載されていた

web.phpファイルを中途半端に書いていたため、エラーが出たようだ
原因となっている部分をコメントアウトして
もう一度
`php artisan make:controller ~ `
を打った

`Controller created successfully.`
が出て目的のコントローラーを作成できた。
学習したことを投稿していきます

完全未経験からプログラミングを学習しています。

投稿の目的
1. 自分の理解を深めるため
2. 自分の積み上げを確認するため
3. 自分のような完全未経験の視点から情報を発信することで同じ視点の方の役に立てると考えたから 

Markdown記法もしっかり使い、自分の理解を深めるため、また、学習を始めた頃の自分が知りたかったことを投稿していきたいと思います。

間違い等無いように気を付けますが、何かありましたらご指摘いただけたら嬉しいです。
Reactのthis.props.fooなんて知らないぞ！

# 結論
コンポーネントに渡された入力データを this.props で参照し、render() の中で使用する。

# 内容
完全React初心者の自分が、練習がてらコンポーネントを自作する際に、メソッドの中でthis.props.hogeが使用されているのを見かけ、「なんだこれは、こんなの定義してないのぞ。。。。。」と思ってみたので調べてまとめてみた。

まずは以下のコードを見て欲しい。

```react
class HelloMessage extends React.Component {
  render() {
    return (
      <div>
        Hello {this.props.name}
      </div>
    );
  }
}

ReactDOM.render(
  <HelloMessage name="Taylor" />,
  document.getElementById('hello-example')
);
```
これはとても初歩的な自作Reactコンポーネント。ちなみにこちらは、参考資料に掲載している本家Reactのホームページのチュートリアルから抜粋してきたものである。


```react
  <HelloMessage name="Taylor" />
```
コンポーネントを使用する際、name="Taylor"をコンポーネントに渡している。this.props.nameはこのnameを参照して、コンポーネントの中で  Hello {this.props.name}を表示する。


---
参考資料
[React tutorial](https://ja.reactjs.org)