OmniAICreator/Qiita-1.07M huggingface dataset:
【unity】x,y,zを数値入力すれば、ひたすら自動回転するオブジェクトであそぼう

当記事の動画での解説はこちらから。
https://youtu.be/QExPYTRZb7o

Packageファイルは、BOOTHにて無料配布しています。
[BOOTHへはこちらから](https://sanpeita.booth.pm/)

こんな感じに、x,y,zを数値入力することによって、
オブジェクトがひたすらグルグルまわります。

![AutoRotObject.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191635/a2cf31ed-f618-218b-b646-79b4aef2d77d.gif)


<img width="207" alt="b.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191635/e82dc221-451c-e27e-0694-2ed6f05a5964.png">

---

スクリプトはこんなかんじ。

```RotateCube.cs
using UnityEngine;
public class RotateCube : MonoBehaviour
{
    public float rotX;
    public float rotY;
    public float rotZ;
    void Update()
    {
        transform.Rotate(rotX, rotY, rotZ);
    }
}
```


すると、コンポーネントは下図のようになります。

![20211006a02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191635/ca53e604-d1d6-9471-dedf-e25e066b321a.png)

下図のように値を入力してみます。

![20211006a03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191635/6e9717dc-163d-7586-67ea-b0266dec485b.png)

回っている様子
![AutoRotObject.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191635/b34ed3d6-e8bf-ed9f-b447-195b0f3fe539.gif)

---

ぜひ遊んでみてね!!
キー押下でScene再読み込みをする(リロード、リトライ的なもの)

実行ボタンのオンオフがめんどくなってきたら、
カメラなどオブジェクトの存在が一定の物に対して、スクリプトをアタッチしておくと楽チン

---

**関連**

- [【Unity】Sceneを切り替えるコード](https://qiita.com/sanpeita/items/912bf1fbaab975c9b7d4)
- [【unity】爆速でunitychanを動かしたい時【unitychan】](https://qiita.com/sanpeita/items/ab3bb9ce5a5b7e6cf6a0)

---

実質3行の追加で実装完了(中括弧は除く)

必要なのは下記のとおり

```Reload.cs

using UnityEngine.SceneManagement; //ここと
using UnityEngine;

public class Reload : MonoBehaviour
{
    void Update()
    {
        //ここから
        if (Input.GetKey(KeyCode.Return))
        {
            SceneManager.LoadScene(SceneManager.GetActiveScene().name);
        }
        //ここまで
    }
}

```
【unity】爆速でunitychanを動かしたい時【unitychan】

**関連**

- [【Unity】Sceneを切り替えるコード](https://qiita.com/sanpeita/items/912bf1fbaab975c9b7d4)
- [キー押下でScene再読み込みをする(リロード、リトライ的なもの)](https://qiita.com/sanpeita/items/acc518a3fd8176164405)
- [【unity】unitychanでいきなりエラーが出た【unitychan】](https://qiita.com/sanpeita/items/73ffaa1c1d095ed82035)

---

1.unityHubではなく、unity2018などを起動する

2.プロジェクト新規作成の段階で、
　アセットの　**standardAssets**　と
　**unitychan**　を指定してプロジェクト作成する

---

***Standard Assets***
https://assetstore.unity.com/packages/essentials/asset-packs/standard-assets-for-unity-2017-3-32351

***"Unity-Chan!" Model***
https://assetstore.unity.com/packages/3d/characters/unity-chan-model-18705

---


3.地面を作る


4.***unitychan***をプレファブからぶっこむ
　**NG...unitychan_dynamicではないよ!!**
<img width="340" alt="u03.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191635/e86975fd-0bec-9eac-4d9f-7f10b0d0d02a.png">


5.アニメーターコントローラーをstandardassetsの**ThirdPersonAnimatorController**にする
<img width="350" alt="e.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191635/1e24caec-b78b-6a1a-0b0b-cb8879b567ca.png">
<img width="434" alt="u01.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191635/1bdfb1a0-bba4-566d-aa2e-495cbf501633.png">

6.関係ないやつをオフる
下図参照
<img width="182" alt="f.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191635/3b19540d-07d3-4332-389f-fd6bcc33d6cb.png">


7.カプセルコライダーをいい感じにする
参考として下図
<img width="250" alt="u04.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191635/47aa2092-6342-1f05-326d-790049a841b0.png"><img width="423" alt="u05.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191635/79b382e0-70cf-5f5b-9ac4-92c35378ddb4.png">



8.ThirdPersonCharacterをアタッチして、細かい挙動はあとからいい感じにする
※注意…scriptフォルダにある、**ThirdPersonUserControl**をアタッチすること。
<img width="434" alt="u01.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191635/c3f1fe5d-9194-aa45-0c14-0f821590e78b.png">
ちょっとアタッチするスクリプトを間違えても、最悪見た目が一緒で「動かないよー」という状況になります。
<img width="426" alt="u02.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191635/b104d9e0-294b-a9b2-f02f-731719da2fea.png">



9.カメラ設定はいろいろやり方があるけれど、とにかく時間短縮命!であれば、
**MainCameraのチェックを外して、**
(standardassets内の)**MultipurposeCameraRig**を入れて、**ターゲットをunitychan**にすればオケ
<img width="302" alt="h.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191635/7409af56-0637-1621-9645-5ce2507a91cb.png">

10.設定をする際、画像のようにすればunitychanを定点で見るような感じになります<img width="291" alt="i.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191635/b8231c36-9963-46a5-c3e6-9cebaa9bc9e6.png">
Powershell ISEでのデバッグでブレークポイントで止めても、$argsの中身は取れないよって話

# 題名の通り、Powershell ISEで引数指定してps1ファイルをデバッグ実行した場合に$argsの内容は取れない

powershellファイルにAAAAという引数を渡して
ブレークポイントで止めて、その地点で\$argsを取得するも取れず
![powershell.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/501968/8121d15a-764b-5ee0-1609-56c2de48de49.png)

かといって、\$args自体は空はない
![powershell2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/501968/95f4f485-6bfd-01ee-70c3-92541cfc96a6.png)

# 対処方法
ps1ファイル内で、\$tmp = \$argsといった形式で$argsの内容を別の変数に移し替えれば内容が取得できる
Linuxでスケジューリングポリシーを指定してプロセスを起動する

スケジューリングポリシーの種類とその説明はこの記事では扱いません。(後日追記する可能性はあるかもしれません）
# スケジューリングポリシーを指定してプロセスを起動する方法
chrtコマンドを使います。-f でFIFOを指定。

```
$ sudo  chrt -f 38 yes > /dev/null &
```

ポリシー確認。

```
$ sudo chrt -p 32407
pid 32407's current scheduling policy: SCHED_OTHER
pid 32407's current scheduling priority: 0
```

すると、SCHED_OTHERですね。なぜだ・・・

# 追加調査

```
$ sudo chrt -f 1 yes > /dev/null &
```

chrt -p で表示されるスケジューリングポリシーと、psコマンドのclsで表示されるスケジューリングポリシーが異なりますね。(FFがSCHED_FIFOのはず)

```
$ ps -C yes -o comm,pid,ppid,cls,rtprio,%cpu
COMMAND           PID  PPID CLS RTPRIO %CPU
yes             27629 27628  FF      1 94.2
$
$ chrt -p 27629
pid 27629's current scheduling policy: SCHED_OTHER
pid 27629's current scheduling priority: 0
```

なぜだ・・・

# 閑話
同じプログラムを実行している以下の二つのプロセス
(1) SCHED_FIFOのプロセスをchrtでSCHED_OTHERにしたプロセス
(2) SCHED_OTHERのプロセス

topの出力を見るとどちらも同じくらいのCPU使用率になるのだが

```
  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND
  626 ec2-user  20   0  132m 7088 4304 R 49.8  0.7   7:53.42 cpu_bound.py
  722 ec2-user  20   0  132m 6980 4196 R 49.8  0.7   3:45.94 cpu_bound.py
```

psコマンドで確認すると、以下のような感じでCPU使用率に偏りが出ている。

```
[ec2-user@ip-172-21-0-185 experiment]$ ps -C cpu_bound.py -o comm,pid,ppid,cls,rtprio,pri,ni,%cpu
COMMAND           PID  PPID CLS RTPRIO PRI  NI %CPU
cpu_bound.py      626 26292  TS      -  19   0 69.1
cpu_bound.py      722 26292  TS      -  19   0 35.4
```

なぜだ・・・
さらに、%CPUの合計が100を超えるのもなぞ。
## さらに分かったこと
topのCPU使用率はtopの前の更新からのCPU専有率だが、psはプロセスが起動してからのCPUを使用した割合であるらしい。
https://hacknote.jp/archives/10596/https://hacknote.jp/archives/10596/
それならpsの%CPUが100%にならないのも納得。
Webブラウザ上で完結するGoogle翻訳を使った英文PDFの和訳

## 目的
コピペや変換，改行コード消去といった前処理の必要がなく，ブラウザ上ですべて完結する英文PDFドキュメントの日本語化

## 方法
1. Firefox, Chromeなどの拡張機能が使えるブラウザを使う
2. [pdf.jsのデモページ](https://mozilla.github.io/pdf.js/web/viewer.html)を開く (https://mozilla.github.io/pdf.js/web/viewer.html)
3. ビューアー右上の「Open File」からPDFをアップロード
![pdf.js_upload.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570534/051cd8a5-f49c-0d67-eb34-71e1ab59023d.png)
4. [Simple Translate](https://addons.mozilla.org/ja/firefox/addon/simple-translate/) などの拡張機能を使う
![simple_translate.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570534/d395c6b7-7ca1-824f-c376-efbc1f0ae20f.gif)

[Mouse Dictionary](https://addons.mozilla.org/ja/firefox/addon/mousedictionary/)などの辞書系拡張機能も機能する
![mouse_dictionary.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570534/c0a0c297-5769-7e38-5f55-d74ae17c6c10.gif)

なんだったら併用もできる
![both.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570534/8196a23b-aafe-1f61-7317-0bac27d3372c.gif)

## 注意点
一般公開されている論文などを翻訳する用途を想定して書いているので問題ないとは思いますが，PDFファイルを外部にアップロードする形にはなります．
一応，[pdf.js](https://mozilla.github.io/pdf.js/) (https://mozilla.github.io/pdf.js/) をローカルな環境に設置することもできます．

## 補足
### pdf.js とは
>PDF.jsは、HTML5で構築されたPortable Document Format（PDF）ビューアーです。
>PDF.jsはコミュニティ主導であり、Mozilla Labsによってサポートされています。私たちの目標は、PDFを解析およびレンダリングするための汎用のWeb標準ベースのプラットフォームを作成することです。

pdf.jsはバージョン19以降のFirefoxに組み込まれていて，デフォルトのPDFビューアーとして使われていたり，DropboxのPDFプレビュー機能にも使われていたりするらしい．
それにもかかわらずFirefoxのデフォルトのビューアーで拡張機能が使えない理由はよく分からない．
unitychanでThirdPersonCharacterを入れて壁に埋まった時

unitychanにThirdPersonCharacterを入れて遊んでいるとき、
<img width="283" alt="d.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191635/b35a31e5-50bb-8ea9-8126-e81b971e82e2.png">
こんな感じで埋まってしまったら...
<img width="106" alt="c.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191635/58785172-8d42-a707-a6e4-17038787d5a9.png">

プロトタイプであれば、とりあえずの緊急コードでその場をしのぎましょう

upup.csとか適当なスクリプトを作ります。
Uキー押下で、上に上昇します。


    void Update()
    {
        if (Input.GetKey(KeyCode.U)) {
            transform.position += transform.TransformDirection(Vector3.up * 10 * Time.deltaTime);
        }
    }
CUDA+cuDNNのインストールまとめ

<h2>はじめに</h2>
Windows10の環境にNVIDIA CUDA ToolkitとcuDNN SDKを
インストールする手順をまとめました。

今回は、Tensorflow2.1.0で動作することを目的としているので
インストールするバージョンは下記になります。

<ul>
<li>CUDA10.1</li>
<li>cuDNNv7.6.5</li>
</ul>

CUDA対応GPU
https://developer.nvidia.com/cuda-gpus

tensorflow2.1.0のGPUサポートページ
https://www.tensorflow.org/install/gpu

<h2>Visual Studioのインストール</h2>
CUDAを動かすには、Visual Studioのコンパイラが必要なので
入れてない場合は、事前にVisual Studioをインストールしておきましょう。
https://docs.microsoft.com/ja-jp/visualstudio/releases/2019/release-notes

CUDA10.1の対応表です
![viusal_studio_CUDA.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/334847/570df03d-3d1f-040f-00d9-240e50fa867e.png)


インストールする場合、「C++によるデスクトップ開発」にチェック
オプションに「MSVC v142 - VS 2019 C++ x64/x86 ビルドツール」にチェックが
入っていることを確認してください。
![visual_studio_install_photoshop.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/334847/0f2b5429-6f7a-4692-d365-f04c2ecc2084.png)

<h2>CUDA Toolkitのダウンロード</h2>
https://developer.nvidia.com/cuda-toolkit-archive
上記よりCUDA Toolkitをダウンロードしてインストールします。
今回はCUDA10.1をダウンロードしました。

フレームワークまたはアプリケーションによっては、
対応バージョンが違うので必ずしも、最新版を入れればよいというわけでないので注意してください

システム環境変数のPATHが下記のようになってるか確認
![システムPATH.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/334847/89546655-a8f1-1639-4dbe-78e78182a2e8.png)


システム環境変数のCUDA_PATHが下記のようになってるか確認
![CUDAPATH.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/334847/8c7587ce-e68a-c917-1edd-f3cc9acca038.png)


システム環境変数のCUDA_PATH_V10_1が下記のようになってるか確認
![CUDAPATH10.1.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/334847/0aa75955-94e1-7928-32d6-6821948b9b7b.png)


<b>インストールしてからまだPCを再起動していない場合
ここらへんで、再起動することをお勧めします。</b>

環境変数にPATHを通した場合、再起動しないと適応されない場合があります。
詳しくは[環境変数を変更したら再起動すべきか](http://toshirr.blog13.fc2.com/blog-entry-885.html)

<b>コマンドプロンプト</b>で下記を実行して
PATHがちゃんと通ってるか確認してください

```
nvcc -V
```

![nvcc.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/334847/08ae2702-d06d-de3e-d985-1a47e0816e49.png)

<h2>cuDNNのインストール</h2>
https://developer.nvidia.com/cuDNN
上記よりcuDNNをダウンロードします。
ダウンロードするにはログインが必要なので簡単にアカウントを作ってください。

![download_cuDNN_photoshop.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/334847/3e993a61-c303-d170-c1e4-3c2e5463c918.png)


解凍したら、cuDNN内のcudaフォルダの中身をすべて
C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v10.1
にコピーします。

最後にシステム環境変数に<b>新規</b>で

変数名「CUDNN_PATH」
値    「C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v10.1」

を追加します。

![システムPATH_cuDNN.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/334847/f779ccf6-abf7-0d5f-0b9a-46bb00ea03b2.png)


<b>ここでも再起動することをお勧めします。</b>

次に<b>コマンドプロンプト</b>で下記を実行し、エラーがでないことを確認してください。

```
where cudnn64_7.dll
```

![cuDNN結果.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/334847/a6f59021-22ef-bd29-7be3-5b8e697143bd.png)

<h2>Tensorflowで動作を確認</h2>
今回、Tensorflow2.1.0での使用目的だったので一応動作確認しておきます。

```python:test.py
import tensorflow as tf

with tf.device('/gpu:0'):
    a = tf.Variable([[1., 2.]])
    b = tf.constant([[3.], [4.]])
    print(tf.matmul(a, b))
```

![tensorflow_結果.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/334847/b140be6f-83ab-9031-3c05-bddbc4d2268a.png)
以上です、お疲れさまでした。
DockerでINTERNAL ERROR: cannot create temporary directory!となるときの対処法

環境 : Dockerコンテナ(mysql, Wordpress, nginx)

WordPressのブログの記事を執筆していると次のようなエラーが表示されました．

![EOh8O2rU4AAWDIR.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294876/49dedf44-0ff3-2d9c-9cc6-08ec1dfa4e2e.png)

どうしてこのエラーが表示されたのかわかりませんが，おそらく画像をアップロードするときに失敗していたのでそれが原因ではないかと思います．

早速サーバー内に入ってDBのDockerコンテナを再起動しようとしましたが，`INTERNAL ERROR: cannot create temporary directory!`とエラーが表示されました．違うコンテナで試してみても同じエラーだったので，どうやらDBのDockerコンテナに問題があるのではなく，サーバーかDocker自体に問題があるようです．

とりあえず，`$ free -m`で今のメモリの状況を確認し，`$ echo 1 > /proc/sys/vm/drop_caches`でキャッシュの解放をして空きを増やしました．
再度，コンテナを起動しようとしましたが，同じエラーのままでした．

# 解決方法

色々調べて[こちらのstack overflow](https://stackoverflow.com/questions/40755494/docker-compose-internal-error-cannot-create-temporary-directory)にたどり着きました．

どうやらコンテナとイメージを削除すればよさそうです．

**(20/01/23追記)下記のコマンドでコンテナとイメージを全て削除できますが，まずはDockerに残ってしまている不要なものを削除しましょう(ahsgw様にコメントでご教授いただいた[リンク](https://qiita.com/shione/items/dfa956a47b6632d8b3b3)が参考になります)．ちなみに僕は，それでもできなかったので，下記コマンドを実行しました．**


```
$ docker rm -f $(docker ps -a -q)

$ docker rmi $(docker images -q)
```
その後，`$ docker-compose up -d`すると動きました．

DBのコンテナはマウントしていましたが，サーバから操作しないだろうと思いwordpressのコンテナをマウントしていませんでした．

**イメージ消したら中身のデータ消えちまうんじゃねぇか！？**

と恐る恐る実行しました．
結果は，記事などのデータはDBに保存しているので，しっかり残っていましたが，Wordpressプラグインなどがやはり消えてしまっていました．

全部消えなかっただけよかったですが，マウントしておこう．．．．．
Python 画像データ前処理 入門 ImageDataGeneratorを用いた画像データ水増し

# Pythonで画像の水増し
pythonで画像を水増しする際に便利なImageDataGeneratorを紹介します。
関数内の詳細はhttps://keras.io/ja/preprocessing/image/ をご覧ください。

##ソースコード

```data_augumentation.py
# -*- coding: utf-8 -*-
from keras.preprocessing.image import load_img, img_to_array
from keras.preprocessing.image import ImageDataGenerator
import matplotlib.pyplot as plt
import numpy as np
import os
import glob
import argparse
import cv2
from scipy import ndimage


def data_augumentation(input, output, size, ex, ran):
    files = glob.glob(input + '/*.' + ex)
    if os.path.isdir(output) == False:
        os.mkdir(output)

    for i, file in enumerate(files):
        img = load_img(file)
        img = img.resize((size, size))
        x = img_to_array(img)
        x = np.expand_dims(x, axis=0)
        datagen = ImageDataGenerator(
            channel_shift_range=50,
            rotation_range=180,
            zoom_range=0.5,
            horizontal_flip=True,
            vertical_flip=True,
            width_shift_range=0.1,
            height_shift_range=0.1,
            )

        g = datagen.flow(x, batch_size=1, save_to_dir=output, save_prefix='img', save_format='jpg')
        for i in range(ran):
            batch = g.next()

def main():
    parser = argparse.ArgumentParser(description='output mixed images')
    parser.add_argument('--size', '-s', type=int, default=256, help='size to resize images')
    parser.add_argument('--out', '-o', default='./', help='Path to the folder containing images')
    parser.add_argument('--input', '-i', default='./', help='Path to the folder containing images')
    parser.add_argument('--range', '-r', default=9,type = int, help='data_augumentation range')
    parser.add_argument('--extension', '-e', default='jpg', help='File extension to images')
    args = parser.parse_args()
    os.makedirs(args.out, exist_ok=True)
    data_augumentation(args.input, args.out, args.size, args.extension, args.range)


if __name__ == '__main__':
    main()
```

##関数の使い方

```
> python data_augumentation.py --size 512 --out outdir --input inputdir --range 3 --e png
```

| コマンドライン引数       | 内容 |   
|:-----------------|------------------:|
| --size           | 出力画像の解像度を指定 |
| --out           |  出力フォルダの指定 |  
| --input             | 入力フォルダの指定 |   
| --range        |   1枚の画像を何枚水増しするか |  
| --extension            | 入力フォルダ内の拡張子を指定 |  

以上、画像水増しの参考になれば幸いです。
質問等あればお気軽にどうぞ！
ご一読ありがとうございました。
よければLGTM等お願いします！
Maya MEL 特定のグループ内の特定の名前を含むオブジェクトにスムースかけるだけ

```
string $children[] = `listRelatives -ad -f "blendShape_geo_grp"`;
for($child in $children)
{
    if(`objExists $child`)
    {
        if(`gmatch $child "*_face_geo"`)
        {
            select -r $child;
	　　 polySmooth;
	    select -r $child;
	    DeleteHistory;
        } 
    }
}
```
golangで標準入力


###基本的な標準入力の方法

Go言語で標準入力を行う方法をまとめておきます。

paizaのスキルチェックに標準入力は必須です。

```
package main

import (
    "bufio"
    "fmt"
    "os"
)

func main(){
    scanner := bufio.NewScanner(os.Stdin)
    for scanner.Scan() {
        ucl := scanner.Text()
        fmt.Println(ucl)
    }   
}
```
git help のデフォルトブラウザを変更する

gitでコマンドを調べるときに使う`git help <command>/ git command --help`ですが、初めの慣れていないうちはターミナルで調べるよりもブラウザの方が見やすかったりします。
Windowですとデフォルトでブラウザに移遷してくれるのでいいんですが、macだとgitconfigで設定しないと、勝手にvisual studio codeとかのエディターでhtmlを表示してしまい、ソースコードが表示されてしまいます。
なので、デフォルトで好きなブラウザで表示する方法を紹介します。

まずは、というか`.gitconfig`以下のように設定を行っていただければ全部動きます。

```
[web]
    browser = "opera"
[browser "opera"]
    path = /Applications/Opera.app/Contents/MacOS/Opera
```

見ての通りですが、`[browser="opera"]`の下の`path`に設定するブラウザアプリまでのパスはダブルクォーてションで囲まないこと。さらに、ブラウザのパスは実際の実行ファイルまでのパスをしてすることが必須です。単に"/Applicaitons/Opera.app"とはしないように。
【緊急事態】PHPのセッション変数が引き継げない！！

開発環境で動いていたプログラムが、
本番環境にいったら動かない！！
ということはよくある。

多いのは、どこまでをエラーとして出力するかの定義の差の場合が多い。

昔からの資産があると、どうしてもワーニングが出てしまう事がある。本当はワーニングを出ないようにすべきなのだが。。。

そのような場合、多くは
.htaccessに
php_value error_reporting 30711
と書けば問題は解決してくれる。

しかし、今回は違った、ログインの情報をセッション変数に入れているのだが、リダイレクトするとその情報が引き継げないという現象が起きた。

ネットで調べると、多くはsession_start();の前に、
何かを出力してしまった事が原因という単純なもの。

ようやっと、リダイレクトでうまくいかないとの報告は見つけたが、その解決策は無し。

本番環境の構築の期限は迫っている。

しょうがないので、セキュリティー的にはNGなんだろうが、画面遷移をするためのformを用意して、それを使う事でとりあえず納品とした。

同じプログラムをデモとして別のサーバにもアップした。サーバはmix-host。
ログインなどは問題なく出来ているが、
error.log
なるものが出力されていることに気がついた。

その内容は、

session_start(): Cannot start session when headers already sent in

session_start()が失敗する？

コードは

```
<?php
session_start();
：
```

とその前には何もない。

しかし、エラーメッセージから調べると、
ファイルにBOMが付いているとsession_start();が失敗するとのページを見つけた。

セッション変数を引き継げないページのsession idを調べると何も設定されていなかったのを思い出す。

恐る恐るBOMを確認する、付いていた！！

BOMを外してみた。

formが無くても動く！！

シンプルにsession_start();が失敗していたのか。

mix-host を使わないとわからなかった。
Datadogでdockerコンテナを監視を始めたときのメモ


## この記事について

AWSのEC2(なお、OSはAmazon Linux2)上に配置しているairflowのログ収集をdatadogに任せたく、チュートリアルに従って設定を行ったら本当に一瞬で終わってしまったので、メモがてら残しておく。datadog agentは参考記事[^1]にならいdockerイメージ版を利用した。
設定にあたっては、公式ドキュメント[^2]にある一番シンプルなスクリプトに環境変数をいくつか追加している。

## やったこと

下記のシェルスクリプトを実行しただけ。本当にそれだけ。

```.sh:init_dd-agent.sh
#!/bin/bash -eu

DOCKER_CONTENT_TRUST=1 \
docker run  -d --name datadog-agent -v /var/run/docker.sock:/var/run/docker.sock:ro \
                                    -v /proc/:/host/proc/:ro \
                                    -v /sys/fs/cgroup/:/host/sys/fs/cgroup:ro \
                                    -e DD_API_KEY=$MY_DD_API_KEY \
                                    -e DD_TAGS="<your-tag1> <your-tag2>" \
                                    -e DD_LOGS_ENABLED=true \
                                    -e DD_LOGS_CONFIG_CONTAINER_COLLECT_ALL=true \
                                    -e DD_AC_EXCLUDE="name:datadog-agent" \
                                    -e SD_BACKEND="docker" \
                                    -e NON_LOCAL_TRAFFIC=false \
                                    datadog/agent:latest
```

正常に実行されていれば、datadog agentのコンテナが起動しているはずなので、`docker ps` コマンドを実行して確認しよう。
また、プロセスが実行されたあとにdatadog上にサーバのメトリクスやログが飛んできているか確認しましょう。

### 設定のポイント

個人的には公式ドキュメントの他、datadog-agentのgithubリポジトリ[^3]にも色々説明が乗っているので、監視したい対象に合わせて最適なオプションを探しましょう。

* `DD_API_KEY` は当然ながら必須の設定。datadogの管理画面から取得し、環境変数にでも入れておきましょう。
* `DD_TAGS`にはスペース区切りでタグを入れることでdatadogの画面上での検索性が上がる。部署名などお好きなものをどうぞ。
* `DD_LOGS_ENABLED` を`true`に設定することにより、DatadogのLogs配下にログが飛んでくるようになる。これを設定しないとサーバのメトリクスのみが連携される。
* `DD_LOGS_CONFIG_CONTAINER_COLLECT_ALL` これをtrueにすることで、全てのコンテナの実行ログを取ることができる。datadog agentを入れているサーバ上でコンテナアプリケーションを実行していて、そのログを収集したい場合、trueにしよう。
* `DD_AC_EXCLUDE`を設定することでログを収集しないコンテナを指定できる。今回の場合はdatadog-agent自体のログを収集しないため設定。


## 参考記事

[^1]: [DatadogでDocker監視が幸せになった話](https://www.m3tech.blog/entry/2018/08/20/113000)
[^2]: [Datadog公式ドキュメント](https://docs.datadoghq.com/ja/agent/docker/?tab=standard)
[^3]: [DataDog/docker-dd-agent](https://github.com/DataDog/docker-dd-agent)
CodeCommit + CodeDeploy + CodePipelineでEC2にデプロイ~CodeCommitの設定~



|    目次    |
|:------------------|
| 1. CodeCommitの設定(この記事)  |
| 2. [CodeDeployの設定](https://qiita.com/k_senbei/items/b713d828737f3810b187)          |
| 3. [CodePipelineの設定・デプロイ実行](https://qiita.com/k_senbei/items/f748f5a30414696ac645)  |

AWSのCodeCommit、CodeDeploy、CodePipelineを組み合わせてEC2にデプロイするまでをまとめました。
この記事ではCodeCommitにリポジトリを作成してgit cloneするまでを説明します。

## 前提

* 既にAWSアカウント、IAMユーザーは作成済みとします。
* ローカル環境 : CentOS 7

## CodeCommit

AWSのGitホスティングサービスです。

競合サービス : GitHub、GitLab、etc..

## 準備

#### IAM ユーザーに対してCodeCommit へのアクセスを許可

1. AWSマネジメントコンソールにログインして、IAMコンソールを開きます。
2. ナビゲーションから[ユーザー]を選択し、CodeCommitへのアクセスを許可するIAMユーザーを選択します。
3. [アクセス権限]タブの[アクセス権限の追加]を選択します。※ここでPowerUserAccess等、CodeCommitにアクセス可能な権限が既に付与されている場合、4~5の作業は不要です。
4. [既存のポリシーを直接アタッチ] を選択し、ポリシーのリストからCodeCommitにアクセス可能なポリシー(例. AWSCodeCommitFullAccess)を選択して[次のステップ:確認]。
5. 追加するアクセス権限を確認して[アクセス権限の追加]を選択します。

#### CodeCommitへアクセスするためのGit認証情報を作成

1. [IAMコンソール > ユーザー]で先にCodeCommitへのアクセス権限を追加したIAMユーザーを選択します。
2. [認証情報]タブの[AWS CodeCommit の HTTPS Git 認証情報]で[認証情報を生成]を選択します。
3. 生成された"ユーザー名"、"パスワード"が表示されるので控えておきます。[認証情報のダウンロード]からCSVでダウンロードすることも可能です。
4. ローカルの`~/.netrc`に先に控えた認証情報を書きます。

```shell:.netrc
machine git-codecommit.ap-northeast-1.amazonaws.com
login ユーザー名
password パスワード
```

## CodeCommitにリポジトリ作成

1. CodeCommitのコンソール([https://console.aws.amazon.com/codesuite/codecommit/home](https://console.aws.amazon.com/codesuite/codecommit/home))を開きます。
2. [ソース]の[リポジトリ]を選択し、[リポジトリを作成]を選択します。
3. リポジトリ名と作成(リポジトリの説明)を入力して[作成]を選択します。
![create_repository.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/118624/b8998cc1-69e4-775f-7449-cc63113281b8.png)
4. ローカル環境で、作成したリポジトリのHTTPSのURLを指定してgit cloneします。

## まとめ

これでCodeCommitにリポジトリを作成してローカルにcloneできました。

次回はCodeDeployの設定方法を説明します。
【django】herokuにデプロイした途端、cssが反映されないときの処方箋

「ローカルではちゃんと表示されるのに」っていういつものやつです。


## settings.pyにwhitenoiseの一行追加


```settings.py

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    'whitenoise.middleware.WhiteNoiseMiddleware',    # この行を追加
]
```

これで無事CSSも読み込まれます。

これやってもまだ表示されないようなら、wsgi.pyとかでwhitenoiseをimportしていないか確認しましょう。
もしimport していたらその行をコメントアウトすればいいらしいです。
初心者によるプログラミング学習ログ 216日目

#100日チャレンジの216日目

twitterの100日チャレンジ#タグ、#100DaysOfCode実施中です。
すでに100日超えましたが、継続。

100日チャレンジは、ぱぺまぺの中ではプログラミングに限らず継続学習のために使っています。

216日目は

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">おはようございます<br>216日目<br><br>架空のwebサイトコーディング<br><br>wifiの調子がわるくて、調整に手間取ってたら勉強時間少なくなった<a href="https://twitter.com/hashtag/100DaysOfCode?src=hash&amp;ref_src=twsrc%5Etfw">#100DaysOfCode</a> <a href="https://twitter.com/hashtag/%E9%A7%86%E3%81%91%E5%87%BA%E3%81%97%E3%82%A8%E3%83%B3%E3%82%B8%E3%83%8B%E3%82%A2%E3%81%A8%E7%B9%8B%E3%81%8C%E3%82%8A%E3%81%9F%E3%81%84?src=hash&amp;ref_src=twsrc%5Etfw">#駆け出しエンジニアと繋がりたい</a> <a href="https://twitter.com/hashtag/%E6%97%A9%E8%B5%B7%E3%81%8D%E3%83%81%E3%83%A3%E3%83%AC%E3%83%B3%E3%82%B8?src=hash&amp;ref_src=twsrc%5Etfw">#早起きチャレンジ</a></p>&mdash; ぱぺまぺ@webエンジニアを目指したい社畜 (@yudapinokio) <a href="https://twitter.com/yudapinokio/status/1219352401578090496?ref_src=twsrc%5Etfw">January 20, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
Q14.行を挿入するには？

エクセルのVBAマクロで行を挿入するにはどうすればいいでしょうか

今回は例として以下のようなエクセルファイルがあるとして、

![Q10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560479/f1df7c5f-a077-1015-a08b-06d5b4ccd51c.png)

この4行目に新しく行を挿入する処理を作ってみましょう。


###■ポイント
行の挿入は簡単に実装できます。
Rows(挿入したい行).Insertで挿入することができます。

もし、列を挿入したい場合は、
Columns(挿入したい列).Insertとなります。



###■回答
```VB
Sub Q14_Answer()
    Rows(4).Insert
End Sub
```

###■解説
そのまんまです(笑)
書式設定とかは上のセルのを引き継がれるのでご注意を。

一応結果はこちらです。4行目に新しい行が挿入されているのが分かります。

![Q14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560479/02017b73-2dab-666c-77d4-968782b113f2.png)
回転させたオブジェクトを水平に動かす方法(ローカルとグローバル)

オブジェクトを回転させた後に、水平移動するとき、ぽちぽちとpositionの値を変えていませんか？
そんなときは下図のように、ローカルとグローバルを切り替えましょう!

【ローカル】
<img width="345" alt="a.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191635/ecdcaafe-f52c-59d2-855c-b8ac75b4d0cc.png">

【グローバル】
<img width="348" alt="b.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191635/6fe6d818-9541-fd8c-8b45-86bf76e4b303.png">
Slackで平日の特定の時間に通知

毎日14時に発生するタスクを記載する。
これによりサイボウズ等の予定にわざわざ日次作業を登録しなくても気づくようになる。

```/remind me "LAN正常性チェック" at 14:00 every weekday```

↓

![slackaleart.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197872/310f9d79-38e0-3a05-1710-96b41cc395bd.png)
Railsのバージョンの消し方（アンインストールのやり方）

# 経緯
Railsのバージョンを間違えてインストールしてしまいました。

インストールしたバージョンをアンインストールしたやり方をお教えします。

# Rails バージョンの消し方

Railsのバージョンを確認しましょう

```rails
$ rails -v
Rails 6.0.2.1
```

Railsのバージョンが　6.0.2.1　なので以下を入力する

```rails:
$ gem uninstall railties -v '6.0.2.1'
```

すると　以下が出る。

```
You have requested to uninstall the gem:
       railties-6.0.2.1
rails-6.0.2.1 depends on railties (= 6.0.2.1)
If you remove this gem, these dependencies will not be met.
Continue with Uninstall? [yN]  yN <---- ＊ここは yN　を入力してください。
Successfully uninstalled railties-6.0.2.1
```

成功です!

さらに、

```
$ gem list | grep rails
```

上記を入力することで削除したバージョンがないかの確認ができます。

```
autoprefixer-rails (9.8.4)
chart-js-rails (0.1.7)
coffee-rails (4.2.2)
jquery-rails (4.4.0)
rails (6.0.3.2, 6.0.3.1, 6.0.2.2, 5.2.4.3, 5.2.4.2, 5.2.4)
rails-dom-testing (2.0.3)
rails-html-sanitizer (1.3.0)
rails-i18n (5.1.3)
sass-rails (6.0.0, 5.1.0)
sassc-rails (2.1.2)
sprockets-rails (3.2.1)
```

以上から削除したバージョンないことが判断できます。
【AWS SDK for .NET 】S3フォルダ内のファイル一覧を取得する

## 概要
AWSの公式ドキュメントの通りにやると、バケット内のファイル一覧は取得できるけど、特定フォルダー内のファイル一覧の取得方法が分からなかったので調査。
ファイル一覧を取得するには`ListObjectsV2Request`を使用する。
## コード
BucketName/Test/Template
　　　　　　　      　  └ file1.js
　　　　  　　　　      └ file2.js

というS3の構成で`file1.js`と`file2.js`を取得したい場合以下のようになる

```ListObjectsTest.cs
static async Task ListingObjectsAsync()
{
	ListObjectsV2Request request = new ListObjectsV2Request
	{
		BucketName = bucketName,
		Prefix = "Test/Template/",  // ← 一覧を取得したいフォルダのキーをPrefixに指定する。
		MaxKeys = 10
	};

	ListObjectsV2Response response;
	do
	{
		response = await client.ListObjectsV2Async(request);  

		// Process the response.
		foreach (S3Object entry in response.S3Objects)
		{
			Console.WriteLine("key = {0} size = {1}", entry.Key, entry.Size);
			// 以下の内容が取得できる
			// [0] BucketName/Test/Template		←なぜかPrefixで設定したキーが取得される
			// [1] BucketName/Test/Template/file1.js
			// [2] BucketName/Test/Template/file2.js
		}
		Console.WriteLine("Next Continuation Token: {0}", response.NextContinuationToken);
		request.ContinuationToken = response.NextContinuationToken;
	} while (response.IsTruncated);
}
```
>[AWS SDK for .NET を使用したキーのリスト作成](https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/dev/ListingObjectKeysUsingNetSDK.html)


## 取得結果
```
// [0] BucketName/Test/Template
// [1] BucketName/Test/Template/file1.js
// [2] BucketName/Test/Template/file2.js
```
ファイル一覧を取得できるが、`ListObjectsV2Request#Prefix`で設定した内容が`[0]`に入る。
これが困る場合、値のSizeは0らしいので、Sizeを見て対応するのがよさそう。

## 参考
- [ListObjectsV2Request](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/S3/TListObjectsV2Request.html)
- [ListObjectsV2Response](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/S3/TListObjectsV2Response.html)
- [ListObjectsV2Request(AWS SDK for Java)でS3のファイル一覧を取得する](https://qiita.com/seijikohara/items/32198148fad35c641cd2)
UbuntuでMacBookProの内臓カメラが起動しない

# モチベーション
前回、仮想環境（Ubuntu）でPythonとOpenCVを導入したので、Mac内臓カメラが使えるかどうかを確認したら、エラーがでまくった。（泣）いろいろ調べてみて、うまくいったのでメモとして残します。

# 環境
Host: MacOS Catalina
Guest: Ubuntu 18.04
仮想化: Virtualbox 6.0.14

# エラー現象
どんなエラーメッセージだったかはキャプチャを撮り忘れました。。。今度、取り直します。
VIDEOIO ERROR: V4L: can't open camera by index 0　な感じのエラーだったような・・・
要するにカメラデバイスがないと言っている。Macの内臓カメラが認識できていない。

# 解決策
<a href="https://qiita.com/white_aspara25/items/b286027710c777eaa319">こちら</a>のサイトを参考にVirtualBox Extension Packをインストールしてあげると内臓カメラが認識できました。

①公式サイトからVirtualBox Extension Packをダウンロードします。
　重要：VirtualBoxと同じバージョンを選びます。
<img width="961" alt="Screen Shot 2020-01-21 at 18.06.35.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/565739/35751e35-a17a-1d9a-2cf1-d1adc24051b3.png">

②Virtualboxを起動し、Tools > Preferences をクリック
<img width="854" alt="Screen Shot 2020-01-21 at 18.03.54.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/565739/c7c5693b-680d-5a2b-4b0e-3ad4b6d4d3a2.png">

③Extensions タブの右端にある + をクリックし、ダウンロードしたパッケージを選択します。
<img width="662" alt="Screen Shot 2020-01-21 at 18.08.01.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/565739/5e1b67bc-b667-9e6e-77f4-72d74ca582d4.png">

④後は画面にしたがってインストールすればOKです。Virtualboxを再起動。

⑤Ubuntuを起動するとメニュー画面に Devices > Webcams > FaceTime HD Camera が出てくれば成功です。
<img width="1400" alt="Screen Shot 2020-01-21 at 18.17.52.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/565739/2c16ed5e-2d9e-b34c-c4c2-b89225826684.png">

⑥念のためサンプルコードでカメラが使えるか確認します。
![Screen Shot 2020-01-21 at 18.26.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/565739/ef47d55b-f4bb-90d8-a381-9685f1f28715.png)

お〜〜〜！！！映った！！！！

### 参考
- https://qiita.com/0E1/items/919a56f0d552ad72d65c
- https://qiita.com/0E1/items/919a56f0d552ad72d65c
アップロードした画像の有無の判定

#実装したこと
ビューファイルでimageカラムがnilだった時の判定をして表示するビューの切替。
アップローダー：carrierwave
最初は

```ruby:index.html.haml
- if @user.image.nil?
 %p 画像がまだ登録されていません。
- else
 = image_tag @user.image
```

としたところ画像が無くてもPタグの内容が表示されなかった。

binding.pryで中身を確認したとこと

```shell
[1] pry(#<MachinesController>)> @user
=> #<User:0x00007f85e25cca00 id: 27, name: "画像なし", image: nil, created_at: Tue, 21 Jan 2020 08:28:09 UTC +00:00, updated_at: Tue, 21 Jan 2020 08:28:09 UTC +00:00>
```

nilだよなぁ。じゃあimageの中身見るか

```shell
[1] pry(#<MachinesController>)> @user.image
=> #<ImageUploader:0x00007f85e836eaf0
 @cache_id=nil,
 @file=nil,
 @filename=nil,
 @identifier=nil,
 @model=#<User:0x00007f85e9c083b8 id: 27, name: "画像なし", image: nil, created_at: Tue, 21 Jan 2020 08:28:09 UTC +00:00, updated_at: Tue, 21 Jan 2020 08:28:09 UTC +00:00>,
 @mounted_as=:image,
 @staged=false,
 @versions=nil>
```
なんかnilのはずなのにいっぱい入ってるやん！？

で調べてみたところ
https://teratail.com/questions/101330
に回答している方がいらっしゃって
「carrierwaveでは、uploaderをマウントしたアトリビュートにアクセスすると、
uploaderのオブジェクトを返すため、決してnilにはならないらしいです。」
とのこと。

なので、このページの回答の通りに

```ruby:index.html.haml
- if @user.image.file.nil?
 %p 画像がまだ登録されていません。
- else
 = image_tag @user.image
```

にしたら無事に解決しました。

ちょっとややこしかったのでシェア。
【GAS】型を判定して変換を行う

例えば日付型をそのまま出力すると↓のような表示になってしまう

```
Sat Dec 30 1899 23:59:00 GMT+0900 (JST)
```

これを文字列型に変換するとしたら↓

```
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
var workingSheet = spreadsheet.getSheetByName("hogehoge");
var range = workingSheet.getRange(1, 1);
var content = range.getValue();
var objectType = Object.prototype.toString.call(content);
if (objectType == '[object Date]') {
    content = Utilities.formatDate(content, 'Asia/Tokyo','yyyy/MM/dd');
}
```
自宅の公開sshサーバの不正アクセスログを調査してみた

#はじめに
自宅の公開sshサーバーに久しぶりにログインしてみて，アクセスログを見ていたところ，不審なIPアドレスから不審なユーザ名でのログイン試行のログを発見してしまった．
当該ログから不審なIPアドレスによるログイン成功がないか，どんなログイン試行があるのか，いくつくらいあるのかを調査してみた．

#前提
自宅sshサーバーは以下の設定の下，運用している．

- 公開鍵認証を有効にしている
- パスワード認証は無効にしている
- rootユーザーでのログインを無効にしている
- ポートはデフォルトのポートから変更している

運用当初は，デフォルトのポートで公開していなかったため，自分のアクセスログしか見当たらなかったが，半年以上運用したことにより，デフォルトのポート以外で公開されている本sshサービスを発見し，ログイン試行を仕掛けてくる通信が出てきた．

パスワード認証をしようとしても，無効になっているので下記のようなメッセージが出力される．

```log:ログイン失敗メッセージ
[ユーザー名]@[IPアドレス]: Permission denied (publickey).
```

上記より，間違いなく不正アクセスを試みた通信である．（おそらくほぼすべて海外のIPアドレスであると推測される）

#ログイン成功ログの調査
sshのログが記録される/var/log/auth.log* のファイルすべてから必要な情報を抽出し，アクセスに成功したIPアドレスを調査した．ここでは，当該ファイルの情報をssh.log という一つのファイルにまとめた前提で進める．

まずは，アクセスに成功した際にログにどのように記録されるか調べた．
以下のようなメッセージがログファイルに記録される．

```log:ログイン成功ログ
auth.log:Jan 21 17:55:15 [ホスト名] sshd[26757]: Accepted publickey for [ユーザー名] from [IPアドレス] port 52228 ssh2:...
```

鍵認証のログインに成功した場合，Accepted という文字列が出力されるため，本文字列をキーにしてログインに成功したIPアドレスを確認した．
IPアドレスの値があるのがスペースをデリミタとして11番目のフィールドにあるので，cut コマンドで当該部分を切り出し，sort およびuniq コマンドで重複排除した．

```sh:実行コマンド
grep -E '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' ssh.log | grep -E 'Accepted' | cut -d ' ' -f 11 | sort | uniq
```

結果として一つのIPアドレスのみが記録されており，本IPアドレスを調査したところ，見覚えのあるIPアドレスであったため，とりあえず不正アクセスされていないことが確認できた．

#ログイン試行したIPアドレスの調査
とりあえず不正アクセスに成功した形跡はなかったため，一安心した．
次に，どれくらい不正アクセスしたIPアドレスがあるのかを調査した．

```sh:実行コマンド
grep -E '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' ssh.log | cut -d ' ' -f 8 | grep -E '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' | sort | uniq | wc -l
```

上記コマンドで，IPアドレスの種類数を集計できる．結果は下記の通り．

```sh:集計結果
146
```

一つは，自身の使用したIPアドレスである．それ以外はログインに成功した形跡がないため，実に145種類のIPアドレスから不正アクセスを試みられた形跡があった．

各IPアドレスによるアクセス試行回数の上位3種類を調査した．コマンドは下記の通り．

```sh:実行コマンド
grep -E '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' ssh.log | cut -d ' ' -f 8 | grep -E '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' | sort | uniq -c | sort -nr | head -3
```

集計結果は下記の通り．1番目のフィールドがアクセス回数，右側のフィールドがIPアドレスである．(IPアドレスの第4オクテッドは伏字)
また，IPアドレス情報から地域を調査した．

```sh:集計結果
1493 64.62.134.*** ← アメリカ
     20 92.222.141.*** ← フランス
      6 51.91.102.*** ← イギリス
```

アクセス数に偏りがあるが，海外からのIPアドレスであった．（当たり前だが）
圧倒的にアメリカからの攻撃が多かった．

#使用されたユーザー名
最後に，使用されたユーザー名を調査した．
Invalid user というメッセージが出力されている行が，無効なユーザー名を使用してログインしようとした場合のメッセージなので，本メッセージが出力されている行の8フィールド目にユーザー名が記録されていたため，下記コマンドでユーザー名を抽出した．（ログインに使用されたユーザー名というよりか，無効なユーザー名の抽出である．トップ10をリストアップした．）

```sh:実行コマンド
grep -E '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' ssh.log | grep -E 'Invalid user' | cut -d ' ' -f 8 | sort | uniq -c | sort -nr | head 
```

集計結果は，上記と同様で1番目のフィールドが使用回数，2番目のフィールドがユーザー名である．

```sh:集計結果
796 user
 55 test
 40 admin
 35 oracle
 34 postgres
 27 ubuntu
 22 zabbix
 21 nagios
 19 ftpuser
 12 zimbra
```

見たところ，サービスの初期ユーザー名が多い印象を受ける．
初期ユーザーをそのまま使用して運用するのもいいけど，その場合は強固なパスワードにするかパスワード認証を廃止して公開鍵認証にすべきと考える．
というのが，今回調査して得た教訓である．

#おわりに
感想をつらつらと書き下す．

- シェルコマンドを駆使すれば，ログ集計をさっと実施できることが分かった
- ポートが違うからといって攻撃が来ないわけでないことが分かった
- とはいえ，公開鍵認証なので不正アクセスされる危険性は低い，と今回の結果から思う
- 初期ユーザー名は狙い撃ちされるので，初期ユーザー名で運用する場合は不正アクセス対策が必須
- 上記に記載しなかったけど，たぶん流れてしまっているログもあるので，ログの確保は運用上必須

以上
Windows10 のWSL2（Ubuntu 18.04）でRails開発環境、PostgreSQLの設定でつまづいた

Windows 10 のWSL2（Ubuntu 18.04）でRails開発環境を整えようとしていて、PostgreSQLの設定でつまづきました。原因は、DBへの接続が[ピア認証方式](https://www.postgresql.jp/document/9.2/html/auth-methods.html#AUTH-PEER)だったからみたいでした。

WSL1のときも、似たようなつまづきをした記憶があって、2度あることは3度あるだとうとおもい、すこしでも情報を残しておきます。

# ピア認証ではじかれたのでパスワード認証でかわそうとした
- `hba.conf`の`peer`を`md5`にかきかえた
- パスワードが違うとはじかれた

## クラスターを再構築すれば... :no_good: 
- `pg_dropcluster 12 main`で既存のクラスターを削除して
- `pg_createcluster 12 main --start`で新規クラスターを作り直した
- `hba.conf`がもとに戻り、peer認証ではじかれた

# ピア認証を通すために、postgres側にユーザーを追加する方法をとった
- `sudo passwd postgres`でpostgresユーザーのパスワードを設定して
- `su - postgres`でログインしたあと
- `psql -U postgres`でpostgresを起動して
- `create user {name} with password {pass} createdb login`をしてpostgresに接続できるユーザーを作成（`{name}`はUbuntuログイン使用時のユーザー名！）
- さきほど作ったユーザー情報を、`database.yml`の`username`と`password`に設定


`bin/rails db:setup`が通りました。

# 余談1

ググると「`pg_ctl`コマンドをつかってアレコレ..」とあるけれど、すくなくともpostgres 12では、このコマンドは存在しない。

[postgres 12 をインストールして使用できる\`pg\_xxxxx\`コマンド \- Qiita](https://qiita.com/hirocueki2/items/47626716775f903fff9c)をつかう必要があるようです。

# 余談2

- `gem pg`がインストールできなかった
    - `apt install libpq-dev`した
- `webpacker:install`でいろいろ足りなかった
    - [Ubuntuに最新のNode\.jsを難なくインストールする \- Qiita](https://qiita.com/seibe/items/36cef7df85fe2cefa3ea)を参考にNode.jsを追加して、
    - `npm install yarn`した
    

# おわりに
素のUbuntuから環境構築は、慣れていないので大変。細かくメモをとっていても次回の時点でツールのバージョンが上がってたりで通用しなかったりするのがさらに :cry: 

ただ、WSL2はかなり快適 :star2: で、コマンドの実行速度も段違いです。

ターミナルは、[Windows Terminal \(Preview\)](https://www.microsoft.com/ja-jp/p/windows-terminal-preview/9n0dx20hk701#activetab=pivot:overviewtab)をつかっていますが、特に問題なく快適につかえています。

まだ試したことはないのですが、Docker for WSL2がリリースされると開発環境の構築&破棄もさらにラクにできるようになりそうですねー。
- [WSL2 & Docker for WSL2 & VSCode Remote Development｜にさつ｜note](https://note.com/twobooks/n/n623d1a542fa1)
【Nuxt.js】 middleware is 何？

## ミドルウェアとは
- ミドルウェアを使用すると、ページがレンダリングされる前(SSR処理などが行われる前)に設定された関数を実行することができる
- 認証許可が必要なページやログイン後のリダイレクトパスを保持するために使用される。
- 関数は`middleware/`ディレクトリに入れる
    - `middleware/auth.js`は`auth`ミドルウェアになる
- ミドルウェアは第一引数に`context`を取る
    - `context`の内容については[こちら](https://ja.nuxtjs.org/api/context/)を参照
- ユニバーサルモードの場合は、サーバーサイドで一度だけ呼び出される。 (Nuxtアプリケーションへの最初のリクエスト時、またはページの再読み込み時)クライアントサイドでは、他のルートへ移動した時に呼び出される。
- SPAモードの場合、クライアントサイドでの最初のリクエスト時と他のルートへ移動した時に呼び出される。

## middlewareを使用した処理の例
storeのアカウント情報が無い場合、ログイン画面にリダイレクトされる処理を書いてみる。

```js:middleware/redirect.js
export default function ({ redirect, store }) {
  const user = store.state.user
  if(!user) {
    redirect('/login')
  }
}
```
これを`nuxt.config.js`で読み込む。

```js:nuxt.config.js
export default {
  router {
    middleware: 'redirect'
  }
}
```
このようにすると全てのルート変更時に`redirect.js`が読み込まれるようになる。

また、特定のページ(またはレイアウト)にのみ特定の関数を設定することもできる。

```vuejs:index.vue
<script>
import { fetchUid } from '@/middleware/uid.js'
export default {
  middleware: [ 'auth', fetchUid ]
}
</script>
```
1ファイルに1つの処理の場合は、'auth'で関数を実行することができる。
一方、1つのファイルに複数の関数がある場合は、ファイルをimportすることで特定の関数を実行することができる。


## middlewareの実行順序について
- `middleware`自体の実行順序は、このようになっている。
  - `plugins`→`middleware`→`fetch`→`asyncData`
  
- `middleware`の関数の呼び出し方の違いによる実行順序はこのようになる。
  - `nuxt.config.js`→`layout`→`page`

## Login画面では実行したくない問題
アカウント情報を確認してリダイレクトさせる処理を`middleware`内に書いた場合、Login画面ではまだアカウント情報がないので、関数を実行したくない場合がある。
その場合は、`middleware`内の`context`に`route`があるので、そこから関数を実行したくないページを弾いて処理を実行させるようにする。

```js:middleware/auth.js
export default function ({ redirect, store, route }) {
  const user = store.state.user
  if(!user && route.path !== '/login') {
    redirect('/login')
  }
}
```
`create_or_find_by` はユニーク制約が定義されたテーブルで効いてくる

以下の記事で `find_or_create_by` と `create_or_find_by` の違いについてコメントしたのですが、投稿元の方から反応が無かったので別記事として投稿することにしました :pray:

[「find\_or\_create\_by」と「create\_or\_find\_by」 の違い \#Railsのコードを読んでみた \- Qiita](https://qiita.com/4geru/items/e9c6545eb211124f153d#comment-3bcfa66521e94c76b963)

---

> find_or_create_by でできないカラムもcreate_or_find_byではできてしまう可能性があります。
>
> 例えば、Userモデルがあったとします。create_or_find_by ではcreateが先に実行されるため2つ同じようなデータが作られます。
find_or_create_byでは、findが先に実行されるため、検索結果が返され、同じデータは2つ作られることはありません。

意識して使用しないとそのような動作になってしまうのですが、恐らく `create_or_find_by` のユースケースは DB で unique 制約が定義されたカラムに対しての実行だと思います。

See also: [新メソッド: \#create\_or\_find\_by](https://techracho.bpsinc.jp/hachi8833/2018_02_16/52623)

## `find_or_create_by` の場合

**正常系**

1. `find_by` を実行し、レコードが取得できなかった
2. `create` を実行し、レコードが作成される

**異常系**

処理 A と B が同時に実行されている場合

1. A: `find_by` を実行し、レコードが取得できなかった
2. B: A と同じ条件で `find_or_create_by` を実行。`find_by` でレコードが取得できなかった
3. A: `create` を実行し、レコードが作成される
4. B: `create` を実行し、レコードが作成される (実際には unique 制約でエラーになるはず）

同じレコードが 2 つ出来てしまった！ (実際には unique 制約でエラーになるはず）

▶ `find_or_create_by` の `find` と `create` の間に別のプロセスの `create` が割り込む可能性があります。

## `create_or_find_by` の場合

処理 A と B が同時に実行されている場合

1. A: `create` を実行し、レコードが作成される
2. B: A と同じ条件で `create_or_find_by` を実行。 `create` で DB の unique によりレコードの作成に失敗
3. B: `find_by` を実行し、レコードが取得される

▶ 別のプロセスが同時に `create_or_find_by` を実行しても安全に処理される
Vuetify2.xでv-data-tableで行クリックと操作列追加

# Vuetify2.xで変更されたV-Data-Tableをカスタマイズするときのメモ

## 概要

Vuetify1.5から2.2にあげたらV-Data-Tableの書き方が変わっていた。
[1.5→2.0にあげた例](https://qiita.com/filunK/items/e71999d5abef404744b3)を参考にさせていただいた。
V-Data-Tableに関しては、リンク先にあるようにカラム指向になったようなイメージでtemplateの書き方がかわったようだった。
最初はV-Data-Iteratorでまわして自力でTableを構築する必要があるのかな、とおもったが[公式ドキュメント](https://dev.vuetifyjs.com/ja/components/data-tables)に例があったので、参照しつつ解決したときのメモ。

### 行クリック

ドキュメントのAPI欄にさりげなく click:row とあったので試した。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/23242/6ca8def2-1ca4-d374-bdfe-36dffee2fc6c.png)

単にイベントに関数を割り当てるだけでよかった。

抜粋：

```vue:vue
<template lang="pug">
  v-data-table(
   :headers="headers"
   :items="db"
   hide-default-footer
   @click:row="clickRow"
  )
</template>
<script>
  export default {
    name: "List",
    data: () => ({
      headers: [
       {text:'ID', value:'id'},
       {text:'なかまたち', value:'name'}
      ],
      db: [
        {id:1, name:'ブタさん'},
        {id:2, name:'ウサギさん'},
        {id:3, name:'キツネさん'},
        {id:4, name:'ゾウさん'}
      ]
    }),
    methods: {
      clickRow(row) {
        console.log(row.name) // 1 => ブタさん...
      }
    }
</script>
```

### 1行ごとに操作アイコンなどデータ以外の列を表示

[公式ドキュメントの例](https://dev.vuetifyjs.com/ja/components/data-tables#crud-actions)どおりに

1. ヘッダー列定義に操作用の列を追加
2. templateで操作列を定義

#### ヘッダ列への追加

```vue:vueスクリプト抜粋
    data: () => ({
      headers: [
       {text:'ID', value:'id'},
       {text:'なかまたち', value:'name'},
       {text:'操作', value:'action'}
      ],
～～～
```

#### 表示用template

```vue:vueのtemplate
<template lang="pug">
  v-data-table(
   :headers="headers"
   :items="db"
   hide-default-footer
   @click:row="clickRow"
  )
    // 各行・列の描画はよろしくやってくれるので操作列だけ記述すればよい
    template(v-slot:item.action="{item}")
       v-btn(@click="showName(item.name)")
         v-icon fa-home
</template>
<script>
(略)
    showName(str) {
      console.log(str)
    }
(略)
</script>
``` 

## まとめ

どうかけばいいのか調べるのに時間がかかったけど、結局公式ドキュメントをみて試してなんとかなった。
簡潔にかけるので1.5よりも楽じゃないだろうか。
特定の列だけ表示方法をかえるというのも例のとおりでなんとかなるのだろう。

上記例、それぞれなら問題ないが、行クリックと、操作ボタンを両方設定したいた場合、どちらも同時に実行される部分は未解決（ぐぬぬ）
libtorch を Android でビルドするメモ

https://pytorch.org/mobile/android/#building-pytorch-android-from-source

とりあえず一式ビルドするスクリプトあります(実態は cmake を呼んでいる)
 
## setup

* Android SDK
* Android NDK
* cmake, ninja
* Gradle

が必要です. Ubuntu 18.04 で Android Studio をインストールしておくのが楽でしょうか.

```
export ANDROID_HOME=$HOME/Android/Sdk
export ANDROID_NDK=$HOME/Android/Sdk/ndk/21.0.6113669/
# export GRADLE_HOME=$HOME/local/gradle
```

gradle は `GRADLE_HOME`, `GRADLE_PATH` で設定はうまく行かないかもです. PATH で直接 `gradle` が見えるようにしておくのがよさそうです.

また, gradle は特定のバージョンでないとうまくいきません. 執筆時点では 4.10.3 でした. sdkman あたりでインストールしておきましょう. 使っている gradle version は `.circleci` あたりの設定ファイルで確認しましょう.

あとは, python で yaml を使っているので `pip install pyyaml` しておきます.

## libtorch(.a) をビルドする

デフォルトでは arm, x86 でそれぞれ 32bit, 64bit で合計 4 種類ビルドするので, 必要な ABI が決まっていれば `ANDROID_ABI` で指定します.

```
ANDROID_ABI=arm64-v8a BUILD_PYTORCH_MOBILE=1 ./scripts/build_android.sh
```

C++ アプリメインであれば, この .a をあとはリンクすればいけるかと思います.

### コンパイル時間

1 アーキテクチャあたり Ryzen9 3950X で 10 分ほどです.
`torch/csrc/jit` 部分のコンパイルが時間かかります.

## Java binding やらをビルドして .so をビルドする

```
./scripts/build_pytorch_android.sh arm64-v8a
```

などとするだけです(内部で `build_android.sh` で .a を作ってから, fbjni などの .so を作っている).

一部 `c10/util/Registory.h` で cerr が見つからないと言われるかもしれません(.h で printf しているやんちゃなコードですね). そのときは適当にコメントアウトしてビルドしましょう.

## 注意点

ANDROID_ABI など, 設定を変えたら `build_android*` あたりのフォルダを消して再度一からビルドする必要があります.
(`build_***.sh` では既存のビルドディレクトリの中身を消してはくれないため)

## TODO

* [ ] Debug, Release ビルドの切り替えを試す
* [ ] Custom build https://pytorch.org/mobile/android/#custom-build を試す.
* [x] PC(Linux) 向けに libtorch ビルドする
  * `./scripts/build_local.sh` でいける
【nuxt.js】axios.postでOPTIONS メソッドが返ってきた

formの送信ボタンを押下したらOPTIONSメソッドが返ってきた時の対応メモ

### エラーのコード

```vuejs:index.vue
<template>

  <!-- 省略 -->

  <button @click="submit">
    送信
  </button>

  <!-- 省略 -->

</template>

<script>
import axios from "axios"

export default {

  // 省略

  methods: {
    // 省略
    create() {
      const data = {
        organization: this.organization,
        name: this.name,
        email: this.email,
      }

      const url = "https://app.1323/forms"
      axios
        .post(url, data)
        .then(response => {
          alert("pass")
        })
        .catch(error => {
          alert("error")
        })
    }
  }
}
</script>
```

### 原因
- APIサーバーのCORSの問題
    - CORSとは
        - オリジン間リソース共有、 Cross-Origin Resource Sharingの略
        - HTTPヘッダーの転送で構成されるシステムであり、ブラウザがオリジンをまたいだリクエストのレスポンスに、フロントエンドのJavaScriptコードがアクセスすることをブロックするかどうかを決めるもの
    - リクエストには、プリフライトリクエストとHTTPリクエストの2つがある
         - CORSプリフライトリクエストは、CORSプロトコルが理解されているかどうかを確認する

### 解決策
- nuxt.config.jsでプロキシを設定

```javascript:nuxt.config.js
{
  axios: { proxy: true },
  proxy: {
    "/forms": "https://app.1323"
  }
```

- proxyとは
    - 直訳すると「代理」
    - 内部ネットワークからインターネット接続を行う際、高速なアクセスや安全な通信などを確保するための中継サーバ
    - 内部と外部のネットワークの中継をする役割を持ち、情報の受け渡しを行う

### 修正後のコード

```vuejs:index.vue
<template>
  <!-- 省略 -->
</template>

<script>
import axios from "axios"

export default {

  // 省略

  methods: {
    // 省略
    click() {
      const data = {
        organization: this.organization,
        name: this.name,
        email: this.email,
      }

      axios
        .post("/forms", data)
        .then(response => {
          alert("pass")
        })
        .catch(error => {
          alert("api error")
        })
    }
  }
}
</script>
```

→ OPTIONメソッドではなくPOSTメソッドが返ってきた！

### 参照
- [Axios Module](https://axios.nuxtjs.org/options)
- [オリジン間リソース共有 (CORS) - HTTP | MDN](https://developer.mozilla.org/ja/docs/Web/HTTP/CORS) 
- [プロキシ（サーバ）とは？仕組みやメリット、セキュリティ対策について徹底解説](https://cybersecurity-jp.com/security-measures/32171)
async(Promise)のthen()内の関数の引数の省略

備忘録として書き記す。

nuxt.jsのコードを追っていたところ下記の部分で引っかかる。

```javascript:.nuxt/client.js
// Create and mount App
createApp().then(mountApp).catch(errorHandler)
```
コードの内容から察するにmountAppにはcreateAppの結果が引数として渡されているように見えるので実際に確かめてみた。


```javascript:main.js
const first = async () => {
  return 'first'
}

const second = (arg) => {
  console.log('second')
  console.log(arg)
}

// then内の関数に自動的に引数が渡される
first().then(second)
// second
// first

// 省略しないパターン
first().then((f) => second(f))
```

どなたかこのような振る舞いの名称や公式で記載されているページをご存知であれば、コメントで教えていただけると幸いです。
BSD 系の Network に関する手動設定について

FreeNAS などで BSD に触れる機会があり、Linuxと微妙にネットワーク設定が異なり、よく忘れるのでメモ。
以下例の`fxp0`は自環境のデバイス名に読み替える。

# 現在の IPアドレスを確認
複数のネットワークデバイスがある場合は一覧が表示される。

```console
# ifconfig
```

# ネットワークデバイスfxp0にIPアドレスの指定 (192.168.0.10/24)

```console
# ifconfig fxp0 inet 192.168.0.10 netmask 255.255.255.0
```

# エイリアスの設定 (192.168.0.10 を追加)

```console
# ifconfig fxp0 inet 192.168.0.10 netmask 255.255.255.255 alias
```

# エイリアスを無効にする (192.168.10.10 を無効)

```console
# ifconfig fxp0 inet 192.168.0.10 netmask 255.255.255.255 -alias
```

# メディアタイプの指定 (100base-TX)

```console
# ifconfig fxp0 media 100baseTX
```

# メディアタイプの指定 (10base-T)

```console
# ifconfig fxp0 media 10baseT/UTP
```

# duplex の指定 (full fuplex)

```console
# ifconfig fxp0 media 100baseTX mediaopt full-duplex
```

# auto の設定

```console
# ifconfig fxp0 media autoselect
```

# ネットワークデバイスの up down
DHCP クライアントでIP アドレスを取得したい時も up する。

```console
# ifconfig fxp0 down
```

```console
# ifconfig fxp0 up
```
# ルーティングテーブルの表示
Linuxの場合。

```console
# route
```

FreeBSDの場合。

```console
# netstat -nr
```

# default gateway の指定 (192.168.0.254 を指定)

```console
# route add default 192.168.0.254
```

# defalut gateway の削除

```console
# route delete default
```

# 経路の追加 -net (172.16.1.0/24 を 192.168.0.253 に)

```console
# route add -net 172.16.1.0 -netmask 255.255.255.0 192.168.0.253
```

# 経路の削除

```console
# route delete 172.16.1.0
```

# 経路の追加 -host (172.16.1.1 を 192.168.0.253 に)

```console
# route add -host 172.16.1.1 192.168.0.253
```

# 経路の検索

```console
# route get 172.16.1.1
```

# 経路のモニタ
ルーティングテーブルの変更、検索の失敗、などをモニタリングする。

```console
# route monitor
```
【SwiftUI】@Environmentを支える機能

# 基本的な記法

```swift:sample.swift
@Enviroment(.\accessibilityEnabled) var accessibilityEnabled
```

# 関数定義

```swift:definition.swift
@propertyWrapper public struct Environment<Value> : DynamicProperty {
    @inlinable public init(_ keyPath: KeyPath<EnvironmentValues, Value>(
    @inlinable public var wrappedValue: Value { get }
}
```

# なぜ `@Enviroment` のように書けるのか
Swift5.1で追加された@propertyWrapperというattributeを型に付けると、@Environmentのようにアノテーションぽい記述を行うことができます。このマークを付けると、値のget set する際にpropertyWrapperをつけた型を経由することが出来ます。

# なぜアノテーションの右に括弧があるのか
@propertyWrapperで指定した型にイニシャライザがある場合、引数はEnvironmentの場合は、KeyPathを引数に取って初期化されているので、`@Environment(.\accessibilityEnabled)`のようになります。

指定する[EnvironmentValues](https://developer.apple.com/documentation/swiftui/environmentvalues)は、かなり多くのプロパティを有しており、そのキーパスを渡す事でアクセスする仕組みになっています。

# [Dynamic Property](https://developer.apple.com/documentation/swiftui/dynamicproperty)とは何か
StateやBindingなども適合しているprotocolで、updateという必須実装の関数を一つだけ持っています。SwiftUIのモジュールに含まれています。

リファレンスを読むと以下のように書いてあります。

## ドキュメント
Viewの外部プロパティを更新する格納変数

## 概要
Viewは、Viewのbodyを再計算する前にこれらのプロパティに値を提供します。

内容をまとめると**「Dynamic Propertyとは、View外部のプロパティを更新するためのstored propertyで、bodyの中身を再計算するより前の段階でViewによって値が与えられる」**となります。

このケースで考えると、`@Enviroment(.\accessibilityEnabled) var accessibilityEnabled` のvar accessibilityEnabledの部分でstoredPropertyとして扱われていますね。説明を読むとこの環境値はbodyが計算される前に与えられているようなので、「Environmentの値の初期値がタイミングによっては取れない〜」みたいなことはなさそうですね。

# 参考
[SwiftUI徹底入門](https://www.sbcr.jp/product/4815604066/)

[apple doc](https://developer.apple.com/documentation/swiftui/environment)