OmniAICreator/Qiita-1.07M huggingface dataset:
【随時更新】メモ〜Dockerとコンテナ【自分用】

コンテナとは
-
OSの中に別のOSを作成する技術の一つ。

似たような概念として仮想化があげられる。

仮想化とコンテナの違い
-
仮想化ではホストOS上で仮想化ソフトを起動し、その上に立てられたゲストOSの中でプロセスが起動する。

この際、ライブラリ・コマンド・カーネルなどは全てゲストOS上に専用のものが作成され、プロセスからはそちらが参照される。

一方コンテナにおいてはライブラリやコマンドは都度作成されるものの、カーネルに関してはホストOSのものが参照される。

仮想化とコンテナを比較すると前者は`ホストOS>仮想化マシン>ゲストOS>プロセス`という4段階になっているのに対し、後者では`ホストOS>ライブラリやコマンド>プロセス`という3段階となっている。

すなわち仮想化マシンを挟まないために処理が早くなるという特徴がある。

ライブラリ・コマンド・カーネルとは
-
コマンドとは`ls`や`cd`などのターミナルコマンドのことを指す。

ライブラリはプロセスが起動するためのライブラリ群で、Macであれば`Library`ディレクトリに格納されている。

カーネルはコンピュータの基本的な操作を行うための機能を格納したライブラリ群であり（システムコールと呼ばれる）、コマンドに応じて呼び出され処理を行う。

つまり、プロセスが起動した際にはまずコマンドやライブラリが呼び出され、最終的にはシステムコールが実行されることになる。

Dockerとは
-
コンテナを簡単に作成するための機能の一つ。

通常であればコンテナの作成のためにはそのコンテナで使用されるコマンドやライブラリを定義・作成する必要がある。

Dockerと呼ばれるツールをインストールしDockerコマンドを使うことで、コンテナの作成に必要なコマンド・ライブラリの導入を簡単に行うことができる。

DockerHubとは
-
コンテナを作成するのに必要なコマンドやライブラリのセット（OSイメージ）が保管されているリポジトリのこと。

例えばLinuxOSであればCentOSやDebianなどのディストリビューションごとにOSイメージが用意されている。

Dockerfileとは
-
DockerHubから取り寄せたDockerイメージに追加の情報を付与するためのファイル。

例えばDocker上でCenstOSのコンテナを作りその中でphpアプリを走らせることを考えた場合、本来であれば以下の作業が必要になる。

