OmniAICreator/Qiita-1.07M huggingface dataset:
Composer でプライベートリポジトリを使っている時の GitHub Actions 設定方法

Composer でプライベートリポジトリを require している場合、GitHub Actions で普通に 

```yaml
- name: Install dependencies
  run: composer install --prefer-dist --no-progress
```

としていると認証エラーが発生します。（当然ですよね）

```
Failed to clone the git@github.com:foo/bar.git repository, 
try running in interactive mode so that you can enter your GitHub credentials
```

これを解決するためには、プライベートリポジトリを利用するためのアクセストークンを渡してあげる必要があります。アクセストークンを Actions に書いてコミットするなんてことは絶対しちゃいけないので、secret を利用します。なので全体では次のような手順が必要です。

1. GitHub のアクセストークンを生成する
2. リポジトリの secret にそのトークンを保存する
3. Actions の job 定義の中で環境変数をセットする

また、アクセストークンが期限切れになった（なりそうな）時には更新する必要があります。
更新は次のような手順が必要です。

1. GitHub のアクセストークンを更新する
1. リポジトリの secret のトークンを更新する

以下、それぞれの手順を説明します。

## 新たに設定する

### 1. GitHub のアクセストークンを生成する

GitHub Actions 用のアクセストークンを生成します。プライベートリポジトリを require しているので、すでにアクセストークンを生成してローカルの Composer で使っていることと思いますが、ここでは新たに生成します。
次のリンクから生成可能です。