- CentOSのDockerイメージをもとにコンテナを作成する
- コンテナの中に入る
- サーバー(apacheなど）をインストールする
- phpをインストールする
- サーバーを起動する
- 適当なphpファイルを作ってコンテナ上にコピーする
- 8080番ポートにアクセスして動作確認をする

つまり、Dockerイメージにはコンテナの情報しかないため、実際の開発の際には追加で様々なプログラムが必要になりその都度ターミナルを走らせることになる。

Dockerファイルはこれらの一連のコマンドをファイルに記録したものであり、これをイメージ化してそれをもとにコンテナを作成することで必要な手順が全て自動で実行されるようになる。

詳細は以下。

https://qiita.com/keishi04hrikzira/items/c48f6c179317f28e340e

Dockerコマンド達
-

```shell:dockerイメージのpull
% docker pull centos7:centos7
```
```shell:コンテナの作成
% docker run -it --name centos7 centos:centos7 
# M1Macで実行するときには以下のようにプラットフォームの指定が必要
% docker run -it -d --platform=linux/amd64 --name centos7 centos:centos7

# 必要なdockerイメージがpullされていなければ自動ダウンロードが入る
# --name centosは省略可能（コンテナ名をつけているだけ）
# -dはコンテナをデーモン（バックグラウンド）で起動するためのオプション（省略可能）
# 公式は docker run [オプション] --name コンテナ名 [イメージ名][タグ名] [コンテナ起動後に実行するコマンド]
```
```shell:コンテナに入る
% docker exec -it centos7 /bin/bash
# 成功するとプロンプトが以下のように変化する
[root@8d8ca2646e59 /]#
# @以下はコンテナID "/"はディレクトリ、"#"がプロンプト
```

```shell:起動しているコンテナの確認
% docker ps
# 結果
CONTAINER ID   IMAGE            COMMAND       CREATED          STATUS          PORTS     NAMES
8d8ca2646e59   centos:centos7   "/bin/bash"   50 minutes ago   Up 50 minutes             centos7

# -aオプションをつけることで停止中のコンテナも確認できるようになる
CONTAINER ID   IMAGE            COMMAND       CREATED          STATUS          PORTS  　　　　　　    NAMES
8d8ca2646e59   centos:centos7   "/bin/bash"   54 minutes ago   Exited (137) 19 seconds ago   centos7
```

```shell:コンテナの停止
% docker stop コンテナ名またはID
```

```shell:コンテナの再開
% docker start コンテナ名またはID
```

```shell:dockerイメージの作成
% docker commit コンテナ名 イメージ名
>> sha256:33fd144ef6171206b545f23cafe6bb7c877df2386618c53e2e6011e0214b6284
```

```shell:dockerイメージの一覧表示
% docker images
>>
REPOSITORY                    TAG       IMAGE ID       CREATED          SIZE
test1                         latest    33fd144ef617   11 seconds ago   204MB
```
```shell:コンテナの削除
% docker rm コンテナ名もしくはID
```

```shell:Dockerイメージの作成・削除
# DockerfileというファイルからDockerファイルが作られる
% docker build -t dockerイメージ名 dockerイメージのパス

# イメージの削除
% docker rmi イメージ名
```
Javascript カレンダー作成

# はじめに
本稿では下記動画にあるソースコードを解説します。

https://www.youtube.com/watch?v=o1yMqPyYeAo&ab_channel=TraversyMedia

動画にあるカレンダーは、他のライブラリに依存しない実装になっています。
簡単なカレンダーが表示できれば十分、かつ、依存ライブラリを増やしたくない場合などで使えると思います。

**ソースコード**
https://github.com/lashaNoz/Calendar


#カレンダー作成に必要な変数
```javascript
// 今日の日付　EX) 2021/11/24
const date = new Date();
// 月末 EX) 2021/11/30
const lastDay = new Date(date.getFullYear(),date.getMonth() + 1,0).getDate();
// 先月末 EX) 2021/10/31 
const prevLastDay = new Date(date.getFullYear(),date.getMonth(),0).getDate();
// 月初の曜日。0 ~ 6 = 日曜 ~ 土曜　EX) 1 (2021/11/1は月曜日)
const firstDayIndex = date.getDay();
// 月末の曜日。 EX) 2 (2021/11/30は火曜)
const lastDayIndex = new Date(date.getFullYear(), date.getMonth() + 1, 0).getDay(); 
```

# 日付表示
```javascript:calndar.js
// 1.前の月
// firstDayIndexは月初の曜日。EX) 1(月曜)
// prevLastDayは先月の末日。EX) 31 (10/31)
for(let i = firstDayIndex; i>0; --i){
    days += `<div class="prev-date">${prevLastDay - i + 1}</div>`;
}

// 2.今月
const today = new Date().getDate();
for(let i = 1; i<=lastDay; ++i){
    if(i === today){
        days += `<div class="today">${i}</div>`;
    }
    else {
        days += `<div>${i}</div>`;
    }
}

// 3.次の月
const sunday = 6;
for(let i = 1; i<=sunday-lastDayIndex; ++i){
    days += `<div class="prev-date">${i}</div>`;
}
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2087075/90645404-0247-464d-7ea9-6182e9dbb792.png)

# 前月、次月表示ボタン押下時処理
```javascript
document.querySelector(".prev").addEventListener("click", () => {
    // 前月のカレンダーを表示
    date.setMonth(date.getMonth() - 1);
    renderCalendar();
});

document.querySelector(".next").addEventListener("click", () => {
    //　次月のカレンダーを表示
    date.setMonth(date.getMonth() + 1);
    renderCalendar();
});
```

# DOM読み込み完了後にJavascript実行(おまけ)
動画の実装だと、javascriptを読み込むタイミングによってはカレンダーが表示されません。
~~```window.onload```内に処理を定義することで、DOM読み込みが完了した後に処理が実行されます。~~
```DOMContentLoaded``` イベントに処理を定義すると、DOM読み読み込み完了後に処理が実行されます。

```javascript
window.addEventListener('DOMContentLoaded', () => {
    // DOM読み込み完了のタイミングで実行したい処理
    const date = new Date();

    const renderCalendar = function(){
        date.setDate(1);
        ~~~
});
```
Databricks Partner ConnectによるTableauを用いたレイクハウスでの分析

[Building Analytics on the Lakehouse Using Tableau With Databricks Partner Connect \- The Databricks Blog](https://databricks.com/blog/2021/11/22/building-analytics-on-the-lakehouse-using-tableau-with-databricks-partner-connect.html)の翻訳です。

> こちらはTableauのSr. Product ManagerであるMadeleine Corneliによるゲスト記事です。

Databricksは11/18に、お客様がデータ、分析・AIツールを検索し、お使いのレイクハウスに接続できる、パートナーとプレインテグレートされたエコシステムである[Partner Connect](https://qiita.com/taka_yayoi/items/0fd78638a4018284e175)を発表しました。立ち上げ時のパートナーとしてPartner Connectでフィーチャーされ、お客様がお使いの全てのデータを可視化するお手伝いができ、Tableauも嬉しく思っています。

「全てのデータドリブンの企業においては、Tableauのように堅牢なデータ可視化、分析ソリューションを用いることで、人々はビジネスを前進させるデータに容易にアクセス、分析、理解できるようになります。DatabricksのPartner Connectは、より迅速にデータから洞察を導き出すために、お客様のレイクハウスにTableauを接続する際の複雑性を排除します。」とDatabricksのProduct SVPであるAdam Conwayも述べています。

# Databricks Partner Connect:レイクハウスにおける分析

Databricks Partner ConnectにおけるTableauは、ビッグデータとデータサイエンスに対する投資から価値を得るまでの時間を短縮し、お客様がより迅速に洞察に至るお手伝いをします。皆様な分析フローの流れのまま、数秒でユーザーはシームレスにDatabricksのUIからTableauデスクトップに移動することができます。

レイクハウスが目指すのは、全てのユーザーが慣れ親しんでいるツールを使って全てのデータにアクセスできるようにするということです。DatabricksでTableauを使うことで、ビジュアル的な分析を通じて企業のデータの全体像を作成し、お使いのレイクハウスの完全なる価値を解放します。包括的な分析と迅速な洞察によって、[Wehkamp](https://databricks.com/customers/wehkamp)のようなお客様はTableauとDatabricksを一緒に活用し、データドリブンの意思決定を行い、分析とデータスチュワードの間のボトルネックを解消しました。

Partner ConnectでTableauを用いることで、ユーザーはセキュアかつ管理された環境にある適切なデータに容易にアクセスし分析を行うことができます。Tableauは、AskやExplain Dataのようなスマート分析機能や、ビジュアルにデータを探索するための様々な手段を提供します。皆様の組織に価値を提供するためにTableauとDatabricksがどのように動作するのかの詳細に関しては、[こちら](https://www.tableau.com/about/blog/2021/6/how-databricks-and-tableau-customers-are-fueling-innovation-data-lakehouse)を参照ください。
![](https://databricks.com/wp-content/uploads/2021/11/partner-connect-blog-img-4-new-1024x538.png)

Partner ConnectにおけるTableauは、以下のようにしてデータの接続プロセスをシンプルなものにします。

- ユーザージャーニーの簡素化
- ユーザーは分析フローを維持
- すぐに分析に利用できるTableauデータソースをプログラムから作成

# Databricks Partner Connect経由でのTableau起動方法

1. Databricks Partner Connectで、`BI and visualization`の下にあるTableauを選択します。
![](https://databricks.com/wp-content/uploads/2021/11/pc-tableau-2.jpg)
1. Computeエンドポイントを選択し、connectionファイルをダウンロードします。
![](https://databricks.com/wp-content/uploads/2021/11/img-2-1024x584.jpg)
![](https://databricks.com/wp-content/uploads/2021/11/pc-tab-img-3-1024x580.jpg)
1. connectionファイルを開き、TableauデスクトップからDatabricksクラスターに接続するための認証情報を入力します。
![](https://databricks.com/wp-content/uploads/2021/11/pc-tab-img-4-1024x577.jpg)
1. 分析を開始してください。
![](https://databricks.com/wp-content/uploads/2021/11/pc-tab-img-5-1024x637.jpg)

Partner Connectの詳細に関しては[こちら](https://databricks.com/partnerconnect)を参照ください。

### Databricks 無料トライアル

[Databricks 無料トライアル](https://databricks.com/jp/try-databricks)
firebaseのauthenticationで管理側で強制的にユーザのパスワードを再設定する方法（続・firefooはいいぞぉ）

こんにちは。[もぐめっと](https://mogmet.com)です。
![IMG_1058 2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42234/b298bf9e-cdff-f1e8-08b9-e8029d9b3b09.jpeg)
最近本格的なシーズンインに向けて初心者なりに練習を頑張ってます。

本日はパスワードを再設定する方法について、よくある例と、2つの強制的にやる方法を紹介します。

## よくあるパスワード再設定例

よくある例としては[ユーザ側で設定する実装例](https://firebase.google.com/docs/auth/web/manage-users?hl=ja#set_a_users_password)、もしくは[パスワードの再設定メールを送信する実装例](https://firebase.google.com/docs/auth/web/manage-users?hl=ja#send_a_password_reset_email)があげられます。
しかし、問題はユーザがキャリアメールを使っていて、別のキャリアに変えて**メールが届かない**状態と、**パスワードを忘れてしまった**状態のユーザの対応に困ります。
上記の実装だとログインができている、もしくはメールが届くという前提でリセットすることができますが、この問題のパターンだと再設定ができなくなってしまいます。

firebaseのコンソールから再設定という枠もあるのですが、、、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42234/4803b529-879f-87eb-1ee0-aee2c73a2b2c.png)

再設定するメールを送るだけという先程の実装例と変わらないことになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42234/49a50d0d-772a-2e6a-1549-ab731231c60d.png)

## firebase-adminでパスワードを再設定する

ということで問題のユーザにどう対応するかというとfirebase-admin/authにある、updateUserを使うことで強制的にパスワードを再設定できます。

https://firebase.google.com/docs/auth/admin/manage-users?hl=ja#update_a_user

```js
admin
  .auth()
  .updateUser(uid, {
    email: 'modifiedUser@example.com',
    phoneNumber: '+11234567890',
    emailVerified: true,
    password: 'newPassword',
    displayName: 'Jane Doe',
    photoURL: 'http://www.example.com/12345678/photo.png',
    disabled: true,
  })
  .then((userRecord) => {
    // See the UserRecord reference doc for the contents of userRecord.
    console.log('Successfully updated user', userRecord.toJSON());
  })
  .catch((error) => {
    console.log('Error updating user:', error);
  });
```
passwordという項目があるので簡単に再設定ができることを確認できます。
なので更新用に実装をする必要がありますね。

## firefooを使う

実はもう一つもっとお手軽な方法があって、それは先日紹介したfirefooを使うというものがあります。

https://qiita.com/mogmet/items/08a973b510a6f135b5f9

authenticationの一覧を見る機能がありまして、ユーザの詳細を見ると・・・

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42234/b9a3fbb7-410a-7f89-e6f7-17191e877b2f.png)
なんと**パスワードの再設定ができてしまう**ではないか！！
超絶便利です。
よかったら使ってみてください。

## まとめ

パスワードを再設定する方法として**admin.auth().updateUser()を使う**方法と**firefooのauthentication機能**を紹介しました。
パスワードにお困りの方がいたら是非お使いいただければと存じます。

最後に、[ワンナイト人狼オンライン](https://online.1nite-jinro.com/link/blog)というゲームを作ってます！よかったら遊んでね！

https://online.1nite-jinro.com/link/blog

他にも[Camecon](https://camecon.me/)や[Offcha](https://offcha.com/)といったサービスも作ってるのでよかったら使ってね！

https://camecon.me/

https://offcha.com/

また、チームビルディングや技術顧問、Firebaseの設計やアドバイスといったお話も受け付けてますので御用の方は弊社までお問い合わせください。

https://virapture.com/
受験談 AWS Certified SysOps Administrator - Associate 認定

3度目の正直でSOAに合格しました！
この記事は以下アドベントカレンダー2 12/3（金）の記事でもあります。

https://qiita.com/advent-calendar/2021/udemy

# 前提
2021年
8月：SAA [(受験談)](https://qiita.com/h2m_kinoko/items/5179bcb73b6773771f79 "受験談 AWS Certified Solutions Architect – Associate 認定")
9月：SAP
11月：SOA（←今回ココ）

SAA受験談に私のAWSの事前知識・経験が書いてありますが、業務等での経験はほぼゼロです。

# 対象者
- これからSOA他、AWS認定資格の受験をしようとしている方
- Udemyが好きな方
- Udemyって何？なんて読むの？おいしいの？と思われた方

# 結論 Udemy活用しまくり

SAAを最初に受験しましたが、その時の受験談は以下をご覧ください。自分の受験前のAWS知識レベルも記載してありますのでご参考までに。この時もUdemyをめちゃ活用しまくりました。SAA対策講座は比較的多く揃っているのでお勧めです！

https://qiita.com/h2m_kinoko/items/5179bcb73b6773771f79

上記触れていますが、SAA受験時は参考書やBlack Beltなどは一切触れずUdemy講座に絞って勉強しまくりました。セールもいい感じのタイミングでやってるので、どういう講座があるかをあらかじめチェックしておいて、購入はセール期間中にという感じです。

# SAA->SAP->SOA

本記事はSOAの受験談ですが、SAAとSOAの間にSAPを取得してます。
この時ももちろんUdemyの講座を活用。

https://www.udemy.com/share/1020WG3@zP7f7E4bpCYMBAwIm0WMyYQsRxAnnIw1gighAkTPTlZlbnQPNPwXnMNpSz0i72PR-w==/

SAAに比べると流石に講座の数は少ないですが（日本語の講座しか見てません。。英語無理。。）、上記は模擬試験が全5回、1回75問のボリュームです。ひたすら繰り返して理解を深めました。

SAAの受験談でも触れていますが、復習も兼ねて以下を再度通しました。個人的には初めてAWSを触る人にはお勧めです。基本のアーキテクチャを丁寧に解説してくれるので、手を動かしながら理解できると思います。

https://www.udemy.com/share/104nUE3@DRswqaa229HEdub-SDU6_UZlALl7ahfxCj3-d8t-M5faXK1tONUm6GJkr6Sk222d4g==/


# 肝心のSOA

試験詳細は以下に譲りますが、どの認定資格にもだいたい「最低x年のAWS 技術の実践経験」とありますが、気にしません！実務経験を待っていたらいつまでも合格できません笑

https://aws.amazon.com/jp/certification/certified-sysops-admin-associate/


さて。冒頭にも書きましたが3回目の受験でした・・。受験してから次の受験が可能になるまでに2週間空けないといけないのですが、下表の通り立て続けに受験しました。

| 受験日 | 結果 |
|:-:|:-:|
2021-10-16   |不合格   |
2021-11-02   |不合格   |
2021-11-23   |合格   |


正直1回目の時にかなり手応えがあったのですが、微妙に足りなかった・・。2回目は撃沈。3回目は720点の合格ラインを大きく上回る結果に。3回目ともなると、「あー、この問題前も出てたな」というのが分かるようにもなってきました笑
確かに不合格になってからも勉強は続けていましたが、問題によって当たり外れもありそうです（・・・全てをきっちり理解していれば良いのでしょうが）

SOAはC02となり、ラボという実際にAWSコンソールを操作する試験が追加されています。ちなみに受験1回目のラボ試験と受験3回目のラボ試験は一部同じような問題が出てました。ラボ自体の問題はUdemyの講座を勉強する過程でコンソールの操作にある程度慣れておけば、問題文に沿って操作してなんとなか解ける気がします。

それよりも知識問題に苦戦しました。Udemyは以下の講座を活用。模擬問題4回分、1回70問、合計280問ありますので、ひたすら繰り返す形で勉強しました。3度目となると心も折れそうになりましたが、ここまできたからには記憶が新しいうちにとも思い。

https://www.udemy.com/share/102LMC3@6t5hqDOhMi_4U51NlD0qAj9d-wMjsPeP9dsaJ3RUJ1kmwKXvJmiQqGdmRluecgNGkQ==/

# Udemy模擬試験活用時のアドバイス
Udemyの模擬試験講座は、システム上70問など全問解答してから答え合わせをするフローになってます。よくレビューや他の学習談の記載を見ると、「一問一答の形だったら嬉しい」とありますが、私の場合はブラウザ2つ開いて問題のページと解答のページを交互に見ながら進めてました。これで一問一答形式で進められますので、個人的にはお勧めです。



# ということで

「Udemyの講座=>わからない問題や理解が浅い言葉などはスプレッドシートに移して理解を深める」、このサイクルをひたすら回して回して回して・・3回目にして・・SOAも無事に合格できました。

SOA=>SAP=>SOAときて、次はどうしようかなと思っているのですが、Udemyに講座があるかな？で決める気がします笑
自分のスタイルを確立することをお勧めしますが、これからCloud PractitionerやSAAを受けてみようかなという方は、きっとUdemy講座にお世話になることと思います！
Udemy講座ドリブンでいきましょうー！

# 更新

次は結局SCSを受験＆取得しました！

https://qiita.com/h2m_kinoko/items/20f06a746ab15540cd37
STM32L010とシリアルで「HELLO ...」表示 (VSCのCubeIDE)HAL



1.SCLとSDAを接続、プルアップも忘れずに
2.電源の接続
3.下記のソースコードを書き込む
4.コンパイル実行で表示されたら終了
5.おわり

x PlatformIOと言うらしいが超ムズ(以下省略)(誰かに手伝ってもらいましょう?)
x cubemxでnucleo-l011を選択
x vscでnucleo-l011を選択

目的
シリアルのテスト

Seral_Test_010_1内をいろいろ適当にコピー


https://os.mbed.com/users/caa45040/code/f303_h_p1/


参考



https://qiita.com/amutou/items/f521bdbf616b5ef4cf5d



![o_con107.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/879d602c-4b85-d95c-b4a6-786bee425529.jpeg)


![o_con106.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/013d98aa-a60b-e3cf-9e26-6ae5e339ffdd.jpeg)



![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/ed408d27-1f65-b318-7d85-99b8bb9bb2e7.png)




主なソース while内 13は、hello..の長さ




```c++



    HAL_UART_Transmit(&huart2, (uint8_t *)"hello world\r\n", 13, 10);

    HAL_Delay(500);





```
PHPフルスクラッチでWebアプリ作成

# はじめに
マイペースに開発を進める予定です。
記事を書き次第、追記予定となります。
また、デザインは全くと言ってもいいほどつけないと思いますので、ご理解いただけると嬉しいです。

# 経緯
気ままにWebアプリをフルスクラッチで実装しようと思ったので始めました。
また、どうせならアウトプットしようと記事にし始めました。
(MarkDownの勉強もできるし…)
# どんなものを作るか
詳しくは決めていないがバイトのシフト管理アプリを作ろうと考えています。
店長が管理者となり、従業員がシフトを提出して店長がシフトを作成する的な…

# 開発環境
* Ubuntu 20.04.3 LTS
* PHP 8.0
* MySQL 8.0
* Git

※今後随時更新予定

# 記事一覧
### COMMING SOON...
Android ダークモード コードで判定

### 内容
* コードでダークモード判定をする

### 環境
* 今回の内容を実践した私の環境です。

|      |      |
| ---- | ---- |
|  macOS Monterey  |  12.0.1  |
|  Android Studio  |  Chipmunk 2021.2.1 Canary 4  |

### 結論
* 下記のコードにより、ダークモード・ライトモード判定ができます！

```kotlin:judgeMode.kt
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
    // SDKのバージョンがR以降である場合にダークモード設定が導入されたため、それを判定する
    if (context.theme.resources.configuration.isNightModeActive) {
        // ダークモードの場合にこのスコープに入る
    }
}
```
Angular 環境構築と基本コマンド

# Angularとは

- Googleが開発したプログラミング言語
- AngularJs(1.x)とは別物
- TypeScriptベースで作られている
- HTMLとTypeScriptでSPAを開発するためのプラットフォームであり、そしてフレームワークである 

# Angularの環境構築

#### node.js
node.jsが必要です。
React入門でやった[こちら](https://qiita.com/yokowake12345/items/3929af275e1b6b0397a2)を参考にインストールしてください。

#### Angular CLI

Command Line Interfaceの略でしょうか。

Angularアプリのプロジェクト生成や実行などが行えるコマンドラインツールをインストールします。

```
npm install -g @angular/cli
```

インストールが完了したら、下記コマンドを実行しインストールが正常に完了していることを確認します。

```
ng version
```

こんな風に表示されると思います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/559029/bb7afaeb-baf4-8431-a053-18e4efc97aca.png)



#### VSCode

[ここからダウンロード](https://azure.microsoft.com/ja-jp/products/visual-studio-code/)
してください。

日本語化などググるとすぐ情報がたくさん出てきますので、こちらでは説明は省きます。


# プロジェクトの作成

```
ng new プロジェクト名
```

# 起動確認

作成したプロジェクトへ移動して下記コマンドを実行します。

```
ng server --open
```

こんな画面が出たらOKです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/559029/439ab7f6-3575-c4e5-9b81-206c03d8b109.png)

# ちょっとだけ

index.htmlのapp-rootはapp-component.tsのselector部分と紐づいています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/559029/2ac00264-9c42-b84e-52f1-de63669e018d.png)

# Component作成コマンド

```
ng g component コンポ名
又は
ng generate component コンポ名
```

# AppRoutingModuleの追加

```
ng generate module app-routing --flat --module=app
```

# メモ

- StackBlitzとは
- Angularのコア、共有モジュール
Pythonの自動インストール手順（Windows）


## 概要
Windows環境へのPythonインストールを行う場合は主に下記の4つから選ぶ場合が多いと思う。

1. 通常のインストーラー
2. Microsoft ストアパッケージ
3. nuget.org パッケージ
4. 埋め込み可能なパッケージ

今回は1の通常インストーラーのインストール作業を自動化したいので調べたら公式で
起動オプションにより色々できるとのことだったので家訓してみた話

## 手順
### インストーラーの取得
https://www.python.org/downloads/
公式サイトから入れたいバージョンのインストーラーを取得
今回は「python-3.10.0-amd64.exe」

### インストールの設定内容ファイル「unattend.xml」の記述
unattend.xmlは**インストーラーと同じ階層に配置**
このファイルの記述が間違っているとexeがちゃんと動かずに無音で終了する
設定内容は公式ページにまとまっている

https://docs.python.org/ja/3/using/windows.html#installing-without-ui

``` xml
<Options>
    <Option Name="InstallAllUsers" Value="no" />
    <Option Name="Include_launcher" Value="0" />
    <Option Name="Include_test" Value="no" />
    <Option Name="SimpleInstall" Value="yes" />
    <Option Name="SimpleInstallDescription">Just for me, no test suite</Option>
</Options>
```
（"yes" == "1", "no" == "0" で書き換えても良い）

XMLファイルにせずにコマンドの後ろにオプションとして全部連ねれば適用されるが好きな方で

```bat
python-3.9.0.exe /quiet InstallAllUsers=1 PrependPath=1 Include_test=0
```

### インストーラー実行
（どれも管理者権限の確認ダイアログは表示される）
#### 引数なし
通常のGUIインストーラーが表示されGUI操作してインストール

```bat
python-3.10.0-amd64.exe
```

#### 引数：/quiet
インストール内容は unattend.xml に依存

```bat
python-3.10.0-amd64.exe /quiet
```

#### 引数：/passive
動作結果は/quietと同じこっちではインストーラーの進捗表示が出る

```bat
python-3.10.0-amd64.exe /passive
```

#### 引数：/uninstall
アンインストールする

```bat
python-3.10.0-amd64.exe /uninstall
```

## まとめ
インストール手順をコマンドで定型化し、ミスが発生しにくい状態にまとめてプログラマー以外のチームなどに展開するなどで使えそう
PostgreSQLで"rails db:create"でDB作成しようとしたら"connection to server on socket "/tmp/.s.PGSQL.5432" failed: No such file or directory"となった

#問題
タイトル通り、postgresqlでrailsアプリのDB作成を試みると、`connection to server on socket "/tmp/.s.PGSQL.5432" failed: No such file or directory`とエラーを吐かれた。

#状況

postgresqlは`brew install`で最新バージョンをインストールしている。

#原因

下記コマンドでログを見てみる。

```
postgres -D /usr/local/var/postgres
```

すると、

```
% postgres -D /usr/local/var/postgres        
2021-11-24 02:00:01.120 JST [36758] FATAL:  database files are incompatible with server
2021-11-24 02:00:01.120 JST [36758] DETAIL:  The data directory was initialized by PostgreSQL version 13, which is not compatible with this version 14.1.
```

互換性がないと言う旨のエラーが出力。

つまり、インストールしたpostgresqlのバージョンが14.1なのに対し、macPCにインストールされているpostgresのデータディレクトリのバージョンは13なので、互換性がないですよ、と言われている。

#解決策
データディレクトリを一旦削除してから、再度posgreをインストール。


まずはデータディレクトリを削除。

```
rm -rf /usr/local/Cellar/postgresql/14.1
```
※場合によっては`sudo`をつけた方がいいかも。


homebrewでインストールした、postgresqlをアンインストール。

```
brew uninstall --force postgresql
```


からの、インストール!!!

```
brew install postgresql
```

データディレクトリの作り直しもしておきましょう。

```
initdb /usr/local/var/postgresql
```

インストールされているか確認して、

```
% psql --version
psql (PostgreSQL) 14.1
```

postgresqlを起動。

```
brew services start postgresql
```


`rails db:create`をする。

```
% rails db:create
Created database 'XXX_development'
Created database 'XXX_test'
```

無事、DB作成できました。
画像スクランブル技術をPythonで実装

#下準備
以下のライブラリを使用する

```
import cv2
import random
```

まずはお目当ての画像を2値化しよう.画像のパスをpathとして

```
#原本の画像読み込み
img = cv2.imread("path") 
#画像の白黒化
img_gray = cv2.imread("path", 0)
#画像の2値化
threshold = 160
ret, img_2 = cv2.threshold(img_gray, threshold, 255, cv2.THRESH_BINARY)
```

ここでしきい値は160としたが各自調整して欲しい.色の分散を参照して自動調整する技術も存在する.

#暗号化
ここからnumpyを使う

```
import numpy as np

height = 440
width = 1080
img_onlyblack = np.zeros((height, width, 1))

```

画像のサイズは縦440,横1080としたが,これも各自処理したい画像のサイズをそれぞれ2倍すればよい.
まず黒いだけの画像をひとまず生成した(これは使わない).
次にシード値とも言える画像を生成しよう.これが一枚目の暗号,つまり二つある鍵のうちの１つめの鍵である.

```
img_seed = np.zeros((height, width, 1))

for y in range(0,220):
  for x in range(0,540):
    if (random.randint(0,1) == 0):
      img_seed[2*y][2*x] = 255
      img_seed[2*y][2*x + 1] = 255
    else:
      img_seed[2*y + 1][2*x] = 255
      img_seed[2*y + 1][2*x + 1] = 255
```

次に2枚目の画像を生成しよう.計算方針は

1.原本の画像の一点を参照
2.その点が黒ならば一枚目の画像の対応する点を反転して出力
3.そうでなければそのまま出力
である

```
img_crypt = np.zeros((height, width, 1))

for y in range(0,220):
  for x in range(0,540):
    if (img2[y][x] == 0):
      if (img_seed[2*y][2*x] == 0):
        img_crypt[2*y][2*x] = 255
        img_crypt[2*y][2*x + 1] = 255
        img_crypt[2*y + 1][2*x] = 0
        img_crypt[2*y + 1][2*x + 1] = 0
      else:
        img_crypt[2*y][2*x] = 0
        img_crypt[2*y][2*x + 1] = 0
        img_crypt[2*y + 1][2*x] = 255
        img_crypt[2*y + 1][2*x + 1] = 255
    else: 
      img_crypt[2*y][2*x] = img_seed[2*y][2*x]
      img_crypt[2*y][2*x + 1] = img_seed[2*y][2*x + 1]
      img_crypt[2*y + 1][2*x] = img_seed[2*y + 1][2*x]
      img_crypt[2*y + 1][2*x + 1] = img_seed[2*y + 1][2*x + 1]
```

#出力結果
![waseda_crypt_1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2124333/aff382d2-31ff-d9a7-c7d7-7d340481ef38.jpeg)

![waseda_crypt_2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2124333/48df2146-20ce-0383-1bea-1210b6af3a57.jpeg)

この暗号の具体的な使い方を示すためここではあえて版権フリーでない画像を使用した.よって元の画像を掲載することはできない.気になる人は二枚の画像をダウンロードして高速で切り替えてみよう.目の錯覚で元の画像が見えるはずである.または白い部分を透過して重ねてみても良いだろう.

自分で生成した画像がうまくいってるかどうか?どんな感じになったかを確認するには次を実行すると良い

```
img_lor = np.zeros((height, width, 1))

for y in range(0,440):
  for x in range(0,1080):
    img_lor[y][x] =255

for y in range(0,440):
  for x in range(0,1080):
    if (img_seed[y][x] == 0) or (img_crypt[y][x] == 0):
      img_lor[y][x] = 0

cv2_imshow(img_lor)

```

#まとめ
ここでは画像スクランブル技術をPythonで実装した.この技術によって版権フリーでない画像も掲載できてしまうのである.
ArcGISのベクタータイルパッケージ（vtpk）の中身

## はじめに
ArcGISでベクトルタイルをどのように消費しているか考える際の参考に、vtpkパッケージの中身を見てみました。
どこかのQ＆Aでtpkはただのzipファイルと書いてあったので、vtpkもただのzipファイルだろうと考えて調べてみました。

## つかったもの

* ArcGIS Pro (2.6)で作ったvtpkファイル
* 作業環境はWindows 10

## 手順
作成されたベクトルタイルパッケージの拡張子（.vtpk）を.zipに変更します。そのあと、zipファイルを解凍して中身を見ます。（ここではvtpkの作成については触れません。ArcGIS Proなどで作成できます。）

## 結果
解凍されたフォルダ（vtpkのファイル名）の中には、esriinfoというフォルダとp12というフォルダがありました。

#### esriinfo
esriinfoの中には、thumbnail/thumbnail.pngという画像（300×200 px）と、item.pkinfoとiteminfo.xmlというファイルが入っていました。画像以外のファイルはテキストエディタでみることができました。
![2021-11-23-02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/679143/2e7f4ec5-5407-3500-3a93-d38508839007.png)


#### p12
p12の方には、イメージとするとVectorTileServerでホストされるようなコンテンツが入っていました。具体的にはresources、tile、tilemapという3つのフォルダと、metadata.jsonとroot.jsonが入っていました。
![2021-11-23-03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/679143/a904bf89-2abc-a1e6-e7c7-3dbb872484c6.png)

resourcesフォルダの中には、fonts、info、sprites、stylesのフォルダがあって、それぞれVectorTileServerから提供されているような内容のファイルが置いてありました。

tileはベクトルタイルそのものがおいてあるところのようですが、L00、L01というようにズームレベルごとにフォルダがあり、それぞれのズームレベルの中に一つR0000C0000.bundleというファイルがありました。pbfファイルが並んでいるわけではないんですね。

tilemapフォルダにはroot.jsonが一つだけありました。ArcGIS REST APIではズームレベルや範囲を指定してtilemapをリクエストしているので、このroot.jsonから生成しているのだろうと想像します。

## まとめ
vtpkの中身を確認しました。VectorTileServerの持っているであろう内容と近いのではないかという感想を持ちました。
また、vtpkの中でのベクトルタイルの持ち方（ズームレベルごとのbundleファイル）も確認できました。このbundleファイルはesriさん独自のものなのか、それとも[mbtiles](https://docs.mapbox.com/help/glossary/mbtiles/)形式のようなのかはまだわかりません。

## おまけ（小ネタ・vtpkのダウンロード）
ArcGIS Onlineからvtpkをダウンロードしたいとき、ダウンロードボタンを押すと自動的にdownloadフォルダにダウンロードが始まってしまいます。時にこれを何とかしたいときがあります。vtpkは数十GBになるものもありますので、PowerShellでのダウンロードの小技メモしておきます。

* ArcGIS Onlineを見ているときにF12（Google Chromeの場合）を押して、そのあとダウンロードボタンを試してみてvtpkのダウンロードパスを確認しておく。
* PowerSchellでファイルを保存したいディレクトリに移動。
* Powershellでダウンロードのコマンドを以下の通り実行。

```
curl.exe -o filename.vtpk -C - --retry 100 https://download-url.sample.abc/arcgis/sharing/rest/content/items/..../data
```

-C オプションは最初の時はなくても大丈夫です。ダウンロードを途中で止めて（止まって）再開したい時に使います。
(But, I saw "curl: (33) HTTP server doesn't seem to support byte ranges. Cannot resume.")
MySQL 備忘録

##CREATE DATABASE
DB「database_sample」を作成する例

```sql
DROP DATABASE IF EXISTS database_sample;
CREATE DATABASE database_sample COLLATE utf8mb4_ja_0900_as_cs_ks;
```

## CREATE TABLE
TB「housework_history」を作成する例

```sql
USE `house_work`;

-- 家事履歴のテーブル
DROP TABLE IF EXISTS `housework_history`;
CREATE TABLE `housework_history` (
  `history_id` int(5) NOT NULL AUTO_INCREMENT,
  `lasttime_worksdate` DATETIME DEFAULT CURRENT_TIMESTAMP,
  `flag_nexttimecomp` BIT(1) default 0,
  `works_id` int(5),
  `user_id` int(5),

  PRIMARY KEY (`history_id`),
  FOREIGN KEY works_id(`works_id`) REFERENCES housework_works(`works_id`),
  FOREIGN KEY user_id(`user_id`) REFERENCES housework_users(`user_id`)
  
) COLLATE utf8mb4_ja_0900_as_cs_ks;
```

##カラムの定義で現時刻をデフォルト設定する
```
`列名` 　　　　　　　型       デフォルト 現時刻,
`lasttime_worksdate` DATETIME DEFAULT CURRENT_TIMESTAMP,
```
##FOREIGN KEY（外部キー制約）とは
```
　外部キー    インデックス名 列名    参照先     テーブル名      列名
  FOREIGN KEY works_id(`works_id`) REFERENCES housework_works(`works_id`),
  FOREIGN KEY user_id(`user_id`) REFERENCES housework_users(`user_id`)
```
####→データを追加・更新する際、他テーブルの特定の列の値しか指定できないようにするもの。
##JOIN
####→テーブルどうしを結合する際に使う命令。
```
SELECT
    A.lasttime_worksdate,
    C.category_name,
    B.housework_name,
    B.interval_day,
    DATE_ADD(A.lasttime_worksdate, INTERVAL(B.interval_day)DAY) AS nexttime_houosework,
    D.user_name
FROM
    housework_history AS A 
    INNER JOIN housework_works AS B 
        ON A.works_id = B.works_id 
    INNER JOIN housework_category AS C 
        ON B.category_id = C.category_id 
    INNER JOIN housework_users AS D 
        ON A.user_id = D.user_id;
```
##外部キーエラー
```sql
FOREIGN KEY `category_name`(`category_name`) REFERENCES `housework_category`(`category_name`)
```
|エラー内容|原因|備考|
|----|----|----|
| Referencing column  and referenced column in foreign key constraint  are incompatible|FOREIGN KEY側とREFERENCES側の指定したキーの型が違う。|【例】VARCHARとINT|
WASログまとめ 

WASのログローテーション

１．JVMログ
SystemOut.log SystemErr.log
任意で設定できます。
※不思議だが23時にローテーションされる。
※24時にしているんだけど。。。
※画像はファイルサイズから時間にデフォルトから設定変更している。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2291303/1d8dd4a7-2697-7e5a-aff3-eed7e4fd6c49.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2291303/58cb8438-446f-4543-2f6d-8d48f862ef48.png)

wsadminで設定したい方へ
https://qiita.com/XKYUXSOX/items/425849b6468e8f9dbb51

２．プロセスログ
ログローテーション なし
そのため、運用スクリプトをでコピーして/dev/null運用かなぁと思います。
mvできたっけ？？
native_stdout.log
native_stdout.log
以下の対応を行うとnative_stderrに出力することもできます。
※現在はデフォルトでは、verbosegcログに出力されます。

https://www.ibm.com/support/pages/was-traditional-v90%E3%81%AEfixpack3-%E4%BB%A5%E4%B8%8A%E3%81%A7%E5%86%97%E9%95%B7%E3%82%AC%E3%83%BC%E3%83%99%E3%83%83%E3%82%B8%E3%83%BB%E3%82%B3%E3%83%AC%E3%82%AF%E3%82%B7%E3%83%A7%E3%83%B3%E3%83%BB%E3%83%AD%E3%82%B0%E3%81%AE%E5%87%BA%E5%8A%9B%E3%81%8C%E3%83%87%E3%83%95%E3%82%A9%E3%83%AB%E3%83%88on%E3%81%AB%E3%81%AA%E3%82%8A%E5%87%BA%E5%8A%9B%E5%85%88%E3%81%8C%E5%A4%89%E6%9B%B4

３．診断ログ
trace サイズでやってもいいのかも 5MBから20MBくらいがよいのでは。
ローテーション日数も決めれます。
デフォルト
20M
5世代

４．IBM保守ログ
activety.log
ローテーション ：サイズでの循環ログ。
設定できるのはどのサイズでローテーションするかだけ。


５．ffdcログ
自動的に7日間で削除されます。

https://www.ibm.com/docs/ja/was-zos/8.5.5?topic=SS7K4U_8.5.5/com.ibm.websphere.nd.multiplatform.doc/ae/ctrb_ffdclogs.html
AtCoder B - Power Socket 解説


ソケットの数は電源タップ×数で求められる。
また、ソケットはタップを1つ使うごとに1つ消費される。
ソケット数がbを上回った時のタップの数が答えになる。

上記を理解したがコードに落としこめず。


```python
a,b=map(int,input().split())
for i in range(20): # iを電源タップの数とする
    socket=i*a-(i-1) # 未使用の差込口=電源タップの数×A個口の電源タップ1つ-(電源タップの数-1)
    if socket>=b: # 電源タップの数が未使用の差込口Bの値を超えたとき
        print(i) 
        break
```




参考
https://atcoder.jp/contests/abc139/submissions/27460318

競プロ系の記事はgithubに移行予定。
Ubuntu20.04にAzure開発環境をインストールする


# はじめに

Ubuntu 20.04にAzure用の開発環境をインストールした際の手順です。

# 環境

動作環境は以下の通り。

```bash:Ubuntu
$ cat /etc/os-release 
NAME="Ubuntu"
VERSION="20.04.2 LTS (Focal Fossa)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 20.04.2 LTS"
VERSION_ID="20.04"
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
VERSION_CODENAME=focal
UBUNTU_CODENAME=focal
```

# 手順

## インストール

Ubuntu 20.04(LTS)では、本記事執筆時点で .NET Core 3.1 と.NET 5をサポートしています。

https://docs.microsoft.com/ja-jp/dotnet/core/install/linux-ubuntu#supported-distributions

.NET Core 3.1 と.NET 5を両方ともインストールしましょう。

### パケージリポジトリの追加

パッケージ リポジトリを追加します。

```bash
wget https://packages.microsoft.com/config/ubuntu/20.04/packages-microsoft-prod.deb -O packages-microsoft-prod.deb
sudo dpkg -i packages-microsoft-prod.deb
rm packages-microsoft-prod.deb
```

### .NET SDKの追加

.NET SDK をインストールします。

```bash
sudo apt-get update; \
  sudo apt-get install -y apt-transport-https && \
  sudo apt-get update && \
  sudo apt-get install -y dotnet-sdk-5.0 dotnet-sdk-3.1
```

### ランタイムの追加

ランタイムをインストールします。

```bash
sudo apt-get update; \
  sudo apt-get install -y apt-transport-https && \
  sudo apt-get update && \
  sudo apt-get install -y aspnetcore-runtime-5.0 aspnetcore-runtime-3.1

sudo apt-get install -y dotnet-runtime-5.0 dotnet-runtime-3.1
```
入門Power Automate Desktop：第零話「業務で使える？Power Automate Desktop」

# Power Automate Desktopとは
名前だけは聞いたことがある人も多いと思います。
Microsoftが提供している自動化ツールの名称です。
Power Automateは「Power Platform」の一つで、下記4つのソフトウェアが存在してます。

https://powerplatform.microsoft.com/ja-jp/

| 名称 | 説明 |
| --- | --- |
|Power Automate|WebやWindows操作を様々なトリガで自動操作させるツール|
|Power BI|データ分析ツール|
|Power Virtual Agents|チャットボット作成ツール|
|Power Apps|コーディング不要のアプリ作成ツール|

Power Automate DesktopはこのPower Automateのデスクトップ操作に特化したツールを指します。

# 何故今Power Automate Desktop？
最大の理由はWindows11で標準搭載されるからです。
Microsoft製品なので開発現場での導入を断られることは少ないと思いますが、OSにプリインストールされていれば敷居はさらに下がります。
開発現場にWindows11がやってくるのは当分先ですが、今のうちに慣れておけばどんな現場でも自動化を簡単に導入できるようになります。

# 具体的に何ができるのか？
一言で言えば「何でもできます」
それだとイメージできないので簡単な例を挙げます。

| 要素 | 具体例 |
| --- | --- |
|WEB操作|WEBサービスへのログインや画面操作、情報抽出など|
|GUI操作|WindowsのGUIアプリの画面操作、文字入力やボタン押下など|
|Windows操作|ファイルやフォルダ作成、印刷やスクリーンショットの撮影。<br>またキー入力やクリック操作など|
|スクリプト実行|DOS・JS・Pythonスクリプトを実行|
|HTTP操作|WEBサービスへのREST操作|
|Excel操作|Excelの基本的操作|
|PDF操作|PDFからの画像や文章の取得|
|OCR操作|画面上からのテキスト取得|
|Windowsサービス操作|Windwosサービスを起動や停止操作など|

# デメリットや弱点は？
- Power Automate Desktop単体だと時間起動やSlack通知を検知して起動～は行えません。
<br>トリガ関係はPower Automateが担っているので、Power AutomateからPower Automate Desktopを呼び出す必要があります。
- Power Automate Desktopで作成したフローは無料版だと他人に公開することが出来ません。
<br>エクスポート機能は無いのですが、フローをコピーすると以下の文字列が取得でき、それをペーストすることでフローをコピーすることは可能です。
<br>(素直にエクスポート機能つけてくれれば良いのに。。。)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/587410/edb8a47a-07dc-454b-0dcc-f068ed24bc2f.png)
Rustで動的に変化する複数の非同期処理を待つ

__まとめ__

* `tokio::select!` は、 コンパイル時に既知な非同期処理にしか利用できない。
* 動的に変化する非同期処理を待つには、[tokio_stream::StreamMap](https://docs.rs/tokio-stream/0.1.8/tokio_stream/struct.StreamMap.html) を使う。
* 合わせて、 [tokio_stream::wrappers::ReceiverStream](https://docs.rs/tokio-stream/0.1.8/tokio_stream/wrappers/struct.ReceiverStream.html) を使うと簡潔に書ける。

***

### tokio::select! の 使用例

Rustでは、`tokio::select!`を使うことで、複数の非同期処理のうちから、最初の完了を待つことができる。 [参考](https://zenn.dev/magurotuna/books/tokio-tutorial-ja/viewer/select)


例えば、次のようなコードである。

```rust:select.rs
use tokio::sync::mpsc;

#[tokio::main]
async fn main() {
    let (tx1, mut rx1) = mpsc::channel::<usize>(10);
    let (tx2, mut rx2) = mpsc::channel::<usize>(10);

    tokio::spawn(async move {
        tx1.send(1).await.unwrap();
        tx1.send(2).await.unwrap();
    });

    tokio::spawn(async move {
        tx2.send(3).await.unwrap();
        tx2.send(4).await.unwrap();
    });

    loop {
        // tokio::select!で、rx1.recv() と rx2.recv() の2つの非同期処理を待つ。
        // 手抜きのためbreak処理は省略。
        tokio::select! {
            val = rx1.recv() => {
                println!("recv 1, {:?}", val);
            },
            val = rx2.recv() => {
                println!("recv 2, {:?}", val);
            }
        }
    }
}
```

しかしながら、`tokio::select!` は、コンパイル時に、同時に待ちたい非同期処理(上記例では `rx1,recv()` と `rx2.recv()` )がわかっている必要がある。
言い換えると、 ある条件時のみ (`rx2.recv()`) を待ちたいといった場合には `tokio::select!` は利用できない。

これを解決するには、 [tokio_stream::StreamMap](https://docs.rs/tokio-stream/0.1.8/tokio_stream/struct.StreamMap.html) か、 [futures::stream::SelectAll](https://docs.rs/futures/0.3.18/futures/stream/struct.SelectAll.html) を使う

両者の違いは、 `tokio_stream::StreamMap` では、どの非同期処理が完了したかを知ることができる。

### tokio_stream::StreamMap の 使用例

[tokio_stream::StreamMap](https://docs.rs/tokio-stream/0.1.8/tokio_stream/struct.StreamMap.html) にサンプルがあるが、[tokio_stream::wrappers::ReceiverStream](https://docs.rs/tokio-stream/0.1.8/tokio_stream/wrappers/struct.ReceiverStream.html) を使うと、より簡潔に記述できる。

コード例を以下に示す。

```rust:mpsc2.rs
use tokio::sync::mpsc;
use tokio_stream::{StreamExt, StreamMap};

#[tokio::main]
async fn main() {
    let (tx1, rx1) = mpsc::channel::<usize>(10);
    let (tx2, rx2) = mpsc::channel::<usize>(10);

    // ReceiverをReceiverStreamに変換する。
    let rx1 = tokio_stream::wrappers::ReceiverStream::new(rx1);
    let rx2 = tokio_stream::wrappers::ReceiverStream::new(rx2);

    tokio::spawn(async move {
        tx1.send(1).await.unwrap();
        tx1.send(2).await.unwrap();
    });

    tokio::spawn(async move {
        tx2.send(3).await.unwrap();
        tx2.send(4).await.unwrap();
    });

    // StreamMapを作成して、追加する。
    let mut map = StreamMap::new();
    // Insert both streams
    map.insert("one", rx1);  // insert, remove で 動的に待つ非同期処理を増減させることできる。
    map.insert("two", rx2);

    loop {
        let result = map.next().await;
        let (key, val) = match result {
            Some(result) => result,
            None => break,
        };
        println!("recv, key:{:?}, val:{:?}", key, val);
    }
}

```


サンプルコードは [ここ](https://github.com/kenmasumitsu/tokio-test) にあります。
【SAP-C01試験対策】DDoS攻撃に対する対策

# はじめに
AWS上のDDoS攻撃に対するセキュリティ技術を勉強するために以下の公式ドキュメントおよび研修を参考にしたので内容をまとめます。

https://aws.amazon.com/jp/shield/ddos-attack-protection/

https://www.school.ctc-g.co.jp/course/AW08.html

# 背景
本記事はAWSソリューションアーキテクトプロフェッショナルに合格するために、[Udemyの模擬試験](https://www.udemy.com/course/aws-53225)を解いて分からなかった部分を勉強してまとめるものです。

試験対策用のため、分からない知識を補足したり試験で問われなさそうなところを省略したりしながらまとめています。
なるべくわかりやすい記載を心がけますが、最終目的は自己学習用であるということをご容赦ください。

# DDoS攻撃とは

複数のソースを使用してウェブサイトやアプリケーションに負荷をかけ、正当なエンドユーザーのアクセスを妨害する攻撃。
Distributed Denial of Service attack（分散型サービス拒否攻撃）の略。

## OSI参照モデルとDDoS攻撃の種類（主なもの）
|#|レイヤー|アプリケーション|攻撃の例|
|--|--|--|--|--|
|7|アプリケーション|データ|[HTTPフラッド、DNSクエリフラッド](#アプリケーションレイヤー攻撃)|
|6|プレゼンテーション|データ|[SSLの悪用](](#アプリケーションレイヤー攻撃))|
|4|トランスポート|セグメント|[SYNフラッド](#インフラストラクチャ攻撃)|
|3|ネットワーク|パケット|[UDPリフレクション攻撃](#インフラストラクチャ攻撃)|

## インフラストラクチャ攻撃
- UDPリフレクション攻撃：標的サーバのIPになりすまし、サーバから増幅されたレスポンスが返るようなリクエストを送る。
- SYNフラッド：大量の接続を作成し放置することで標的サーバのTCPサービスを使い果たさせる。

## アプリケーションレイヤー攻撃
- HTTPフラッド：HTTPリクエストを大量に送信してアプリケーションを過負荷状態にする。
- DNSフラッド：大量のリクエストを送り付けてDNSサーバのリソースを使い果たさせる。

# [アーキテクチャによる対策](https://d1.awsstatic.com/whitepapers/Security/DDoS_White_Paper.pdf)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/951272/0109dfe9-d79c-52df-5d43-45f9ae42578c.png)

|#|サービス|概要|
|--|--|--|
|BP1|CroudFront<br>Global Accelerater|正しい形式の接続のみ受け入れ、攻撃がオリジンに到達できないようにする。|
|BP2|WAF|ウェブACLルールと関連付けることで送信元IPをブロックする|
|BP3|Route53|・シャッフルシャーディング機能により、ネームサーバーが利用不可となった場合に別のエッジロケーションでネームサーバに再試行する。<br>・anycastストライピングによりDNSを最適な場所で処理させる。<br>・DNSクエリの送信元と量から、信頼できるユーザからのリクエストを優先する。|
|BP4|APIGateway|AWSのコンポーネントをパブリックアクセスから隠す|
|BP5|ネットワークACL<br>セキュリティグループ|許可された送信元のアクセスのみに限定する|
|BP6|ELB|正しい形式のTCP接続のみを受け入れる。|
|BP7|EC2|Auto Scalingによりパフォーマンスを向上させる。

# DDoS攻撃の検知・保護に役立つサービス
- CloudWatch：正常な動作を追跡、把握し、DDoS攻撃を識別する。
- VPCフローログ：ネットワークトラフィックの異常を識別する。
- AWS GuardDuty：AWS上の操作や動作をモニタリングし、セキュリティ上の脅威を検出する。
- AWS Shield：DDos攻撃からウェブサイトを保護する。
 - AWS Shield Standard：CroudFrontやRoute53でTCPのレイヤー3,4に対する既知の攻撃から保護する。
 - AWS Shield Advanced：Standardに加えEC2等でも、レイヤー3,4,7に対する攻撃から保護する。リアルタイム通知およびAWSから24時間365日のサポートを受けられる。
MySQL

# MySQLとは
・表形式でデータを保存する。
・MariaDBとは、MySQLと共通点の多いデータベース。
今最も勢いのあるDB。

# DBの用語
・テーブル：一つ一つの表
・レコード：行
・カラム：列

#テーブルを作ろう

1.CREATE TABELE テーブル名();
・テーブル名は、複数のレコードを管理するため、複数形にすることが多い。
・丸括弧の中に定義したいカラム名を書く。
・定義のときに、データ型を指定する。

2.DESC テーブル名;
テーブルの構造を確認できる

３.SHOW テーブル名;
テーブル一覧

#レコードの挿入
・DROP TABLE テーブル名;
 テーブルを削除。もしテーブルが存在していなかったらエラーになるため、「IF EXISTS」をつける　と良い。

・INSERT　INTO　テーブル名 VALUES();
レコードの挿入

#データ型
###整数
データ型の後ろに**UNSIGNED**をつけると、マイナス分をプラスに持ってこれる。

###少数
通常は**DESIMAL**

###文字列
CHAR：固定長
VARCHAR：文字数がバラバラ
TEXT:それより長くなるやつ

###ENUM
特定の文字列に限定して、そのうちの一つだけの値を格納したいときに使用。（セレクトボックスのイメージ）
１から始まるインデックス番号でも表現可能。
特定の文字列のうち複数の値ならSETを使う。

#真偽値・日時
真偽：**BOOL**
日程：**DATETIME**

#NULLの扱い
何も値が入っていないと、基本的にNULL。
NULLのときにエラーにしたい場合は、カラムにNOT NULLとつける。
デフォルトを設定したい場合はDEFAULT

#値に制限をつける
カラム名の後ろにCHECK(条件式)をつけると、条件式通りでないとエラーにすることができる。
Django 初期設定

#はじめに
djangoのプロジェクトを作成するたびにドキュメント読みに行っている気がしたので、
知識の定着も兼ねて記事を書きます。

Pythonのバージョン:3.8.2
djangoのバージョン:3.2.9
gitのバージョン:2.30.2

#目次
1.git clone
2.startproject
3.startapp
4.settingsの情報修正
5.シークレット情報の設定

##git clone
gitを利用していないならスキップ

djangoのアプリを作成するディレクトリに移動
gitにてリポジトリを作成してURLをコピー
git cloneしていきましょう。

```
git clone https://github.com/repository.git
```

#startproject
djangoのアプリを作成するディレクトリに移動してコマンドを実行

```python
django-admin startproject projectname .
```
ディレクトリの状態
>.
├── projectname
│   ├── __init__.py
│   ├── asgi.py
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
└── manage.py

##startapp

```python
python manage.py startapp appname
```
ディレクトリの状態
>.
├── appname
│   ├── __init__.py
│   ├── admin.py
│   ├── apps.py
│   ├── migrations
│   │   └── __init__.py
│   ├── models.py
│   ├── tests.py
│   └── views.py
├── projectname
│   ├── __init__.py
│   ├── asgi.py
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
└── manage.py

##settingsの情報修正
作成中

##シークレット情報の設定
シークレットの設定は下記を参考に
https://qiita.com/Hirakawa123/items/92cdfcf1db6b175b7639

設定は以上
Dockerが起動した後に実行させるスクリプト

Dockerのサービスが起動した後に特定のコンテナを起動させたいと思ったので方法を検討してみました。MacかLinuxで動作すると思います。未検証ですがWIndowsの場合はWSL2のUbuntu上で設定すると動作するかもしれません。

> 参考
> https://superuser.com/questions/1315050/run-shell-script-after-docker-daemon-starts

## スクリプトファイルを用意する

> 参考
> https://leico.github.io/TechnicalNote/Mac/catalina-zsh

`$HOME/docker_startup.sh` に以下の内容のファイルを用意する。

```shell
#!/bin/bash
# 3分経過するか、dockerが起動するまでループする
TMP_COUNT=0
until docker version > /dev/null 2>&1 || [ ${TMP_COUNT} -eq 180 ]; do
  sleep 1
  TMP_COUNT=$((TMP_COUNT + 1))
done
# dockerが起動した後に実行される処理

#
# 例えば以下のコマンドを記述することでログイン時にportainerのコンテナを起動、もしくは作成する。
#
if [ "$(docker ps -qf name=portainer -f status=exited)" ]; then
# コンテナが既に作成済みの場合はstartで起動
docker start portainer
elif [ ! "$(docker ps -aqf name=portainer)" ]; then
# コンテナが無い場合は新しく作成
docker run \
    --detach \
    --publish 8000:8000 \
    --publish 9000:9000 \
    --name portainer \
    --restart always \
    --volume /var/run/docker.sock:/var/run/docker.sock \
    --volume portainer_setting_data:/data \
    portainer/portainer-ce
fi
# 上記で作成したコンテナとボリュームは下記のコマンドで削除可能
# docker stop $(docker ps -aqf "name=portainer") && docker rm $(docker ps -aqf "name=portainer") && docker volume rm portainer_setting_data
```

### ファイルに実行権限を持たせる

起動時に実行出来るように実行権限をもたせます。`Permission denied `エラーが表示される場合は、700を705等にしてみてください。

```bash
chmod 700 $HOME/docker_startup.sh
```

## ログイン時に実行させる

> https://itiut.hatenablog.com/entry/2013/07/07/114143

UbuntuのGUIの場合は`~/.profile`に以下の内容を追記。他Linuxの場合は`~/.bash_profile`に追記、MacはCatalinaより新しいOSの場合、`~/.zshrc`に追記する。その他環境によってはログイン時に実行されるファイルが違うので注意して設定してください。

```zsh
/bin/bash $HOME/docker_startup.sh
```
VS CodeでMarkdownをHTMLに変換する(Github Style)

## はじめに
業務で経験したことや勉強で得た気づきなどを知見として蓄積することを考えています。そこで、Markdown形式のファイルをhtml形式のファイルに変換しようとして色々躓いたのでメモを残します。

## 対象者
この記事は下記のような人を対象にしています。

- VS CodeでMarkdownをHTMLやPDFに変換する方法が知りたい
- 変換したHTMLにGithub StyleのCSSを適用する方法が知りたい

## 環境
- windows 10 home
- VS Code

## 流れ
1. VS Codeの拡張機能である Markdown PDF をinstallする
1. github形式のcssを入手する
1. VS Codeのsetting.jsonに設定を追記する
1. HTML形式で出力する

## 最終的なフォルダ構成
```
.
├── github-markdown-css  //git cloneしたリポジトリ
|   └── ...
├── github-markdown.css //リポジトリ内からコピーしたcssファイル
├── example.md //適当なmdファイル
└── example.html //出力したhtmlファイル
```

### Markdown PDFのインストール
MarkdownをHTMLやPDFに変換してくれる拡張機能としてはyzane氏による「Markdown PDF」がある。この拡張機能をインストールしてしまえば、後はコマンドパレットから［Markdown PDF: Export (XXX)］コマンドを実行するだけで、HTMLやPDF、PNG、JPEG形式のファイルに変換できる（「XXX」には変換先のフォーマットに応じて「html」「pdf」などが入る）。

左サイドバーの上から6つめ、拡張機能を選択する。markdown pdf と検索窓に入力し候補に出てくる Markdown PDF をインストールする。

![pic1.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/577794/e8f5b7a9-64d4-bc27-ac27-a88baf3e007b.png)


### github形式cssの入手 & 編集
HTMLに変換するまでは、VS Codeに拡張を導入するだけで可能。出来上がるHTMLをGitHub風の見た目にするためにcssを入手したり設定ファイルを編集する必要がある。下のリンク先のリポジトリをローカル環境にクローンする。

https://github.com/sindresorhus/github-markdown-css


```
mkdir workdir
cd workdir
git clone https://github.com/sindresorhus/github-markdown-css.git
cd github-markdown-css
cp github-markdown.css ../github-markdown.css
cd ..
```

github-markdown.cssはこのままではVScodeで使用するにあたって使いにくい部分もあるので変更を行う。

1. すべての.markdown-を削除(空文字で置換すると楽)する
1. code blockの折返しを設定する。

Code Block内で長い行があったときにはみ出てしまうという問題を解決するために、CSSを以下のように書き換える。上記の1. の削除は済ませているものとする。

```github-markdown.css
body pre>code {
  padding: 0;
  margin: 0;
  font-size: 100%;
  word-break: normal;

  - white-space: pre;
  + white-space: pre-wrap;

  background: transparent;
  border: 0;
}
```

上記のwhite-spaceの値をpreからpre-wrapに変更することで、Code Blockに折り返しが働く。

### setting.jsonに設定を追記
CSSの編集が終わったら、「Ctrl」+「,」を押し、設定画面を開く。右上の「設定(JSON)を開く」を押す。setting.jsonに以下を追記する。

```
//デフォルトのCSSを無効にする
"markdown-pdf.includeDefaultStyles": false,
// 上記で編集したCSSを指定する
"markdown-pdf.styles": ["./github-markdown.css"],
```

![pic3.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/577794/d85fa599-56a5-e570-b3b2-64e10b4253fb.png)



### HTML出力
適当なmdファイルを開く。mdファイルのコード上で右クリックし、
「Markdown PDF: Export (html)」をクリックするとhtmlファイルが出力される。

![pic2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/577794/9def509f-e503-b585-c230-bf730d739764.png)



## おわりに
VS CodeとMarkdownをもっと使いこなしたいです。

## 参考にした記事
- [VS CodeでMarkdownをプレビューするには？](https://atmarkit.itmedia.co.jp/ait/articles/1804/20/news030.html)
- [VS CodeでMarkdownをHTMLやPDFに変換するには？](https://atmarkit.itmedia.co.jp/ait/articles/1804/27/news034.html)
- [VS Codeのsettings.jsonの開き方](https://qiita.com/y-w/items/614843b259c04bb91495)
- [VScodeのMarkdown PDFでGithub StyleのCSSを適用する](https://jackjasonb.com/2021/03/22/markdown-pdf-css/)
YahooAPIを利用してルビを振る　V２


　以前作った「YahooAPIを利用してルビを振る」で使っていたAPIが廃止になるようだ。それに変わってバージョンが上がったものがある。なのでそれを使って「YahooAPIを利用してルビを振る」のをやってみようと思う。

https://qiita.com/99nyorituryo/items/55cb36a733d4745588eb

変更点がXMLからJSONになった。xmlhttpreqestの要求もjsonをテキスト化して送っている。リクエストヘッダーにユーザーエージェントを指定しているので、ブラウザからxmlhttpreqestではリクエストを送れなかった。


```javascript
    http.setRequestHeader("Content-Type", "application/json");
    http.setRequestHeader('User-Agent','Yahoo AppID: ' + Appid);
    // 要求
var param_dic = {
      "id": "1234-1",
      "jsonrpc": "2.0",
      "method": "jlp.furiganaservice.furigana",
      "params": {
        "q": Sentence,
        "grade": Grade
      }
    }
    http.send(JSON.stringify(param_dic));
```

XMLからJSONに変更になったが、向こう側でXMLで作ったものをJSONに変換しているだけなのではないかと思ったので。XMLのパースもJSONのパースもあまり変わらない感じである。

以下全体のコードである。

https://github.com/kyukyunyorituryo/add_ruby/blob/master/%E3%81%B5%E3%82%8A%E3%81%8C%E3%81%AA.js
WAS設計その14 ホットデプロイとコールドデプロイ

アプリケーションサーバにアプリをデプロイするとき
※ND版に関して
※Base版はアプリケーションサーバが起動していないとデプロイできない。

コールドデプロイ
アプリケーションサーバを停止した状態でデプロイする

ホットデプロイ
アプリケーションサーバを起動した状態でデプロイする。

基盤側でsnoopアプリくらいインストールするなら、当然ホットデプロイで実施する。

アプリチームが作成した手順に依存するので何とも言えないが、結構コールドデプロイするところも多い。理由は不明。まぁコールドでデプロイしたほうが色々間違いがないと思う。
※起動時のエラーチェックもできるし。

停止できるのであれば、コールドデプロイがいいと思います。
sedコマンド、3行足すだけで万能変換ができるカンペ


# 問. 下記の変数HENKAN_MOJIにおける「open」を、変数SUBSTIDUTE_CHARにおける「\\|/」へ変換せよ
  - HENKAN_MOJI='left_open_right'
  - SUBSTIDUTE_CHAR='\\|/'
  - (正値) HENKAN_MOJI=left_\\|/_right

## 失敗例 〜　いつものやり方　〜

```
HENKAN_MOJI='left_open_right'
SUBSTIDUTE='\|/'
echo "${HENKAN_MOJI}" | sed 's/open/'${SUBSTIDUTE}'/g')

`s' に対するオプションが不明です
```

「\\|/」の「/」が置換対象変数内の区切り文字である「/」と重なり、エラーとなる
かといって、区切り文字を「|」にして、
> sed 's|open|'${SUBSTIDUTE}'|g'

としようにも、置換対象変数内に「|」があるため同様のエラーとなる
## 解決法 〜　特殊記号を他の文字列に置き換える　〜

```
HENKAN_MOJI='left_open_right'
SUBSTIDUTE='\|/'
SUBSTIDUTE=$(echo "${SUBSTIDUTE}" | sed 's/[|]/CHAR_VERTICAL_VAR/g' | sed 's/[/]/CHAR_SLASH/g' | sed 's/[\]/CHAR__BACK_SLASH/g')
HENKAN_MOJI=$(echo "${HENKAN_MOJI}" | sed 's/open/'${SUBSTIDUTE}'/g')
HENKAN_MOJI=$(echo "${HENKAN_MOJI}" | sed 's/CHAR_VERTICAL_VAR/\|/g' | sed 's/CHAR_SLASH/\//g' | sed 's/CHAR__BACK_SLASH/\\/g' | sed 's/*right/text/g')
echo "${HENKAN_MOJI}"

--> left_\|/_right
```

三行目で**「\\」「|」「/」を文字列「CHAR_VERTICAL_VAR」「CHAR_SLASH」「CHAR__BACK_SLASH」に置き換えている**
これさえ、できれば四行目で普通に「open」を変換できる。
あとは、「\\」「|」「/」へ戻すのを忘れずに。