1. [GitHub: アクセストークン](https://github.com/settings/tokens) にアクセスします
1. `Generate new token` をクリックします
1. Note の欄には何のためのトークンかを説明する文章を入れましょう。適当に入れると後でわけわからなくなります
1. Select scopes の欄では、`repo` にチェックを入れます
1. `Generate token` ボタンをクリックして生成します
1. Personal Access Token のページに戻りますが、そこにアクセストークンが表示されています
1. コピーボタンをクリックしてトークンをクリップボードにコピーします (ここでコピーし忘れると二度と見ることはできませんので注意が必要です)

トークンのコピーを忘れた場合は更新の時の手順に従ってトークンの再生成を行なってください。

### 2. リポジトリの secret にそのトークンを保存する

生成したトークンは、リポジトリの Actions secret に保存しておきます。

1. Actions を設定したいと思っているリポジトリを開き、`Setting` > `Secrets and variables` > `Actions` と選択します
2. `New repository secret` をクリックします
3. `Name` の欄に名前（ここでは `COMPOSER_AUTH` としますが別の名前でも構いません）を入れ `Value` の欄にトークンをペーストします
4. `Add secret` ボタンをクリックして保存します

### 3. Actions の job 定義の中で環境変数をセットする

次のように、`COMPOSER_AUTH` 環境変数に secret の値を含んだ文字列をセットします。この前のセクションで secret の名前を変更した場合は、`secrets.COMPOSER_AUTH` の部分もそれに合わせて変更してください。

```yaml
  - name: Install dependencies
    env:
      COMPOSER_AUTH: '{"github-oauth": {"github.com": "${{secrets.COMPOSER_AUTH}}"} }'
    run:
      composer install --prefer-dist --no-progress
```

以上で完了です。

## 更新する

### 1. GitHub のアクセストークンを更新する

1. [GitHub: アクセストークン](https://github.com/settings/tokens) にアクセスします
1. トークンの一覧の中から対象のトークンを選択します
1. `Regenerate token` ボタンをクリックして再生成します
1. 確認画面が表示されますので `Regenerate token` をクリックします
1. Edit personal access token のページが表示されますが、画面上部に再生成されたトークンが表示されます。
1. Personal Access Token のページに戻りますが、そこにアクセストークンが表示されています
1. コピーボタンをクリックしてトークンをクリップボードにコピーします (ここでコピーし忘れると二度と見ることはできませんので注意が必要です)
1. `Update token` ボタンをクリックすると更新されます

コピーを忘れた場合は、もう一度再生成をします。

### 2. リポジトリの secret のトークンを更新する

1. 対象のリポジトリを開き、`Setting` > `Secrets and variables` > `Actions` と選択します
2. Repoitory secrets の一覧に設定済みの secret があると思いますので、その `Update` ボタンをクリックします
3. `Value` の欄にトークンをペーストします
4. `Update secret` ボタンをクリックして保存します

以上で更新は完了です。
結局どのランタイムが一番速いですか？　Pytorch、ONNX、OpenVINO、CoreML速度比較

# AnimeGAN2-pytorchの推論で比較してみました

ONNXとOpenVINOはColabで、CoreMLはM1MacBookAirです。NVidiaのGPUしかなかったので、OpenVINOのGPU推論は試せてません。
Colab CPU:Intel(R) Xeon(R) CPU @ 2.20GHz

|runtime|time(s)|
|---|---|
|Pytorch-CPU|5|
|Pytorch-GPU|0.006|
|onnx-CPU|4.9|
|onnx-GPU|2.4|
|onnx量子化(int8)-CPU|4.9|
|onnx量子化(int8)-GPU推論|2.4|
|onnx simplifier-CPU推論|4.9|
|onnx simplifier-GPU推論|2.4|
|onnx simplifier 量子化(int8)-CPU|4.9|
|onnx simplifier 量子化(int8)-GPU|2.4|
|openvino-CPU|4|
|openvino 量子化(int8)-CPU|4|
|CoreML|0.14|

🐣
****
フリーランスエンジニアです。
お仕事のご相談こちらまで
rockyshikoku@gmail.com

Core MLやARKitを使ったアプリを作っています。
機械学習／AR関連の情報を発信しています。

[Twitter](https://twitter.com/JackdeS11)
[Medium](https://medium.com/@rockyshikoku)
[GitHub](https://github.com/john-rocky)
goのポインタ


## ポインタ
- ポインタを渡すというのは、変数の内容を渡すのではなく、変数のメモリの値を渡すという意味
    - なので、渡された関数などで、値の変更が合った場合は、渡された関数の外であってもそのポインタを参照すると値は変わっている
- ポインタではない通常の変数のわたし方の場合は、変数のコピーが渡されるため、関数内で値が変わった場合、変数が渡された関数の中と外でその変数を参照しても値は変わっている

```golang
package main

import "fmt"

// ポインタ
func pointer(x *int) {
	*x += 1
	fmt.Println("ponter func: ", *x)
}

// ポインタではない
func nopointer(x int) {
	x += 1
	fmt.Println("nopointer func: ", x)
}

func main() {
	z := 2
	pointer(&z)
	fmt.Println(z)

	fmt.Println("------------")
	y := 2
	nopointer(y)
	fmt.Println(y)
}
```


出力

```
 yuta  ~  gotest  go run main.go
ponter func:  3
3
------------
nopointer func:  3
2
```
Manjaro Linux (arm64 for Raspberry Pi)の日本語設定

個人的メモです。必要なくなったら記事消します。

Raspberry Pi4 で Manjaro Linux の日本語設定しようとした時に、一般的に読める記事で記載の方法（Manjaro Helloから設定）が使えなかったのと、fcitxパッケージがそろそろサポート終了しそうな雰囲気だったので、以下のような手順で設定しました。

## 環境

- Manjaro Linux (arm64 for Raspberry Pi) 22.02 KDE version
- Raspberry Pi 4B Momory 4GB

## 手順

- パッケージマネージャでAURをオンにして更新
- fcitx5-mozc, fcitx5-input-support, fcitx5-configtoolを入れる
    - fcitx(ver4)はメンテ停止予告が出ているため、fcitx5を使用します。
    - fcitx5-configtoolでkdeの設定から呼べます。
    - kcm-fcitx5は動作しませんでした。
- fcitx5-configtoolでInput MethodにMozcを追加

## 動作確認したアプリ

- VSCode
- Chromium
- LibreOffice
[UE5] VRテンプレートにデバッグ用の機能追加

# はじめに
UE5がとうとう正式リリースされたので、作業環境を移行するため、これまでUE4で作成してきたVRのデバッグ用の機能等をUE5のVRテンプレートに持っていきました。
作成したプロジェクトを[GitHub](https://github.com/SatoshiTakahama/VRtemplate)に置きましたので、よろしければ使ってみてください。
動作確認はMetaQuest2で行っています。

VRテンプレートからの変更箇所は以下になります。
~~・コントローラをグレイマンの手に変更
　[以前の記事](https://qiita.com/Satoshi_Takahama/items/77747c7fea45fd0f1cce)の内容を実装したものです。~~
(2023/1/1追記、UE5.1のVRテンプレートのマネキンに更新しました)
・PC上のビューポートでVRPawnを動かす機能の追加
　[以前の記事](https://qiita.com/Satoshi_Takahama/items/77747c7fea45fd0f1cce)の内容を実装したものです。
　記事での内容に加えて、マウスでの視点移動等を追加しています。
　また、キー入力を持ってかれてしまうのでVRSpectatorをレベル上から削除しています。
・VR上でOutputLogを確認できるViewerの追加
　こちらの記事[VR内でOutputLogを見よう](https://qiita.com/ruyo/items/b9f65ec6d1c3da5a51e4)で説明されていた内容を参考に実装したものです。
・プロジェクト設定の変更
　対応プラットフォームから使用しないIOS/Linuxのチェックを外した
　~~デフォルトのRHIをDirextX12=>DirextX11に変更(ライティングのビルドで落ちる対策、[フォーラム](https://forums.unrealengine.com/t/vrtemplate-build-lighting-crashes-ue5-adding-landscape-material-build-lighting-crashes-at-exporting-data-33/508936)参照)~~ (2022/6/7追記、UE5.0.2で解消したため元に戻した)
・UE5.1対応(2023/1/1追記)
　UE5.1のVRテンプレートのマネキンに差し替え
　Enhance Inputに変更
　※UE5.1からAndoroid(含むMetaQuest2)向けにビルドするにはNDK 25.1.8937393のインストールが必要です。自分は[フォーラムの記事](https://forums.unrealengine.com/t/error-uat-ld-lld-error-undefined-symbol-aarch64-swp8-acq-rel-ue5-1/693154)を参考にしました。なお、NDKを更新した後、自分の環境ではUE4.27でAndoroid向けのビルドに失敗するようになりました。共存する方法を知っている方がいましたら教えて欲しいです・・・

# 環境
MetaQuest2(旧OculusQuest2)
Windows~~10~~11
UnrealEngine ~~5.0.0~~5.1

# 参考資料
・[VR テンプレート](https://docs.unrealengine.com/5.0/ja/vr-template-in-unreal-engine/)
公式のドキュメントです。
【AWS】WEBサーバー構築

# [<font color="#333">備忘録</font>](#-2.備忘録)
***前提***
* ApacheやPHPが最初からインストールされてない
* その他の設定は踏み台サーバーのイメージを引き継いでいる

***Apacheインストール***
```
yum install httpd
```

***PHPインストール***
```
yum -y install --enablerepo=remi,remi-php73 php php-devel php-mbstring php-pdo php-gd php-xml php-mcrypt php-pear php-pecl-apc-devel php-mysqlnd zlib-devel
```

***Apache設定***

```
cd /etc/httpd/conf.d

//welcom.conf削除
rm welcome.conf

//autoindexも削除
rm autoindex.conf
```


一階層戻ってconfに入る
```
cd ..
cd conf
```

まずはバックアップ
```
cp -p httpd.conf httpd.conf.20220401

vim httpd.conf

```

95行目のドメイン名を取得したドメインにする

144行目を下記に変更

```
Options FollowSymLinks
```
1番下に下記追加
```
TraceEnable off
```

さらにその下に下記7行追加
```
Header append X-FRAME-OPTIONS "SAMEORIGIN"
Header set X-XSS-Protection "1; mode-block"
Header set X-Content-Type-Options nosniff
FileETag None
Header Unset X-Powered-By
ServerTokens ProductOnly
ServerSignature off
```

ここに入る
```
cd /etc/httpd/conf.modules.d
```

下記入力でコメントアウト外れてればOK
```
conf.modules.d]# cat 00-base.conf| grep "LoadModule headers_module modules/mod_headers.so”
```

httpdを起動
```
systemctl start httpd
//enableにしておく
systemctl enable httpd
//ステイタス確認
systemctl status httpd
```

***PHPの設定***
```
cd /etc
```

php.iniの編集（バックアップ忘れずに）
```
vim php.ini
```
922行目タイムゾーン変更
```
date.timezone = Asia/Tokyo
```
376行目
```
expose_php = Off
```

pemファイルのあるディレクトリで
```
curl -I 18.181.121.142(webサーバーのE-IP)
```
**Date**: Tue, 01 Feb 2022 20:42:19 GMT

**Server**: Apache

**X-FRAME-OPTIONS**: SAMEORIGIN

**X-XSS-Protection**: 1; mode-block

**X-Content-Type-Options**: nosniff

**Content-Type**: text/html; charset=UTF-8
こんな感じならOK

***MySQLインストール***
```
yum remove mariadb-libs
yum install wget
```

MySQL5.7のインストール
```
wget https://dev.mysql.com/get/Downloads/MySQL-5.7/mysql-5.7.18-1.el7.x86_64.rpm-bundle.tar
```
解凍
```
tar xf mysql-5.7.18-1.el7.x86_64.rpm-bundle.tar
```
下記3点インストール
```
rpm -Uvh mysql-community-common-5.7.18-1.el7.x86_64.rpm mysql-community-libs-5.7.18-1.el7.x86_64.rpm mysql-community-client-5.7.18-1.el7.x86_64.rpm
```


これで/var/www/html配下にプロジェクトを持ってくればOK
AtCoder Beginner Contest 248　A~D　4完記事

アルゴリズムの学習改善のための自身の備忘録及び学習の一環として記事を書くことにしました.
読んでくれた方で何かありましたら気兼ねなくコメントしてください.お待ちしております.

# [A - Lacked Number](https://atcoder.jp/contests/abc248/tasks/abc248_a)

## 問題文　概要
$0$~$9$の中に含まれていない整数は何か

## 制約と入力
制約
>$S$ は数字のみからなる長さ $9$ の文字列である。
>$S$ の文字はすべて相異なる。

入力
>入力は以下の形式で標準入力から与えられる。
>$S$

## 考察
全探索を用いて，含まない物を探索する．
$0$~$9$まですべてから探索する．


## サンプルコード
```python:a.py
s=set(list(input()))
ans=-1
for i in range(10):
    if str(i) in s:
        continue
    ans=i
print(ans)
```

# [B - Slimes](https://atcoder.jp/contests/abc248/tasks/abc248_b)

## 問題文　概要
$A$が$B$を超えるまで$k$倍を続ける．
何回操作したのかを求める．

## 制約と入力
制約
>$1\leq A \leq B \leq 10^9$
>$2\leq K \leq 10^9$
>入力は整数。

入力
>入力は以下の形式で標準入力から与えられる。
>$A \ B \ K$

## 考察
$A<B$である限り$A=A\times K$を繰り返し続ける．
$A\geq B$となるまでに行った操作回数が答えとなる

## サンプルコード
```python:b.py
A,B,K=map(int,input().split())
for i in range(10**9):
    if A>=B:
        print(i)
        exit()
    else:
        A*=K
```

# [C - Dice Sum](https://atcoder.jp/contests/abc248/tasks/abc248_c)
## 問題文　概要
数列$A=(A_0,...,A_N)$に対して各要素は$1\leq A_i \leq M$である．
$$\sum_{i=1}^N A_i\leq K$$となる数列の取り方は何通りあるか



## 制約と入力
制約
>$1\leq N,M \leq 50$
>$N \leq K \leq NM$
>入力は全て整数

入力
>$N \ M \ K$

## 考察
動的計画法を用いて考える．
$dp[n][sum]$として，｢$n$の時の総和｣の取り得る数列の数を保存する．
この時，$nex=(1,2,...,M)$とすると$n+1$の時，$sum+nex$が総和として遷移される
遷移として具体的に
$dp[i+1][sum+nex]=dp[i][sum]$となる
$n$は固定なので$dp[n]$の時の総和が答えとなる．



## サンプルコード
```python:c.py
n,m,K=map(int,input().split())
MOD=998244353
dp=[[0 for _ in range(K+1)] for _ in range(n+1)]
dp[0][0]=1
for i in range(n):
    for j in range(K+1):
        for k in range(1,m+1):
            if j+k>K:
                continue
            dp[i+1][j+k]+=dp[i][j]
            dp[i+1][j+k]%=MOD
print(sum(dp[-1])%MOD)
```


# [D - Cylinder](https://atcoder.jp/contests/abc247/tasks/abc247_d)
## 問題文　概要
数列$A=(A_1,A_2,...,A_N)$に対して$(A_L,...,A_R)$に$x$はいくつあるか
数列$A$は固定であるが，$L,R,X$は変動するなかでそれぞれで求める


## 制約と入力
制約
>$1\leq N \leq 2 \times 10^5$
>$1 \leq A_i \leq N$
>$1\leq Q \leq 2 \times 10^5$
>各クエリについて$1\leq L \leq R \leq N,1\leq X \leq N$
>入力は全て整数


入力
>$N$
>$A_1 \ A_2 \ \dots \ A_N$
>$Q$
>$Query_1$
>$Query_2$
>$\vdots$
>$Query_N$

$Query_i​$は各クエリを表す．
各クエリ
>$L \ R \ X$

## 考察
愚直に各クエリを数列$A$から探索すると計算回数は$N^Q$必要となり，間に合わない．
前計算として，$A_i$のインデックスを管理した連想配列を準備する．
各値毎にインデクスを昇順に保持する．
連想配列の$X$の値の時の配列に$L,R$を挿入する．
挿入するインデックスを比較すると答えは求まる．


## サンプルコード
```python:d.py
import bisect
n=int(input())
a=list(map(int,input().split()))
cnt=dict()
cnt_set=set()
for i in range(n):
    if a[i] in cnt_set:
        cnt[a[i]].append(i+1)
    else:
        cnt[a[i]]=[i+1]
        cnt_set.add(a[i])

q=int(input())
for i in range(q):
    l,r,x=map(int,input().split())
    if x not in cnt_set:
        print(0)
        continue
    else:
        L=bisect.bisect_left(cnt[x],l)
        R=bisect.bisect_right(cnt[x],r)
        print(R-L)
```
プリンシプルオブプログラミングを読んで

* 良いプログラマーは時間がかかっても、言語、技術、ツール、問題領域など、分野を問わず理解してから作業に取りかかる
感想 : その通りだが速さが必要な場合や、全体像を先に捉え、細部を潰していくと言うやり方では駄目なのか。経験して、自分の最適解を見つける。
* コードを書く時は常に他者が読むことを考えて書く
日付入力フォームのクリック範囲を拡大

# [<font color="#333">完成形</font>](#-2.完成形)
こんな感じでどこをクリックしてもカレンダーが展開されるようにします。
![ezgif.com-gif-maker (1).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/920917/65d6f4a6-4d95-7316-fbcb-409c8a7036f2.gif)

何も考えずに下記の記述のみだと
```index.html
 <input id="date" type="date" name="date" class="form-control >
```
カレンダーマークが出て、それをクリックしないとカレンダーは展開されません。
PCならまだしも、SPだと操作しづらい事この上なき。

CSSのみで簡単にできるので日付入力フォームの時はちゃんと実装したいものです。
```date.css
input[type=date]::-webkit-calendar-picker-indicator {
  position: absolute;
  width: 100%;
  height: 100%;
  opacity: 0;
}


input[type="date"]::-webkit-inner-spin-button{
  -webkit-appearance: none;
}

input[type="date"]::-webkit-clear-button{
  -webkit-appearance: none;
}

input[type="date"]{
 
  position: relative;
}

```
やってる事は単純で、カレンダーマークをビヨーンと入力フォーム全体に伸ばしてるだけ。
そして見えるとカッコ悪いのでopacity:0で透明にしてます。
jQueryでボタン連打防止！！

# [<font color="#333">連打ダメ！絶対！</font>](#-2.連打ダメ！絶対！)
何か情報を登録したり更新したりする時に、POSTした際に画面を読み込んでる時間があると思います。その際に登録ボタン等を連打すると何も対策してない状態だとご親切に連打した分だけDBに情報を登録してくれます。
それをフロント側で制御してあげましょう。

こんな感じでボタンがあるとします。
```index.php
 <button class="js-no-repeated" type="submit">登録</button>

```

そしたらこれだけでOK
```app.js
 $('.js-no-repeated').on('click',function(){
    $(this).prop("disabled", true);
    $(this).closest('form').submit();
  });
```

これでボタン押せなくなるのはわかると思いますがポイントはその下
```app.js
$(this).prop("disabled", true);

```
disabledにするとその瞬間post自体がされなくなるんですね。
なので下記記述でjsでsubmitをする必要があります。
```app.js
$(this).closest('form').submit();
```
Exressを使って占いAPIを作りましょう

# expressを使ってAPIを作りましょう

```
curl https://tarot-system.herokuapp.com
```
heroku無料プランのためサーバーが寝てる間は失敗するので、何回か試してみてください。
まず出来上がったものはこちら。
シングルカードのタロット占いができるAPIです。

***
１.まずは適当にディレクトリを作成しましょう。
2.そのディレクトリに移動して
```
npm init
```
このコマンドを実行します。
色々質問されますが、とりあえずEnter連打でOKです。

3.次にExpressをインストールします。
先程と同じく１で作ったディレクトリで
```
npm install express --save
```
このコマンドで下準備は完了です。

4.index.jsファイルを作成し次のコードを記述します。
```javascript
const express = require('express');
const app = express();

app.set('port', (process.env.PORT || 3000));

app.get('/', function(request, response) {
  response.send('Hello World!\n');
});

app.listen(app.get('port'), function() {
  console.log("Node app is running at localhost:" + app.get('port'));
});
```

5.記述ができたら1で作ったディレクトリで
```
node index.js
```
これでサーバーが稼働しますのでターミナル別に開いて次のコマンドを打ちます。
```
curl http://localhost:3000
```

すると
```
Hello World!
```
と表示されるのでこれで完成です。

***

①あとはタロットカードのデータを、HerokuのPostgreSQLに用意する。
②DBからデータを引っ張ってくるように、今作ったAPIを改造する。（このAPIもHerokuにデプロイします）

で完成です。
DBの話とHerokuにデプロイする件はまたの機械に。
jQueryで指定文字以上でボタンを非活性にする

# [<font color="#333">何をするか</font>](#-2.何をするか)
コンテンツを登録する際やプロフィールをDBに登録する際に、最大文字数を制限したい場合があります。
その際にバックエンドでバリデーションを行っても良いのですが、そもそもフロント側でsubmitできない様にしてあげた方が親切ですね。

まず下の様な簡単なフォームがあるとする。

```index.php
 <form action="{{route('item_post')}}" method="POST" enctype="multipart/form-data">
        @csrf
       
        <table class="p-form__table">
           
            <tr>
                <th class="p-form__name">内容(255文字まで)</th>
                <td class="p-form__body">
                    <textarea name="comment" class="p-form__textarea js-comment" required>{{old('comment')}}</textarea>
                    @error('comment')
                    <p class="c-error p-form__error">{{$message}}</p>
                    @enderror
                    <span>255</span>/ <span class="js-text-count"></span>
                    <span class="c-error p-form__counterror js-error">文字数オーバーです。</span>
                </td>
            </tr>
            
        </table>
        <button class="c-btn__form p-form__btn--center js-submit" type="submit">登録</button>
    </form>


```

次にjQueryで文字数をカウントしてエラーを出す。
```app.js

  //編集画面などで最初からテキストエリアに文字がある場合は最初に文字数を入れておく
  if($('.js-comment').length){
  var text_count = $('.js-comment').val().replace(/\n/g, "").length;
  $('.js-text-count').text(text_count);
  }


  $('.js-comment').on('keyup', function () {
   //今回は改行や空白も数える。
   //文字数をカウント
    var text_count = $(this).val().replace(/\n/g, "").length;
   //カウントした数を表示させる
    $('.js-text-count').text(text_count);
    //255文字以上ならエラークラス付与＆エラーメッセージ。ボタンも押せなくする。
    if(text_count > 255){
      $('.js-comment').addClass('err');
      $('.js-error').show();
      $('.js-submit').prop("disabled", true);
    }else{
      //条件に入らなければエラー文消す。ボタン活性化
      $('.js-error').hide();
      $('.js-comment').removeClass('err');
      $('.js-submit').prop("disabled", false);
    }
  });
```

ポイントは
```app.js
 $('.js-submit').prop("disabled", true);
```
これでボタン非活性。逆にtrueをfalseにすればまたボタンをまた押せる。
完成形は下の様なイメージ。分かりづらいですが、エラー時は登録ボタンも押せなくなってます。
![ezgif.com-gif-maker.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/920917/0d50f007-1728-635a-ab75-8e8b8d02c28f.gif)
2022/4/18主にITとかセキュリティの記事

京都駅ビル開発、サーバーへの不正アクセスが発覚　利用客 約950件、取引先 約3,400件などの個人情報が流出の可能性　クレジットカード情報はない(4/16)
https://ampmedia.jp/2022/04/16/kyotosb-fusei/

サポート詐欺とは｜仕組みや偽警告の消し方を解説(4/15)
https://news.nifty.com/article/technology/techall/12276-1579492/

社説：クレカ被害　便利さのリスクに注意(4/16)
https://www.kyoto-np.co.jp/articles/-/773638

Apple、Siriで購入を可能にする計画を中止していた〜プライバシー侵害を懸念(4/16)
https://iphone-mania.jp/news-450334/

改正個人情報保護法
個人データの利用停止・消去請求権を拡充(4/15)
https://www.jimin.jp/news/information/203304.html

世界の検索エンジンシェア、Googleの一強が続く(4/16)
https://dime.jp/genre/1368737/

Windows10、11更新後　ブラウザがクラッシュ(4/16)
https://jp.sputniknews.com/20220416/windows1011-10636444.html

黒田小「学校預かり金」誤入力で保護者口座から49万円引き落とし(4/15)
https://www.joetsu.ne.jp/179087

ブレア元米国家情報長官、日本「英並みサイバー能力を」(4/16)
https://www.nikkei.com/article/DGXZQODE161KY0W2A410C2000000/
MacBook Pro 2017でシステムデータが大きすぎるからiCloudバックアップで初期化する

# はじめに
4年も使っているMacBook Proの容量がほとんどなくなった。
![スクリーンショット 2022-04-16 17.16.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/353004/e7f5320a-1536-9cea-1e48-b8ca4ebaa02c.png)
書類やデータはほとんどiCloudに移していて、
アプリケーションも使わないものはどんどん消したにも関わらず、空き容量がない。
特に「システムデータ」が大きすぎる。

最近どうも動作が重かったりファンがよく回るので、良い機会だから初期化してみます。

# 環境

MacBook Pro (2017, 256GB)
macOS Moonterey

# 必要なデータをiCloudにバックアップする
デスクトップと書類フォルダのデータは常にiCloudに同期する設定をしていましたが、
他の場所にあるデータも全てiCloudに入れました。

# macOSを再インストールする
(この手順はIntelのチップを搭載するmacbookが対象です。
Appleチップ搭載の場合は [このリンク](https://support.apple.com/ja-jp/HT212749) を参考にしてください)  
<br>
OSの初期化は、
https://support.apple.com/ja-jp/HT208496 を参考にして実行します。

まず、ファイルのバックアップが完了したら、
* iCloudからサインアウト
* iMessageからサインアウト

を済ませておきます。

次に、macの電源を切り、[ディスクユーティリティに従ってIntel搭載のMacを消去する](https://support.apple.com/ja-jp/HT208496) を行います。
Mac の電源を入れてすぐに「command (⌘) + R」キーを長押し → 管理者ログイン で次の画面が表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/353004/84e8e29c-b90b-0e2b-7ec4-193f24779ea9.png)
あとはリンク先の手順に従って内蔵ボリュームとユーザの削除を完了してください。

上の画面に戻ったら、「macOS Montereyを再インストール」に進みます。
詳細は[ここ](https://support.apple.com/ja-jp/HT204904)にあります。インストール中はmacbookの蓋は閉じないほうがいいみたいです。


# OSの再インストールで選択するディスクがない
原因は分かりませんが、内蔵ディスクの削除を終えたあと、
Montereyの再インストールをしようとしたら、ディスクが選べませんでした。
![IMG_1651.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/353004/2053980c-81a2-3938-ed9f-adeeb8f4966b.jpeg)
なので一度再起動してみると、High Sierraのリカバリーモードで起動されました。
![IMG_1653.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/353004/eaa66a98-9f4d-eae0-fbdc-000a36a7f63a.jpeg)
面倒でしたが、「macOSを再インストール」からHigh Sierraを入れて、
その後でAppStore経由でMontereyにアップグレードする形になりました。

（アップグレードのインストール中に「"null"を確認中...」で止まってしまい、
それ以降進まない問題が発生しましたが、強制的に再起動し、
リカバリーモードからもう一度内臓ボリュームの削除 → High Sierraのインストール → Montereyにアップグレード で解決しました。）

# NVRAMをリセットする（任意）
(この手順はスキップしても問題ありません)

NVRAM (不揮発性ランダムアクセスメモリ) は音量や画面解像度、
そして最近起きたカーネルパニックの情報などが記憶される小容量のメモリです。

これらの設定情報に関する問題が起きている場合は、
NVRAMのリセットで解決できる場合があります。
例えば次のような場合です。
>システム環境設定の「起動ディスク」パネルで指定したものとは異なる起動ディスクから 
Mac が起動する場合や、Mac の起動時に疑問符アイコンが表示される場合は、
NVRAM のリセットが必要だと考えられます。

OSの再インストールが完了すると、再起動されますが、
設定を続けずに「command (⌘) + Q」キーを押してシステム終了してください。

続いてmacの電源を入れたら、
「option」「command」「P」「R」の 4 つのキーを同時に押し、
20 秒ほど押し続けてからキーを放します。
![スクリーンショット 2022-04-16 18.21.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/353004/24446b4e-0fae-1a8b-fbad-3ed74a952350.png)
リセットされるとmacは再起動し、設定アシスタントが再び表示されます。
あとは表示される手順に従いましょう。

# 新しいOSにログインしたら、iCloudを同期する
これで完了です。
さて、112.77GBもあった「システムデータ」はどれだけ減ったかというと...
![スクリーンショット 2022-04-18 4.13.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/353004/282a1899-6682-cb24-bd0a-a9a18ef36f9c.png)
スッキリしました。
あとはiCloudを同期して、必要なデータをまた戻すなどして完了。

# おわりに
少ししたら、相変わらずファンがうるさく回り始めた。
iCloud Driveの同期が原因かもしれない。
アクティビティモニタ見るとbirdとかclouddなどのプロセスがCPU消費してる。

全て完了するまで、半日くらいはかかった。
あと、Time Machineで復元する方法もあるが、特に古いmacbookだと何が起こるか分からないので、大切なデータは別の安全な場所に保存しておくといいかもしれない。

とりあえずサクサク動くようになったから満足。
初代GPD WINをシンセ専用Linux機として使う

初代GPD WINはWindowsを入れて使うともっさりだがLinuxならサクサク。これをお手軽ウインドシンセ用音源として使わない手はない。

### 用意するもの ###
GPD WIN本体
USBメモリ (4GBでイケるかな？)
WiFiが繋がる環境

### インストール用ISOイメージ取得 ###
[ここ](https://ubuntu-mate.org/download/)にあるGPD Pocket用のイメージをダウンロードし、USBメモリに焼く。焼き込みには[balenaEtcher](https://www.balena.io/etcher/)が便利。

### インストール ###
GPD WINにUSBメモリを挿し、電源を入れたらDELキー押しっぱなしでBIOSに。BOOTセクションで最初のブートデバイスにUSBメモリを指定して、Save and Exit。

インストーラーが起動したら意のままにインストール。最小インストールでいい。インストールが終わったらUSBメモリを抜いてEnterキーで再起動。

### MATEじゃないUbuntuのインストール ###
ターミナルを開いて
```
$ sudo apt install ubuntu-desktop -y
```
ただし重いのでMATEのままの方が良い。

### シンセの設定 ###
Pulse Audio Serverは44.1kHzから192kHzまでサポートしてるが実際のデバイスがサポートしてるのは48kHz。それ以外はサンプリングレートコンバーターが挟まると思う。実際のハードウェアはchtrt5645。バッハサイズは256が限界で、それより小さいとノイズにしかならない。
JavaScript Proxyの使い方

## Proxyとは
Proxyを使うことで元のObjectのproxy(代理)として処理を中継できます。
元の処理以外の処理を追加することで、元のObjectに影響を与えずにObjectを再定義することができます。

## Proxyの作成
```js
//Proxyオブジェクトのコントラクタの第一引数に元のObject、第二引数に元のObjectへの追加処理(ハンドラ)をわたします。
const proxy = new Proxy(target, handler);
//追加処理がない場合でも空のハンドラオブジェクトが必要です。
const array = [1,2,3,4,5];
const sample_proxy = new Proxy(array, {});
console.log(sample_proxy); // => [ 1, 2, 3, 4, 5 ]
```

## トラップの設定
ハンドラオブジェクトにトラップ(=メソッド)を設定することで処理を割り込ませることができます。
```js
const student = {
  name: 'Tanaka',
  age: 18,
  major: 'Math'
};

const proxy = new Proxy(student, {});
//ハンドラは空なので、プロキシは元のターゲットと同じ動作をします。
console.log(student.name); // => Tanaka
console.log(proxy1.name); // => Tanaka

//get()トラップを使うことでプロパティの値の取得に割り込みをします。
const handler1 = {
  get(target, prop, receiver){
    return target[prop].toUpperCase()
  },
};

const proxy1 = new Proxy(student, handler1);
console.log(proxy1.name); // => TANAKA
//handler1のget(target, prop, receiver)について、
//この場合targetはstudent、propはname、receiverは{ name: 'Tanaka', age: 18, major: 'Math' }となります。
```
## プロパティへのアクセスのカスタマイズ
set()トラップを使用してプロパティへのアクセスをカスタマイズができます。
数字1桁、小数点第2位までの数字を受け付けそれ以外はエラーを返す配列インスタンスのproxyを作成してみます。

```js
const numbers = [1, 2.0, 3.11];

const proxy = new Proxy(numbers, {
    set(target, prop, value) {
    const pattern = /^[0-9]{0,1}(\.[0-9]{1,2})?$/
    if (!pattern.test(value)) {
        throw new Error('Illegal Pattern');
       }
    target[prop] = value;
    }
})

proxy[0] = 1.0;
proxy[1] = 2.1;
proxy[2] = 3.12;
console.log(proxy) // => [ 1, 2.1, 3.12 ]
proxy[3] = 3.111;  // => Error: Illegal Pattern

```

## Reflectの使用
Reflectクラスを使うことで簡単に元のオブジェクトへの操作を呼ぶことができます。

```js
const student = {
  name: 'Tanaka',
  age: 18,
  major: 'Math'
};

//ownKeysメソッドで元のオブジェクトが所有するキーの返却ができます。
console.log(Reflect.ownKeys(student)); // => [ 'name', 'age', 'major' ]

//handler1と同じくget()トラップを使いpropを大文字にしますが、propがnameの時だけに限定し、
//他は元のオブジェクトのプロパティを返します。
const handler2 = {
  get(target, prop, receiver){
    if (prop === 'name') {
      return target[prop].toUpperCase();
    }
    return Reflect.get(target, prop);
  },
};

const proxy2 = new Proxy(student, handler2);
console.log(proxy2.name); // => TANAKA
console.log(proxy2.age); // => 18
console.log(proxy2.major); // => Math

```
## proxyを使用した関数への割り込み

apply()トラップを使用することで、関数の呼び出しに割り込むことができます。

```js
  const multiply = (a, b) => {
    return a * b;
  }
  
  const handler = {
    apply(target, thisArg, argumentsList) {
      console.log(target); //=> [Function: multiply]
      console.log(target(4,8)); //=> 32
      console.log(thisArg); //=> undefined
      console.log(argumentsList); // => [4, 8]
      return target(argumentsList[0] ** 2, argumentsList[1] ** 2);
      // 下記に入れ替えても同じ結果が得られる
      // return target.apply(thisArg, argumentsList.map(num => num ** 2));
    }
  };
  
  const proxy = new Proxy(multiply, handler);
  console.log(proxy(4, 8)); => 1024
  //handlerのapply(target, thisArg, argumentsList)について、
  //この場合targetはmultipy関数、thisArgこの呼び出しに対するthis引数
  //argumentsListはこの呼び出しに対する引数リストとなります。
```
[Unity]半透明のオブジェクトを作る方法（備忘録）

透けるオブジェクトの作り方の備忘録。unity側をちょこっと操作するだけだった。

:::note info
使用PC： MacBook Pro (13-inch, M1, 2020)
OSバージョン: 11.5.2
Unityバージョン：2020.3.30f
:::

# 完成図
これを
![スクリーンショット 2022-04-18 2.06.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/890419/a29ae52e-b217-ff05-1b78-27c0ec04cc1b.png)

こうする
![スクリーンショット 2022-04-18 1.55.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/890419/8d26d932-09d0-474b-9af3-58b6a5b8a746.png)

# やり方
①【Projectビュー】→【＋】→【Material】を選択
![スクリーンショット 2022-04-18 2.08.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/890419/0b2cbd07-9a81-7e17-6b55-973ad1699f2b.png)

②名前をwhiteとか適当に変えておく

③作成したMaterialを選択し、【Inspectorビュー】→【Rendering Mode】→【Fade】をを選ぶ
![スクリーンショット 2022-04-18 2.11.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/890419/b69a3025-02c5-88a2-d720-ce89b934fedf.png)

④【Inspectorビュー】→【Main Maps】→【Albedo】から、かラーパレッド的なやつを開く

⑤ALPHA値をいい感じに調整する
![スクリーンショット 2022-04-18 2.13.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/890419/5a5d8dac-6968-6a16-3676-3132e6285348.png)

# 以上！！簡単！！！！！
Next.js入門してみた

Nuxt.js2 + TypeScript しか触ったことない人が Next.jsを入門したくなった話

## 用意したもの
node v14.17.2
npm 8.7.0
yarm 1.22.4
Next.js
MaterialUI
Emotion
StoryBook
ESLint
Prettier


## 導入コマンド
```
# Next.jsのプロジェクト作成
 npx create-next-app@latest
# フォルダが2重になっていたので1つ外に出した
 mv * ../
# 開発鯖動かしてみる -> 動いた
 npm run dev
# MaterialUIとEmotion
 yarn add @mui/material @emotion/react @emotion/styled
# MaterialUIのアイコン
 yarn add @mui/icons-material
# Storybookを追加
 npx sb init --builder webpack5
# TypeScript入れ忘れたので慌てて追加
 yarn add --dev typescript @types/react @types/node
# ESLint追加
 yarn add -D eslint @typescript-eslint/eslint-plugin @typescript-eslint/parser
# Prettier追加
 yarn add -D prettier eslint-config-prettier eslint-plugin-prettier
# パッケージ更新
 yarn upgrade
# とりあえず動く
 yarn run dev
```

## んで、次何する?
- TypeScriptを後から入れたのでページを修正 [参考](https://gist.github.com/elzup/db2229b132ccda46d4ac3b25a52b60b7)
- この時点ですでにeslintに怒られてたので修正 [参考](https://chaika.hatenablog.com/entry/2020/12/04/083000)

## とりあえず公式チュートリアルを進めよう
TypeScriptではないがここに公式チュートリアルがあり、ある程度はここで学ぶことができる
Nextでは各ファイルをjsx/tsx って名称で終わらせて `const hoge = () => {} export default hoge`
みたいな描き方するのがお作法っぽい

https://nextjs.org/learn/basics/create-nextjs-app

## さてこの次何する?
(ここで Nuxt3が気になりだし、Nuxt3に浮気してしまったため未完)


### 参考
https://mo-gu-mo-gu.com/create-next-app-typescript/

https://reffect.co.jp/react/next-js

https://storybook.js.org/blog/get-started-with-storybook-and-next-js/

https://zenn.dev/ttani/articles/next-materialui-setup

https://qiita.com/dosukoi_man/items/8324a5a712fd36a758f4

https://gist.github.com/elzup/db2229b132ccda46d4ac3b25a52b60b7

https://chaika.hatenablog.com/entry/2020/12/04/083000

https://qiita.com/taskeknight/items/7772981e32166b1a6c5e

https://qiita.com/syuji-higa/items/931e44046c17f53b432b

https://zenn.dev/nus3/articles/257d724e24a39b756b5a
pyenv+venv環境をwls2+ubuntu20.04でつくる

# いつも忘れる環境構築
いつもいつも環境を壊したり、pcを乗り換えるたびに忘れるこの手の環境構築を備忘録としてメモしたい。
とはいっても、備忘録的なやつなので、他サイトの引用をばちばち使う。

前提、makeが通るよう状態か確認。なかったら以下を実行。

```
sudo apt install build-essential
```

あとは、以下のurlの「システム Python とは別に Python 3.8 をインストール （pyenv を使用）」の３まで実行。pyenv shellはやらなくていい。

(記事)[https://www.kkaneko.jp/tools/ubuntu/ubuntu_pyenv.html]

そこからは、自分が作成したいディレクトリに移動して、以下を順に実行
自分がインストールしたいバージョンをインストール。今回は3.8.0
```
pyenv install 3.8.0
```
次に、localする
```
pyenv local 3.8.0
```
venv環境作成
```
python3 -m venv venv
```

以上。

あとは
```
source venv/bin/activate
```
でvenv環境に入ってpipでinstallするだけ。

多分。。。。
JSの基本-タブバー切り替えの実例

JSの基本-タブバー切り替えの実例


実現した効果：
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2632252/2ee9df28-0d48-6356-7dcd-e766cf2920e7.png)



上のモジュールの下にあるテキストをクリックして、それに応じて表示します。

アイデア：

全体は2つの部分に分かれています。最初の部分は、上の項目をクリックして、クリックされた効果のあるものに対応する方をクリックすることです。記事ブログ：JSの基本-排他的な思考ケース_setTimeout（）ブログ-CSDNブログ

 2番目の部分は、上の項目をクリックして下のコンテンツを表示することです。これはカスタム属性によって実現されます。ここでは、上と下のカスタム属性を設定します。完全なコードは次のとおりです。

```ruby:
<!DOCTYPE html>
<html lang="en">
 
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>tab切り替え</title>
    <style>
        * {
            margin: 0;
            padding: 0;
        }
        
        .box {
            width: 800px;
            height: 100px;
            margin: 200px auto;
        }
        
        .box .tabtop {
            width: 800px;
            height: 40px;
            background-color: #eef1ee;
        }
        
        .box .tabtop ul li {
            list-style: none;
            float: left;
            line-height: 40px;
            padding: 0 10px;
            font-size: 14px;
            cursor: pointer;
        }
        
        .hs {
            color: #fff;
            background-color: #c61521;
        }
        
        .box .tabitem {
            font-size: 14px;
        }
        
        .box .tabitem div {
            display: none;
        }
    </style>
</head>
 
<body>
    <div class="box">
        <div class="tabtop">
            <ul>
                <li class="hs">商品紹介</li>
                <li>規格と梱包</li>
                <li>アフターサービス</li>
                <li>商品詳細(50000)</li>
                <li>スマートフォン</li>
            </ul>
        </div>
        <div class="tabitem" id="tb-item">
            <!-- 内容部 -->
            <div style="display: block;">商品紹介モジュール内容</div>
            <div>企画梱包内容</div>
            <div>アフターサービス内容</div>
            <div>商品詳細内容</div>
            <div>スマートフォン内容</div>
            <div></div>
        </div>
    </div>
    <script>
        // 全てli要素取得
        var lis = document.querySelectorAll('li');
        // 全て内容部要素取得
        var content = document.getElementById('tb-item').querySelectorAll('div');
        // 上記の内容部カスタマイズ
        for (var i = 0; i < content.length; i++) {
            content[i].setAttribute('index', i);
        }
        for (var i = 0; i < lis.length; i++) {
            lis[i].setAttribute('indexs', i);
        }
        for (var i = 0; i < lis.length; i++) {
            lis[i].onclick = function() {
                for (var j = 0; j < lis.length; j++) {
                    lis[j].className = '';
                }
                this.className = 'hs';
                for (var j = 0; j < content.length; j++) {
                        for (var k = 0; k < content.length; k++) {
                            content[k].style.display = 'none';
                        }
                        content[j].style.display = 'block';
                    }
                }
 
            }
        }
    </script>
</body>
 
</html>
```
JavaScript コールバック関数の使用例

## コールバック関数とは
関数の引数に関数を渡すことで実現されます。
呼び出し先で実行してもらう関数と考えてください。
コールバック関数を使うことで、ある処理が終わったら次の処理を実行、次の処理が終わったらその次といった具合に
処理を連続して記述していくことができます。
※多用すると可読性が悪くなる(=コールバック地獄)ので注意が必要です。

## mapを使用した実装例
```js
const array = [1,2,3,4,5];

//引数の数値を2乗する関数
const squareNumber = (number) => number * number;

//mapメソッドを使ってsquareNumber関数（ここではコールバック関数)を呼びます
const new_array = array.map(squareNumber);
//これは以下と同じ動きです
array.map((number) => number * number);

console.log(new_array);　// => [1,4,9,16,25]
```

mapを使い配列の要素を1つずつ取り出し、取り出した要素をsquareNumber関数の引数にして関数を実行しています。

## コールバック関数の応用
コールバック関数をうまく利用して、処理の内容・順番を柔軟に変化させることができます。
```js
//例) 
//下記の２つの関数があります
//底を指数で累乗する関数
const baseExponent = (base, exponent) => Math.pow(base, exponent);
//絶対値を返す関数
const absoluteDifference = (num1, num2) => Math.abs(num1 - num2);

//通常はbaseExponent(2,10)のように数値を引数として関数にわたしますが、
//引数にわたす数値だけが先に決まっているとします。
//処理をつなぎ、数値を引数として受け取り、後からコールバック関数を受け取って
//コールバック関数を実行する関数をつくってみます。
const sampleFunc = (...args) => func => func(...args);
//上記関数に先に数値を引数としてわたします。
const numberAppliedFunc = sampleFunc(2,10);

//後から柔軟に関数を適用させることができます。
console.log(numberAppliedFunc(baseExponent)); // =>　1024
console.log(numberAppliedFunc(absoluteDifference)); // => 8

```
【備忘録】.phpから別の.phpにある変数を参照する

web開発初心者の備忘録です。
オリジナリティあふれるソースコード。
# ポイント
require関数を使って.phpを読み込むことで、記述されているグローバル？な変数を参照できる。

https://www.php.net/manual/ja/function.require.php
# ファイル構成
```
IISでルートに設定しているフォルダ
　└ test
　　　├ main.html
　　　├ main.php
　　　├ lib.php
　　　├ info.php
　　　├ main.js
　　　└ jquery-3.6.0.js
```
# ソースコード
```html:main.html
<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8"/>
    <title>test</title>

    <script type="text/javascript" src="jquery-3.6.0.js"></script>
    <script type="text/javascript" src="main.js"></script>
</head>

<body>
    <button onclick="hoge()">実行</button>
</body>

<script type="text/javascript" src="main.js"></script>

</html>
```
```javascript:main.js
function hoge() {
    $.ajax({
        type: "GET",
        url: "../test/main.php",
        timeout: 5000
    }).done(($data) => {
        console.log("done");
        console.log($data);
    }).fail(($data) => {
        console.log("fail");
        console.log($data);
    }).always(() => {
        console.log("always");
    });
}
```
```php:main.php
<?php    
    require('lib.php');
    sleep(3);

    echo sample();
?>
```
```php:lib.php
<?php   
    function sample() {
        require('info.php');
    
        return $Message;
    }
?>
```
```php:info.php
<?php    
    $Message = "連れてこられたデータ";
?>
```
# 結果
![スクリーンショット 2022-04-18 010406.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2628832/eef53e0f-7e77-0a21-2977-142ee5db5fec.jpeg)
いいね
![スクリーンショット 2022-04-18 010452.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2628832/ecb0becd-0422-322c-dfb6-6bcda350a31c.jpeg)
ちなみに、require関数をsample関数の外に置く(#includeみたいなポジションに記述する)と、WarningページのHTMLを投げ返されます。あくまで呼び出したスコープの範囲内でしか参照できないみたいですね。
# 最後に
…やっぱりヘッダファイルくんの代わりなんてどこにもいないんだね。
- 初学者の備忘録です。
- 片手間でやっているので、記述が曖昧＆雑です。
- 動作したコードをそのまま載せていますが、摩訶不思議な力によりほかの環境では動かないかもしれません。
AWS-RDSで本番環境のSnapshotを開発環境に展開する方法

開発環境のRDSを本番環境のデータで置き換える必要があったので、その方法のメモです。
そこまで複雑な手順ではないですが、忘れてしまいそうなので手順をまとめておこうと思います。

# 本番環境でSnapshotを作成
AWSのマネジメントコンソールから対象DBのSnapshotの作成を行います。
![2022-04-17_17h17_49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/626057/07a51e39-bfb3-a40f-60b2-f642f6096b0a.png)

# Snapshotの共有
作成されたSnapshotを選択し、スナップショップの共有（Share snapshot）を選択します。
![2022-04-17_17h26_05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/626057/55a349b1-0b0e-889d-5b66-89a2d64a585d.png)

> この時に、以下のようなメッセージが表示された場合、共有可能なキーで暗号化した上で、共有する必要があります。
![2022-04-17_17h43_23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/626057/2e2511a1-4046-30be-322c-373b98f7e88c.png)



# 暗号キーの作成
Key Management Service(KMS)を使用し、Snapshotを暗号化するためのキーを作成します。

***1. キーの作成 (Create key)をクリック***
![2022-04-17_17h34_20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/626057/128c4b82-49be-6419-5de4-22d5af81ccdd.png)

***2. 次へ(Next)をクリック***
![2022-04-17_17h35_50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/626057/807ffc4d-e4f2-1bb8-5907-3723c5442b6b.png)

***3. エイリアスを入力し、次へ(Next)をクリック***
![2022-04-17_17h37_01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/626057/fd88218a-40c1-1c2e-1377-8768851bcde9.png)

***4. デフォルトの権限は何も選択せずに、次へ(Next)をクリック***
![2022-04-17_17h38_32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/626057/13b1e410-d7f6-ba1c-349c-bbbbc0d0ab22.png)

***5. 共有先のAWSアカウントのIDを入力し、次へ(Next)をクリック***
権限の設定は不要です！
![2022-04-17_17h39_56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/626057/9f735c46-b64a-49f1-3ee4-6cf50c32e613.png)

***6. 終了(Finish)をクリックし、作業を完了する***
![2022-04-17_17h41_29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/626057/8b802485-6175-cc58-35f1-e51198274a3b.png)


# Snapshotのコピーを作成
先ほど作成したキーを使用し、先の手順で作成したSnapshotのコピーを作成します。

***1. スナップショットのコピー (Copy snapshot) をクリック***
![2022-04-17_17h44_13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/626057/b48d5ff0-3acb-3ca1-102a-b59b57874d20.png)

***2. スナップショットの名前を入力し、先ほど作成したAWS KMS Keyを選択***
![2022-04-17_17h46_31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/626057/d8074592-449a-4c54-2b95-bffc3442ea60.png)

# Snapshotの共有
先ほどコピーしたスナップショットを選択し、スナップショットの共有を実行します。

***1. スナップショットの共有 (Share snapshot) をクリック***
![2022-04-17_17h50_34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/626057/0fcebdbc-e042-d561-1a49-6c0c92c9a046.png)

***2. 共有先のAWSアカウントのIDを追加し、保存(Save)をクリック***
![2022-04-17_17h52_20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/626057/fd9f1ef4-da8d-e28c-21d5-6d4e0f080e07.png)

# 共有先のRDSにて、共有されたSnapshotを展開
先ほど共有されたスナップショットがリスト(Share with me)に表示されるので、対象のスナップショットを選択。
スナップショットの復元（Restore snapshot）を選択し展開する。
![2022-04-17_17h57_22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/626057/24d4c9d9-4854-2345-849a-b7751277728d.png)

>本番環境からのコピーは、新規のRDSインスタンスとして立ち上がるので、接続しているアプリの接続情報等を変更する必要があります。

以上で、作業は完了です。
炎上案件との戦い

私の実体験をもとに炎上案件でどのような対応をしていたかをつらつらと書きます。
炎上しないための案件の進め方や、同じように炎上案件と戦っている方の立ち回りに役立てられればと思います。
また、現在も進行中の案件のため、必要に応じて情報をアップデートさせていただこうと思います。

# 案件概要
とあるシステムリプレースで、汎用機系から、LAMP構成（FW=Laravel）に変更する。
仕様は現行踏襲だが、連携方式の変更、画面をレスポンシブデザインに変更、業務上発生しない処理、機能は廃止する。

# 私の立ち位置
進行案件の途中（製造単体フェーズ）から参画（他7名のメンバーも参画）。
SE・PGとして3ヶ月、それ以降（9ヶ月）はPLの役割で立ち回っていました。
※親会社メンバー（PL）が多忙により、PL補佐に変更となり、途中から私がPLになりました。

プロジェクトメンバーは、以下の構成でした。
* 私の所属のメンバー：8名（PG：8名）
* 私の所属の親会社メンバー：7名（PG：5名、PL：1名、PM：1名）
* 外部ベンダー1社（親会社発注）

内製チームは、バッチ機能を中心で、画面機能を一部担当していました。
外部ベンダーは、画面機能のみを担当していました。

# 参画時の案件状況と対応
## 開発機能数、工数
##### 状況
* 開発機能数の全体数が明確になっておらず移行対象機能が不明確
* 作業タスクのレベルが荒く、実作業が不明確
* 作業タスクの工数見積がされていない

##### 対応
* システム全体の機能の洗い出し及び、PMへ移行対象機能の決定するように調整
* 開発以外の移行計画等の作業タスクを明確化
* 現行ソースのSTEP数からマイグレーション工数見積し、スケジュール提示およびリスケ調整
* リスケ期間圧縮のための人員調達の調整
* 現行踏襲でも仕様変更があれば設計フェーズを必ず設定

##### 予防策
* 開発見積段階で、移行対象を明確にした上で開発工数を見積
* リプレースで発生しうるデータ移行計画タスクの明確化
* PJ管理では、タスクの単位を最小にし、期間、工数を管理

## 開発方針
##### 状況
* クラス設計不足で、継承親クラス、子クラスの開発が進捗が停滞
* 当初から参画しているメンバーには、FWを熟知していない（＝テックリード可能な人材不在）
* 最新化されていない現行の詳細設計書ベースの開発（＝最新でないため、品質担保できない）

##### 対応
* クラス設計を早期対応し、継承親クラス、子クラスの開発を推進
* 私がテックリードとして、メンバー教育を推進
* 現行ソースコードをトレースしてマイグレーション（現行ソースコードの読み方は私の方で教育）

##### 予防策
* クラス設計は製造フェーズまでに完了
* FWを十分熟知したメンバーの参画もしくは、案件前教育でFWを十分理解
* ドキュメントは常に最新化
* リプレースにおいては現行ソースコードを解読して新システムの言語へのマイグレーションも検討

## 仕様変更
##### 状況
* クラシカルなデザインからレスポンシブルデザインへの変更点が未確定
* データ連携をミドルウェアを使用せずにファイル転送に変更するが設計未着手

##### 対応
* ポイントになる要素の新旧対比表作成（最終的にはエンドユーザー説明にも活用を目的）
* データ連携ミドルウェアの仕様調査および拡張性がある設計（DI等）、開発を推進

##### 予防策
* 要件定義フェーズにて、新旧仕様対比表を作成
* 仕様変更部分の設計は、設計フェーズで完了

# 炎上案件でのメンタリティー
私自身、ここまで酷い案件は初めてでした。
それだけに、この状況を立て直したら、相応の評価がされて自身の昇格にも繋がると考えていました。
また、誰もがダメだろうと思われている中で、見返してやろうと強い気持ちも持つようにしていました。
さらに、炎上案件はなかなか体験できることではないため、私自身の成長にも繋がると考えて取り組んでいました。

# 炎上案件での成果
## 効率化意識向上
本案件以前から効率化意識を持って作業していましたが、
タスクの遂行順序、メンバーの作業割振など
いかに効率良く作業を進めるかより一層意識するようになりました。

## メンバースキルの認知力
各メンバーのアウトプットに対するコスト、品質、必要に応じてコードチェックを行い、
開発スキルを理解することに努めることで認知力が高まった。
それによってメンバーの最適な作業割振にも活かすことができた。

## 案件推進力
立場上、多くのメンバーから質問、課題が来ることもありましたが、
スピード感を持って判断を下すことを意識して回答していました。
それにより開発の手を止めないということを意識して取り組みました。
時には、判断に悩むことがありましたが、悩みに悩むよりもまずは決断することを大事にしていました。

開発と結合が同時並行できるように、結合テスト実施順序を意識した開発順序を設定していました。
また、結合テストで外部ベンダー対応待ちになる場合は、データメンテで先の手順の確認を進められるよう調整。

リプレースにおいて、品質担保を確認するために効率的なのは、新システムと現行システムで同じデータを発生させ、処理ごとに更新テーブルの際を確認することと考え、実践しておりました。
それにより、テストでどの段階で問題があるか、またデータを見なければ気づけない問題にも気づくことができた。

# 反省点
本来、案件を進めるとともに、各メンバーの仕様理解、スキル向上も図って行きたかったが、
案件を進めることが最優先と考え、スキル向上を狙った作業の割り振りができなかった。

# 最後に
本投稿を読んでいただいた方々の少しでも助けになり、
炎上案件が少なくなっていけばと思います。
Dartの関数、引数定義チートシート

# はじめに
Dartの引数定義パターンがややこしすぎるので、一覧でまとめてみました。

```dart:
/// 通常の定義
void normalFunc(bool param1, bool param2) {
  // 引数名指定で関数実行はできない
  normalFunc(true, true);
}

///　引数に名前指定が必要な関数。
void withNameParamNormalFunc({required bool param1, required bool param2}) {
  // 引数順番を入れ替えて挿入することができる
  withNameParamNormalFunc(param2: true, param1: true);
}

/// オプショナルパラメータ
void optionalParamFunc({bool? param1, bool? param2}) {
  //　全てオプショナルなので引数なしで実行可能
  optionalParamFunc();

  // オプショナル関数の場合は、引数名の指定が必ず必要
  optionalParamFunc(param2: true);
}

/// オプショナルパラメータ(デフォルト引数あり)
// デフォルト引数ありの場合は、引数の型をnull非許容型として定義できる。
void optionalParamWithDefaultPramFunc({bool param1 = true, bool param2 = true}) {
  //　全てオプショナルなので引数なしで実行可能
  optionalParamFunc();

  // オプショナル関数の場合は、引数名の指定が必ず必要
  optionalParamFunc(param2: true);
}

/// オプショナル位置パラメータ
void optionalPositionParamFunc(bool param1, [bool? param2]) {

  // オプショナル引数を使用しない場合は省略可能
  optionalPositionParamFunc(true);

  // 最後のparam2は入れなくても良い
  optionalPositionParamFunc(true, true);
}

/// 位置パラメータを使用しないオプショナル
void optionalNotPositionParamFunc(bool param1, {bool? param2}) {
  // オプショナルパラメータへ挿入には、引数名の指定が必要
  optionalNotPositionParamFunc(true, param2: true);
}


/// 関数オブジェクトを引数にとる場合
/// 1と2両方とも、関数オブジェクトを引数にとる
//　引数指定パターン1
String? invokeFunctionObject1(String computation(int,String)?) {
  return computation?.call(1,"param");
}
//　引数指定パターン2
String? invokeFunctionObject2(String Function(int,String)? computation) {
  return computation?.call(1,"param");
}
```
PythonでGoogleAnalyticsからデータを取得する

# この記事の内容
- データを取得する基本的な方法
- filterを使ったデータの絞り込み方
- よく使うdimensionsとmetrics

# 参考記事
- 公式ドキュメント
    - [はじめてのアナリティクス Reporting API v4: サービス アカウント向け Python クイックスタート](https://developers.google.com/analytics/devguides/reporting/core/v4/quickstart/service-py?hl=ja)
- dimensionsとmetricsの一覧
    - [UA Dimensions & Metrics Explorer](https://ga-dev-tools.web.app/dimensions-metrics-explorer/)
- キーファイルとビューIDの取得方法
    - [PythonでGoogleAnalyticsから情報を取得するには](https://www.w2solution.co.jp/tech/2021/07/16/eg_ti_df_pythongoogleanalytics/) 

# APIからデータを取得する

## 前準備
```python
# モジュールをインポート
from oauth2client.service_account import ServiceAccountCredentials
from googleapiclient.discovery import build
import datetime
import os

# GoogleAnalyticsで設定したキーファイルとビューID等を指定する
SCOPES = ['https://www.googleapis.com/auth/analytics.readonly']
KEY_FILE_LOCATION = '生成したJsonファイル.json'
VIEW_ID = 'GAのViewID'

# APIオブジェクトを作成する
credentials = ServiceAccountCredentials.from_json_keyfile_name(KEY_FILE_LOCATION, SCOPES)
analytics = build('analyticsreporting', 'v4', credentials=credentials)
```

## 最も簡単な例（国ごとのセッション数を取得する）
```python
response = analytics.reports().batchGet(
      body={
        'reportRequests': [
        {
          'viewId': VIEW_ID,
          'dateRanges': [{'startDate': '7daysAgo', 'endDate': 'today'}],
          'metrics': [{'expression': 'ga:sessions'}],
          'dimensions': [{'name': 'ga:country'}]
        }]
      }
  ).execute()
```

## データの絞り込み(filter)

例として、日本の絞り込んだセッション数を取得する

```python
response = analytics.reports().batchGet(
      body={
        'reportRequests': [
        {
          'viewId': VIEW_ID,
          'dateRanges': [{'startDate': '7daysAgo', 'endDate': 'today'}],
          'metrics': [{'expression': 'ga:sessions'}],
          'dimensionFilterClauses': [
              {"filters": [
                  {"dimensionName": "ga:country",
                   "operator": "EXACT",
                   "expressions": 'Japan'}
              ]}
          ],
          pageSize: 50000,
        }]
      }
  ).execute()
```

- `operator`は`EXACT`（一致）だけでなく`GREATER_THAN`（指定したものより大きいもの）や`REGEXP`（正規表現）等がある

※pageSizeはデフォルトで1000なのでそれより大きくなる場合は指定する

# よく使うmetrics
metcicsとは：取得したいデータ
|metrics|意味|
| --- | --- |
|ga:session|セッション数|
|ga:transactionRevenue|収益|
|ga:transactionsPerSession|コンバージョン率|
|ga:itemQuantity|ECでの販売数|


※metricsは量的変数、dimensionsは質的変数を担当していると言える

# よく使うdimensions
dimensionsとは：データを分類するためのラベル

|dimensions|意味|
| --- | --- |
|ga:region|地域|
|ga:country|国|
|ga:year|年|
|ga:month|月|
|ga:day|日|
|ga:hour|時|
|ga:minute|分|
|ga:productBrand|ブランド名|
|ga:productName|商品名|
Piscineに落ちた社会人が原因を語る

# Piscineに落ちた社会人が原因を語る
今後受験を検討している社会人に向けて多少なりとも、参考になる情報を残そうと思います。
## Piscineとは
https://42tokyo.jp/

**Piscine**とは42tokyoというエンジニア養成機関への入学試験の名前です。
> ※42tokyoは「**学費完全無料**」「**経歴不問**」「**講師不在(学生同士で教え合う)**」ことが特徴のエンジニア養成機関です。

- 人生で1回のみ受験可能
- 約4週間の試験期間
- フルコミット前提の試験

となっております。

## 試験内容
試験内容については、明かすことができません。
また、採点基準も公表されていないです。

## 参加目的
本気でエンジニアを目指す集団と関わり、自分の**当たり前基準**を変えたかったからです。

## どれくらい時間を使ったか？
私は仕事を休まず、日中は仕事、業務後にPiscineという生活でした。
前半(1,2週目) 平日は4~6時間 休日は12時間ほど
![スクリーンショット 2022-04-18 0.05.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2286023/a2c393c2-ccd9-6c86-e27c-cf93734da48d.png)
後半(3,4週目) 平日は8時間 休日は12時間ほど
![スクリーンショット 2022-04-18 0.03.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2286023/38ac0ce9-b4b9-0ba8-264a-a07e4290a880.png)
約200時間ほど使いました。

## なぜ落ちたか？
課題の進捗で言えば、私の進捗と同等の方々も受かっているようだったので、**コミュニケーション**の足りなさだと思います。
自分の課題進捗に集中しすぎたあまり、落ちてしまったと分析しています。
参加を検討している社会人の皆様は、**コミュニケーションへの意識**を忘れずに参加していただきたいです。

## 最後に
やっぱり悔しいです。
前半本気になりきれなかった自分の甘さ、参加前の情報収集などもっとやれることがあったなと思います。
ただ、Piscineに参加して、普段の業務では触らない言語についての知識をつけることができましたし、
また、意識の高い学生・社会人の皆様と知り合えたことが本当に財産になったと思っております。
悔いのないように、「**Piscineにフルコミットする決意**」だけは持って参加してみてください！
皆様の成功を祈っております。
gin favicon

https://github.com/thinkerou/favicon
こちらを元にしました。

```golang
package middlewares

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"path/filepath"

	"github.com/gin-gonic/gin"
)

// パスの区切り文字にはos関係なくスラッシュで渡す。
func ServeFavicon(path string) gin.HandlerFunc {
	// "/"区切りのパスをosの区切り文字でのパスに変換。
	path = filepath.FromSlash(path)
	// 空文字でないandOSの区切り文字でないなら
	if len(path) > 0 && !os.IsPathSeparator(path[0]) {
		// 作業ディレクトリを取得
		wd, err := os.Getwd()
		// 作業ディレクトリの取得に失敗したら終了
		if err != nil {
			panic(err)
		}
		// 作業ディレクトリと引数のパスを結合
		path = filepath.Join(wd, path)
	}
	fmt.Println(path)

	// ファイルの情報を取得
	info, err := os.Stat(path)
	// エラーでないもしくは情報がないもしくはディレクトリなら終了
	if err != nil || info == nil || info.IsDir() {
		panic("Invalid favicon path: " + path)
	}

	// faviconを読み込む
	file, err := ioutil.ReadFile(path)
	// エラーなら終了
	if err != nil {
		panic(err)
	}

	reader := bytes.NewReader(file)
	log.Println("Success to regist ServeFavicon middleware.")

	// ハンドラを返す
	return func(c *gin.Context) {
		// リクエストのURIがちがければ終了
		if c.Request.RequestURI != "/favicon.ico" {
			fmt.Println(c.Request.RequestURI)
			log.Println("wrong uri.")
			return
		}
		// GET、HEAD以外なら
		if c.Request.Method != "GET" && c.Request.Method != "HEAD" {
			fmt.Println("wrong method.")
			status := http.StatusOK
			// OPTIONじゃないならStatusOK -> MethodNotAllowdに変更
			if c.Request.Method != "OPTIONS" {
				status = http.StatusMethodNotAllowed
			}
			c.Header("Allow", "GET,HEAD,OPTIONS")
			//ここで終了
			c.AbortWithStatus(status)
			return
		}
		// GET、HEADならfaviconを返す。
		c.Header("Content-Type", "image/x-icon")
		http.ServeContent(c.Writer, c.Request, "favicon.ico", info.ModTime(), reader)
	}
}
```

## つまづいたところ
キャッシュの削除すればよかと思っていたが、その上に追加でブラウザの再起動をしないといけないのを知らなくて時間をとってしまった。
シェルスクリプトで`expr`で四則演算する際は掛け算の書き方に注意

備忘メモです。

シェルスクリプトで`expr`使う場合は以下の通り記載する。
（特に掛け算をする場合は\でエスケープが必要である事に注意、エラーになって後から原因特定するのが大変だった。。）

```sh
# 足し算
expr $a + 2

# 引き算
expr $a - 2

# 割り算
expr $a / 2

# 掛け算(\でエスケープが必要!!)
expr $a \* 2
```

以上です

# 参考
https://ike-dai.hatenablog.com/entry/20101026/1288103158
「マイクロサービスパターン」の復習 1章 モノリシック地獄

## 1章 モノリシック地獄からの脱出

- モノリシック地獄
- マイクロサービスアーキテクチャの基本的な考え方
- マイクロサービスアーキテクチャの利点・欠点
- パターン言語とマイクロサービスアーキテクチャパターン
- マイクロサービスアーキテクチャと組織

## モノリシック地獄

- 最初は、綺麗に設計できていれば開発もスムーズだけど、大きくなるにつれてそうもいかなくなる
- 変更の影響範囲が分からなくなるので、開発が遅くなる
- 一つのコードベースだと、常に不安定で、ビルドが通らない
- 自動テストをやっていても、テストに時間がかかる
- （垂直）スケーリングしづらい
    - CPUが必要なモジュールもあれば、メモリが必要なモジュールもあるので

## マイクロサービスアーキテクチャの基本的な考え方

- スケールキューブという考え方がある
    - X軸：いわゆる水平スケーリング
    - Z軸：パーティショニングによるスケーリング
    - Y軸：機能分割によるスケーリング
- マイクロサービスアーキテクチャは、Y軸によるスケーリングを実現する

- SOAの特徴
    - ESBありきの重量級プロトコルを採用する
    - グローバルデータモデル
- SOAは、一つのドメインモデルを、複数プロセスで実現する感じか？プロセスが別れていても密結合な印象を受ける
- ドメイン自体を分割するマイクロサービスアーキテクチャとは、結構違うのかもしれない

## マイクロサービスアーキテクチャの利点・欠点

- 利点：ここのサービスが小さく自立しているので、開発しやすい、テストしやすい、デプロイしやすい、個別にスケーリングできる、障害が分離できる、テクノロジスタックを変えられる
- 欠点：分割方法を見つけるのが難しい、分散システム自体が難しい（部分的に死んでる場合がある、サービスまたがりのトランザクションが使えない、結合テストしづらい）、サービス間の依存関係を考慮したデプロイが必要、マイクロサービスアーキテクチャを使うべきか否かの判断が難しい

- いつマイクロサービスアーキテクチャを採用すべきか
    - 最初はモノリシックで初めて、ある程度大きくなったらマイクロサービスアーキテクチャに切り替えるのがよいのこと
    - 個人的には、一度、モノリシックで開発の流れができてしまったらそう簡単には変えられないのでは？と思う
    - 13章で、モノリシックをマイクロサービスアーキテクチャにリファクタリングする方法を紹介する予定

## パターン言語とマイクロサービスアーキテクチャパターン

- パターン：繰り返し発生する問題に対する解決方法。利点だけでなく、欠点や新たな問題も記述されていることが重要
- パターンの関係性：先行・後続の関係、汎化・特化の関係、代替関係など
- パターン言語：パターンのコレクションと、パターンの間の関係性をまとめたもの

- マイクロサービスパターンの分類
  - 結構な数があるので、ある程度の分類はある。しかしそれほど厳密ではない

## マイクロサービスアーキテクチャと組織

- コンウェイの法則：ソフトウェアアーキテクチャは、組織を反映させたものにしかならない
- 逆コンウェイの法則：目指すべきアーキテクチャに合わせた組織を作れば、おのずとアーキテクチャも実現される
- ウォーターフォールよりもScrumなどのアジャイルなプロセスと、継続的デリバリを取り入れるとよい
- マイクロサービスを採用するのもの最終的には人なので、人間の感情がうまくトランジションできるようにマネージメントが必要

## 感想

- マイクロサービスアーキテクチャというこの大掛かりな仕組みを果たして、どうやったら取り入れることができるだろうか？
- 著者がいうように最初はモノリスではじめて、途中からマイクロサービスというのはあまり現実的な気がしない
- 結局、最初からマイクロサービスアーキテクチャで、かつ、最初からある程度の開発速度になるようにしないとダメな気がする