## この方法の利点
**万能である。**
他の特殊記号(「(」「)」「[」「]」「{」「}」「'」「"」「\`」等etc)であっても、変換可能。
ただでさえ、「|」が変数内に含まれると、そうそう使える区切り文字がないので。
これで、ただでさえ、便利なsedライフを。

# 余談と題して、宣伝
こんなテクニックを駆使してコマンドにおける特殊記号をフルに扱えるアプリを作ってみた
名付けて 
### [コマンドクリック](https://docs.google.com/document/d/19KFUA_DxuWPMMtEZLaBMDIBlX8SB6xPwuQlLiEqaaNs/edit?usp=sharing)
例えば、docker-comopse up -f /home/example/Desktop/share/projedtA/production.yml up -d
等の**面倒なコマンドをクリック一発でターミナルへ送れる**
Ubuntu系Linux限定にて、公開中。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2284147/cdf55869-ade9-77fe-da84-f44081c4f484.png)
- 参考記事
[シェルスクリプトでGUIアプリを作ってみた](https://qiita.com/hoperstep/items/8a24dbc7cdf530d66a71)
Elf32_Symの説明

```c:elf32.h
typedef struct {
        Elf32_Word      st_name;
        Elf32_Addr      st_value;
        Elf32_Word      st_size;
        unsigned char   st_info;
        unsigned char   st_other;
        Elf32_Half      st_shndx;
} Elf32_Sym;
```


* st_nameはstrtab(string table) sectionの先頭からのoffset (null終端されてる
* st_infoは、symbolがobject(変数)か、関数か、等の情報と、そのスコープがファイルローカルなのか、グローバルなのかの情報が格納されている
* st_shndxのshndxはsection header table indexの略称
* st_valueはsegmentの先頭からのoffset
* st_sizeはシンボルの実態のサイズ
Laravelパッケージを作ろう！その弐

前回、LaravelパッケージをGit経由で追加する事ができた。
[Laravelパッケージを作ろう！その壱](https://qiita.com/_bobtabo_/items/c65e6510ca20b8a41f70)
ただ、どうせならGitへプッシュする前に動作確認とかしたいし、パッケージにバージョン振りたいな。

# マシンスペック
* Mac mini 2018
* macOS Catalina（10.15.x）
* Intel Core-i7 3.2GHz 6コア
* メモリ 32GB
* SSD 512GB

# 開発環境
* PHP（PHP-FPM） 8.x
* Composer 2.x
* Laravel 8.x

# やりたい事
* Gitへプッシュする前に動作確認したい
* パッケージバージョンが欲しい

# 前提
[Laravelパッケージを作ろう！その壱](https://qiita.com/_bobtabo_/items/c65e6510ca20b8a41f70)を実施済み

# Gitへプッシュする前に動作確認したい

パッケージ構成は、こんな感じ。

```
[laravel] ← Laravelプロジェクト
 |-app
 |-packages
   |-bobtabo ← パッケージルート
     |-library
       |-src
         |-...
```

Laravelプロジェクト（導入先）の composer.json を編集する

- 編集前

```json:~/laravel/composer.json
{
    "name": "laravel/laravel",
    ・・・
    "scripts": {
        ・・・
    },
    "repositories": {
        "bobtabo/library": {
            "type": "vcs",
            "url": "https://github.com/bobtabo/laravel-package"
        }
    }
}
```

- 編集後

```json:~/laravel/composer.json
{
    "name": "laravel/laravel",
    ・・・
    "scripts": {
        ・・・
    },
    "repositories": [
        {
            "type": "path",
            "url": "packages/bobtabo/library",
            "symlink": true
        }
    ]
}
```

あとは、パッケージを編集する度に導入先にインストールすればOK。

```terminal
$ composer require bobtabo/library
・・・
Package manifest generated successfully.
```

※参考
[Laravelパッケージ開発ハンズオン〜環境編〜#開発パッケージのインストール](https://qiita.com/ucan-lab/items/d09ba1745c6bb45972a0#%E9%96%8B%E7%99%BA%E3%83%91%E3%83%83%E3%82%B1%E3%83%BC%E3%82%B8%E3%81%AE%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB)

# パッケージバージョンが欲しい

パッケージをインストールすると、こうなる。

```json:~/laravel/composer.json
{
    "name": "laravel/laravel",
    ・・・
    "require": {
        "php": "^7.3|^8.0",
        "bobtabo/library": "dev-master",
        ・・・
    },
```

"dev-master"じゃなくて、バージョンが欲しいので、パッケージ側のcomposer.jsonを編集する。

- 編集前

```packages/bobtabo/library/composer.json
{
    "name": "bobtabo/library",
    "description": "Bobtabo Core Library",
    "type": "library",
    ・・・
}
```

- 編集後

```packages/bobtabo/library/composer.json
{
    "name": "bobtabo/library",
    "description": "Bobtabo Core Library",
    "type": "library",
    "version": "0.1.0",
    ・・・
}
```

パッケージをインストールし直す。


```terminal
$ composer require bobtabo/library
・・・
Package operations: 0 installs, 1 update, 0 removals
  - Removing bobtabo/library (dev-master 7f64c58)
  - Installing bobtabo/library (0.1.0): Symlinking from packages/bobtabo/library
・・・
Package manifest generated successfully.
```

お！バージョン出た！？
composer.jsonを確認する。

```json:~/laravel/composer.json
{
    "name": "laravel/laravel",
    ・・・
    "require": {
        "php": "^7.3|^8.0",
        "bobtabo/library": "^0.1.0",
        ・・・
    },
```

バージョンに変わってる！！