OmniAICreator/Qiita-1.07M huggingface dataset:
システムリプレイスに伴うデータ移行やスキーマ変更との付き合い方

## システムリプレイスに伴うデータ移行の方法

既存システムをマイクロサービスへと切り分ける際、
DBに保存されているデータの移行に苦労したため振り返りの備忘録です。

### DMSによるデータ同期を選択

システム切り替えでのサービス停止をさけるため、
DMSで更新を同期し、既存システムのデータを新システムへと流し込む選択をしました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1056504/51587b6f-0103-e0f0-c938-efc50c51e660.png)

### MSK + ECSでスキーマ変更に対応

テーブル定義自体に更新があったため、
データ同期と同時に、MSK + ECSでデータの加工を行っています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1056504/7553f565-1fd7-1dfd-4328-bb735c9f55c0.png)



## 発生した課題

当初、アプリケーション構築の1ストーリーとして計画しましたが
手順、計画ともに課題があり難航しました。

### 検証までにかかる時間が長い

全てのデータが作成されるまで検証が行えず、検証実施まで数日の待ち時間が発生します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1056504/27a68618-eba2-90b5-b42a-440f7abee37d.png)

実施段階では、要求仕様時点で洗いもれのレコードや、
本番環境特有の不具合など、想定以上の手戻りが発生しています。


### 進捗の推移が何度でも0に戻る

通常の開発業務では不具合が検知された場合、タスクを積んでゴールを更新しますが、
データ移行では不備が見つかるたび、0から再作成が必要です。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1056504/e6446bf9-c981-6816-c3a6-292f5f0b3de8.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1056504/c1197dd6-4c95-b4d8-21e4-6e8c208e0e70.png)

## データ移行やスキーマ変更との付き合い方

やっておいて良かった点、次回以降取り入れたい点です。

### テストコード作成

1タスクの認識だったためテストはローカルでの確認のみでしたが、
デバッグ設定の解除漏れによる再作成などが発生したため
テストコード書いておくべきだったと思います。

### スキーマ変更とテーブル同期の分離

データ加工とテーブル同期を完全に分離していたため、
移行先DBの構築進捗やステータスに引きずられず作業が実施できました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1056504/82a259d9-20bb-29aa-ca6b-ca64e5094758.png)

### アプリケーション構築とのプロジェクト分離

DB定義後から着手可能で、結合テストまでに完了していればいいため
アプリケーション開発とは完全に切り分けて計画した方が
予備工数を設定しやすくなりそうです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1056504/f12fb73c-1c4f-997a-b475-e18eb0180cd8.png)

# 採用PR
弊社で一緒に働く仲間を募集しています。
全てのオタクを幸せにしたい方、是非ご覧ください！

https://hrmos.co/pages/vivion/jobs/0000191
Rust の Default::default(), T::new(), T::from() の使い分け

## 概要
Rustのnew()を複数定義することができないため、new()の使いどころは悩みますね。

リストやツリーなど自己参照型の構造体を書いていて、こうしたら良いのでは？というパターンが見えてきたので、まとめます。

## ポイント

* new は構造体のすべてのフィールドを明示的に初期化するメソッドとして実装する
  * 全フィールドを初期化するメソッドが増減することはないから、new()と同名のものを複数定義せずに済む
  * 全フィールドが必須なら、newだけあればよい
* 引数の指定が必要なかったり、すべて省略できる場合は Defaultトレイトを使う
* データのみを指定して初期化する場合は Fromトレイトが役立つ  
  一部フィールドを初期化する場合に役立つ場合もある
* どれにも当てはまらなければ、専用の初期化メソッドを作る  
  * 決まった使い方しかなければ、分かりやすい名前の初期化メソッドを作ればよい
  * パラメーターが多くあるなら、デザインパターンのBuildパターンを適用すればよい

## 例: Default

初期化でパラメーターが不要なら、 Defaultトレイトを使う。
これにより、個々の `new()` の仕様について学習せずに使える。

```rust
let mut list: SList<u8> = Default::default();
list.push_front(1);
list.push_front(2);
```

```rust
pub enum SList<T> {
    Cons(T, Rc<SList<T>>),
    Nil,
}

impl<T> Default for SList<T> {
    fn default() -> Self { SList::Nil }
}
```

## 例: From と new

* new はすべてのフィールドを明示的に初期化するためのメソッドとして定義するのが良い
  * new の効用として、内部の構造を隠ぺいできるメリットがある  
    例えば、Rc::new(…) を Box::new(…) に変更した場合に修正の影響が少なくできる
* from はデータのみ指定して、それ以外をデフォルトとする場合に都合が良い  
  newは1つしか宣言できないので、それを補う役割ができる。

```rust
pub enum SList<T> {
    Cons(T, Rc<SList<T>>),
    Nil,
}

impl<T> SList<T> {
    pub fn new(v: T, next: SList<T>) -> Self {
        SList::Cons(v, Rc::new(next))
    }

    pub fn push_back(&mut self, v: T) {
        let mut cur_slist_ref_mut = self;

        while let SList::Cons(_, next_rc_ref_mut) = cur_slist_ref_mut {
            // &mut SList<T> <- &mut Rc<SList<T>>
            cur_slist_ref_mut = Rc::get_mut(next_rc_ref_mut).unwrap();
        }

        let _ = std::mem::replace(cur_slist_ref_mut, SList::from(v));
    }

    pub fn push_front(&mut self, v: T) {
        let head_node: SList<T>;
        head_node = std::mem::replace(self, SList::Nil);

        let _ = std::mem::replace(self, SList::new(v, head_node));
    }
}

impl<T> From<T> for SList<T> {
    fn from(v: T) -> Self { SList::new(v, SList::Nil) }
}
```
Mysql2::Error ~~ DB名.action_text_rich_text' doesn't exists

### 事象
* Rails6の機能、`action_text`をdockerで実装しようとして出たエラー

### 結論
* nodeのバージョンを新しくしたらエラー解決

### 過程
* `$ rails action_text:install`すると、run ~~ で止まる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/453553/2853f5f4-cb55-6c20-92ed-a2ae20b1b830.png)

* 本来はこの後に`application.js`へ`trix`をrequireする、などを書き込んで欲しい

#### 問題の切り分け
* dockerを使わないで、localでやるとうまくいく。
* そのうまくいったlocalで`$ node -v`すると14代だった
* dockerにnodeをver指定する記述を足す

```dockerfile
RUN curl -sL https://deb.nodesource.com/setup_7.x | bash - && \
        apt-get install -y nodejs npm && npm install n -g && n 14.17.4
```

### その他
* railsguideにaction_textを使うならnode バージョンは~~以上、とは書いてない気がするんだが、、
* まだましか。laravelのreadoubleなんてもっとひどいもんな。
【PostgreSQL】基本構文早見表～SELECT文編～

# 本記事の内容
PostgreSQLのSELECT文で使用する基本的な構文を紹介します。
その他の構文については別記事にて紹介予定です。
※本記事はPostgreSQL 13を参考に記載しています。
※本記事はSQLを学んだことある人向けに、SQLの基本構文の早見表としてまとめています。構文の詳細は記載しておりませんのでご了承ください。

# テーブルのデータを取得する（SELECT, FROM）

### 1テーブルの全カラムを表示
```SQL
SELECT *
FROM [テーブル名]
```
*は全カラム取得を意味します。
[テーブル名]は適宜置き換えてください。

### 1テーブルの指定したカラムのみ表示
```SQL
SELECT [カラム名1], [カラム名2]
FROM [テーブル名]
```
### 複数テーブルのデータを取得
```SQL
SELECT *
FROM [テーブル名1] AS A
INNER JOIN [テーブル名2] AS B ON A.[カラム名1] = B.[カラム名1]
```
使用したい結合方法によって、```INNER```の部分を```LEFT```や```RIGHT```等に変更してください。

# 条件を指定してデータを取得する（WHERE）

### 条件1つ
```SQL
SELECT *
FROM [テーブル名]
WHERE [カラム1] = [条件]
```
### 条件複数
条件を複数指定する場合は、```AND```や```OR```でWHERE句に追加します。
全ての条件を満たすデータを抽出する場合はAND演算子を、
どれか一つでも満たすデータを抽出する場合はOR演算子を使用します。

:::note warn
AND演算子とOR演算子を併用することは可能です。
ただし、誤った順番や記載方法で使用すると、想定通りの結果が得られないことがあるので注意してください。
:::

```SQL
SELECT *
FROM [テーブル名]
WHERE [カラム1] = [値1]
AND [カラム2] = [値2]
```
```SQL
SELECT *
FROM [テーブル名]
WHERE [カラム1] = [値1]
OR [カラム2] = [値2]
```
### 条件記載パターン
WHERE句の[カラム1] = [値1]の部分を適宜求めたい条件に合わせて、下記に修正してください。
※条件の書き方はほんの一部を記載しております。

```SQL
[カラム1] <> [値1] -- 否定
[カラム1] IN ([値1], [値2]) --指定した値を含む
[カラム1] NOT IN ([値1], [値2]) --指定した値を含まない
[カラム1] IS NULL -- NULL値のもの
[カラム1] IS NOT NULL -- NULLでないもの
```

# グループ化してデータを取得する（GROUP BY, HAVING）
### GROUP BY
GROUP BYを使用することで、FROM句で取得したテーブルのうち重複したデータをまとめたり、集約関数を使用することができます。

:::note warn
GROUP BYを使用した際にはSELECT句には集約関数内のカラムを除き、GROUP BY句で使用しているカラム以外のカラムを指定するとエラーが発生するので注意してください。
:::

```SQL
SELECT [カラム1], [カラム2]
FROM [テーブル名]
GROUP BY [カラム1], [カラム2]
```

[カラム1]、[カラム2]に紐づく[カラム3]の数を出力。

```SQL
SELECT [カラム1], [カラム2], COUNT([カラム3])
FROM [テーブル名]
GROUP BY [カラム1], [カラム2]
```
### HAVING
HAVINGでGROUP BYでまとめたデータに対して、絞り込みを行うことができます。

```SQL
SELECT [カラム1], [カラム2]
FROM [テーブル名]
GROUP BY [カラム1], [カラム2]
HAVING SUM([カラム3]) > 10
```
※SUM(… > 10の部分は指定したい条件に合わせて適宜修正してください。

:::note info
HAVINGとWHEREの違い
HAVINGとWHEREはデータを条件で絞り込むという点では、変わりはありません。
では、何が違うのかというと処理のタイミングです。WHEREはFROM句で取得したデータに絞り込みをするのに対し、HAVINGはGROUP BYでまとめたデータにて絞り込みを行います。どちらで条件を絞り込むかによって結果が代わることがあるので注意しましょう。
:::

# データ件数を指定して取得する（LIMIT）
LIMITの後に数値を設定することで、指定した件数にてデータを取得できます。（SQL ServerのTOPと同じですが、LIMITはSELECT句内ではなく最後に記載します。） 

```SQL
SELECT *
FROM [テーブル名]
LIMIT 100
```
上記の例では100件のデータを取得します。
TextInputLayoutにxmlでテキストを指定したらエラーが出た

# やりたかったこと
_TextInputLayout_ を使った[テキストフィールド](https://material.io/components/text-fields)にテキストを指定したかった

# やったこと
こんな感じにxmlで _TextInputLayout_ にテキストを指定してみた

```
<com.google.android.material.textfield.TextInputLayout
    ~
    android:text="@{viewModel.user.name}">

    <com.google.android.material.textfield.TextInputEditText
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

</com.google.android.material.textfield.TextInputLayout>
```

# 出たエラー
> Cannot find a setter for < com.google.android.material.textfield.TextInputLayout android:text > that accepts parameter type 'java.lang.String'

> If a binding adapter provides the setter, check that the adapter is annotated correctly and that the parameter type matches.

_TextInputLayout_ では <font color="red">android:text</font> を _String_ 型では受け付けていませんよ、というエラー

# 解決策
<font color="red">android:text</font> は _TextInputEditText_ の方に書きましょう

```
<com.google.android.material.textfield.TextInputLayout
    ~>

    <com.google.android.material.textfield.TextInputEditText
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
　　　   android:text="@{viewModel.user.name}" />

</com.google.android.material.textfield.TextInputLayout>
```
JSON Web Token (JWT) Profile for OAuth 2.0 Access Tokens メモ

* `JSON Web Token (JWT) Profile for OAuth 2.0 Access Tokens draft-ietf-oauth-access-token-jwt-13`(JWT形式のアクセストークンに関する仕様)の個人用メモ
* アクセストークンをJWT形式にすることで、アクセストークンに紐付く情報をアクセストークンの中に埋め込む方法。



## アクセストークン データ構造

* 偽造検知のため、生成データに署名を含め、利用時に検証する。

### ヘッダー部

* 署名検証を行うために必要な情報を格納する

| パラメータ | 必須 | 説明                                                         |
| ---------- | ---- | ------------------------------------------------------------ |
| `typ`      | 〇   | トークン形式として`at+jwt`を指定する。                       |
| `alg`      |      | 署名に使用するアルゴリズムを指定する。`none`は指定しないこと。 |
| `kid`      |      | 鍵識別子。                                                   |



### ペイロード/クレーム部

| パラメータ   | 必須 | 説明                                                         |
| ------------ | ---- | ------------------------------------------------------------ |
| `iss`        | 〇   | JWT発行者                                                    |
| `exp`        | 〇   | JWT有効期限                                                  |
| `aud`        | 〇   | JWTを受け取るクライアント識別子 認可リクエストに`resource` パラメータが指定された場合、`aud`クレームには`resource`パラメータと同じ値が指定される |
| `sub`        | 〇   | リソースオーナー識別子                                       |
| ` client_id` | 〇   | クライアントID                                               |
| `iat`        | 〇   | JWT発行時刻                                                  |
| `jti `       | 〇   | JWTを一意に識別するための識別子                              |
| `scope`      |      | 認可範囲                                                     |

その他にもあり

## 認可リクエスト/JWTアクセストークン例

* 認可リクエスト

  ```http
  GET /as/authorization.oauth2?response_type=code
  &client_id=s6BhdRkqt3
  &state=xyz
  &scope=openid%20profile%20reademail
  &redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb
  &resource=https%3A%2F%2Frs.example.com%2F HTTP/1.1
  Host: authorization-server.example.com
  ```

* JWTアクセストークンのヘッダー部とクレーム部

  * ヘッダー部

    ```json
    {
        "typ":"at+JWT",
        "alg":"RS256",
        "kid":"RjEwOwOA"
    }
    ```

  * クレーム部

    ```json
    {
    	"iss": "https://authorization-server.example.com/",
        "sub": "5ba552d67",
        "aud":   "https://rs.example.com/",
        "exp": 1639528912,
        "iat": 1618354090,
        "jti" : "dbe39bf3a3ba4238a513f51d6e1691c4",
        "client_id": "s6BhdRkqt3",
        "scope": "openid profile reademail"
    }
    ```

    

## アクセストークン検証

* リソースサーバーは、偽造されていないことを検証してから、アクセストークンに埋め込まれている情報を利用する。

### 流れ

1. `typ`ヘッダーパラメータが`at+jwt`もしくは`application/at+jwt`であることを確認する。
2. JWTアクセストークンが暗号化されている場合は、登録時にリソースサーバーが指定したキーとアルゴリズムを使用して復号化する。
3. `iss`クレームを参照し、認可サーバー識別子と一致していることを確認する。
4. `aud`クレームがリソースサーバー識別子と一致していること確認する。
5. `alg`ヘッダーパラメータに指定されているアルゴリズムを使用し、署名を検証する。
6. `exp`クレームが現在時刻よりも未来日時であることを確認する。



## 参考情報

* [JSON Web Token (JWT) Profile for OAuth 2.0 Access Tokens draft-ietf-oauth-access-token-jwt-13](https://datatracker.ietf.org/doc/html/draft-ietf-oauth-access-token-jwt#section-2)
【SourceTree】既存ローカルリポジトリを追加

SourceTreeに既存のローカルリポジトリを追加する方法です。

前提としては、ローカルリポジトリが既にあること(リモートリポジトリからcloneできていること)です。SourceTreeに既存のローカルリポジトリを追加すると、ローカルリポジトリをSourceTreeで扱えるようになります。


#ローカルリポジトリを追加

**①一番右にあるタブ横の「＋」を押下します。（または、「メニュー」→「新規/クローンを作成する」でも同じことができます。）**

**②「Add」を押下します。**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/605915/86b3bd84-fb48-3d1f-fc2a-3f81de46da87.png)

**③Add a repositoryの画面がでてきたら、ローカルリポジトリをパスを指定します。（参照横の入力フォーム）**

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/605915/6e98bcbf-7044-da4b-ecff-00b93cefa00b.png)

**④「名前」のフォームに名前を付けましょう。**

**⑤「追加」ボタンが活性になるので、「追加」を押下します。**


これで、「SourceTree」でローカルリポジトリを扱えるようになります。
たまに行うのですがやり方を忘れてしまうので、備忘録として投稿します。

最後まで読んでいただいた方、ありがとうございました。
Pickerのタップ領域がClippedされない

備忘録

iOS14 では.clipped()のみでタップ領域をClippedできていたが、iOS15では効いていないよう。

.compositingGroup()をつけることで解消された。



```Swift
Picker(selection: $Index, label:Text("picker"), content: {
       //data contents
}).frame(width: UIScreen.main.bounds.width/3, height: 50)
  .compositingGroup() //これが必要
  .clipped()
```




# 参考
[Picker (wheel style) value selection point (drag area) is offset from the frame.](https://developer.apple.com/forums/thread/689794)
MVCモデルのWebアプリ開発を実施した後の完成イメージについて

> このWEBアプリ開発を行うことで簡易的に以下ことが習得できるようになります。
現場での実装レベル、設計レベルの基準に満たないですがフロントエンド(クライアントサイド)とバックエンド(サーバーサイド)での実装方法がわかるかなと思い開発しました。

・　データベースへのデータ登録方法
・　データベースからのデータ出力方法
・　htmlから何かしらのボタンを押した時のスクリプト実行方法
・　Githubでのバージョン管理などの基本操作方法
・　テーブル設計

> 今後の実装予定
・　Vue.jsを現在一部に取り入れているため、一部のフロント部分の部品を構築しリプレース的な感じでhtmlをいじっていこうと思っています。
・　ログイン処理機能で認証機能を勉強中なのでしばらくしてからログイン処理は機能すると思います。

# 全体の画面設計およびアプリイメージ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542047/a881668e-72c0-c506-10b3-06d54c9dc48a.png)

# 実際の作成状況

# サインアップ画面
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542047/2388be47-9c52-d8ec-59e0-efe13acc3e18.png)


# ログイン画面
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542047/4393872f-d571-39f6-5980-6695b585cfd1.png)


# トップページ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542047/2e82a075-9274-5dfa-7ecd-f626307e79b1.png)


# データ登録画面
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542047/4dbf603a-57be-31fa-8926-16a938bbdac8.png)


# データ登録後画面
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542047/35211585-1d55-a634-561a-e1a6bfd5a6fd.png)


#データ検索画面およびCSVファイル出力画面
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542047/fd749c56-e4f9-cfc6-3b58-9445ea554425.png)


#データ検索後画面
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542047/706f65c7-237e-87d0-af20-242ded66f23c.png)


#CSVデータ出力後画面
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542047/33c5f196-587b-5997-ca9b-d1516f047cc2.png)


#CSVデータ出力結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542047/fb8ac3c0-10bb-a072-ee90-e5cc65a13ae8.png)


#作成テーブル
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542047/ee45aa00-0e02-cda1-b4e6-6dfbe5046339.png)


#ログインパスワードについてはハッシュ値にしてデータとして保持
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542047/ad404b46-aeb3-5665-75af-b71e90e1b4dc.png)

デザインを補正した部分を以下の記事に取りまとめました。
https://qiita.com/noss08327439/private/33f68bc86efe08911ad2
送信元IPアドレスとVPCエンドポイントに基づいてAWSマネジメントコンソールへのアクセスを制限したい

#はじめに
セキュリティ要件によりAWSマネジメントコンソールへのアクセスをIPアドレスで制限したい場合があります。
しかし__AWSマネジメントコンソールにログインするIPアドレスを制限することはできません。__
代わりにIAMポリシーのグローバル条件キーであるaws:SourceIpを使用して権限でAWSサービスへの操作が可能なIPアドレスを制限することが可能です。

https://aws.amazon.com/jp/premiumsupport/knowledge-center/iam-restrict-calls-ip-addresses/

基本的には公式で紹介されているAssumeRoleを使用した解決できますが、AssumeRoleを使用せず直接IAMユーザの権限を使用してAWSの操作が可能なポリシーを作成する方法を紹介します。
Direct ConnectやVPNでプライベートな接続を行っている環境でインターネットへの接続がプロキシで制限されている場合等を想定しています。

#課題
前述した通り公式で紹介されているポリシーでソースIPに基づいてアクセスの制限を行うことは可能です。
しかし、AssumeRoleを使用しない場合各AWSサービスへのAPIコールに対して毎回リクエスト元（送信元IPアドレス）の評価を行うため、VPCエンドポイントを設置するとaws:SourceIpによるリクエスト元の評価ができません。
よってVPCエンドポイントにも対応した汎用的なポリシーを考えていきます。

>aws:SourceIp
>可用性 – このキーは、リクエスタが VPC エンドポイントを使用してリクエストを行う場合を除き、リクエストコンテキストに含まれます。
>https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/reference_policies_condition-keys.html#condition-keys-sourceip

#解決
##IAMポリシー
下記のポリシーを使用することでVPCエンドポイントを経由した場合でも正しく評価を行ってくれます。

```ruby:sourceiplimit
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Deny",
      "Action": "*",
      "Resource": "*",
      "Condition": {
        "NotIpAddress": {
          "aws:SourceIp": "11.22.33.44/32"
        },
        "Null": {
            "aws:SourceVpce": "true"
        },
        "Bool":{
            "aws:ViaAWSService": "false"
        }
      }
    }
  ]
}
```

##説明
条件キーの有無を確認することができるNULL演算子を使用し、aws:SourceVpceがtrue（条件キーが存在しない）場合にすべての操作をDenyにする条件をANDで追加しています。
つまりこの条件を追加することでVPCエンドポイントを経由する場合はaws:SourceIpによる評価を行わずに通信を行うことが可能です。
>aws:SourceVpce
>可用性 – このキーは、リクエスタが VPC エンドポイントを使用してリクエストを行う場合にのみリクエストコンテキストに含まれます。
>https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/reference_policies_condition-keys.html#condition-keys-sourcevpce

このポリシーでは以下の条件に合致するリクエストについてはすべて明示的な拒否を行うようになっています。

* リクエスト元IPアドレスが11.22.33.44/32ではない　かつ
* aws:SourceVpceがtrueである　かつ
* aws:ViaAWSServiceがfalseである
Webアプリケーションにおけるパラメータの種類と違いをまとめてみた

# パスパラメータ

- 一意なリソースを識別するための情報を入れる

## 例

 `comment_id`がパスパラメータに該当する（Qiita API v2より抜粋）

```
GET /api/v2/comments/:comment_id
```
https://qiita.com/api/v2/docs#get-apiv2commentscomment_id

# クエリパラメータ

```
https://example.com/list?query_parameter=1&query_parameter=2
```

- ? 以降がクエリパラメータ
- `? + 変数名 = 変数の値` という形式
- パラメータが複数ある場合は `&` でつなぐ
- 特定のリソースを操作して取得する際に必要な情報は、クエリパラメータに入れる
  - 検索系に使用する
  - GETのみで使用できる（POSTでは使用できない）
- クエリパラメータは、以下に記録されていることが多い
    - Webサーバのアクセスログ
    - ファイヤーウォールログ
    - プロキシサーバのキャッシュやログ
    - ブラウザのキャッシュや履歴


# クエリパラメータの用途

- ユーザーが入力したパラメータの送信（検索条件など）
- Webページ間のパラメータの受け渡し
- Webアプリケーションへのパラメータ付きリンク

# 見られて困る情報はクエリパラメータを使わない

- 見られて困る情報例
    - パスワード
    - Webメールのメール内容などの個人用データ
    - 名前，年齢，住所などの個人情報
    - Webアプリケーション内部のデータ構造
    - Webサーバ内部のフルパスなどの各種システム情報
- 見られて困る情報と困らない情報を分類するべき
    - Webアプリケーション設計時に注意する


# リクエストボディ

- 追加、更新する際の内容を入れる
    - POSTとPUT
- idやパスワードなど、漏洩したら困る情報を付与する
- リクエストボディはログなどには記録されないため、GETよりPOSTのほうが安全

```実行するAPI.
https://example.com/members/
```

```リクエストボディ.
{
  name:"yamada taro",
  age:20
}
```

## リクエストボディの用途

- 見られて困る情報を隠すため、クエリパラメータではなくリクエストボディを使う
    - ユーザーID、パスワードなど

# SQLインジェクションとは？

- SQLの呼び出し方に不備がある場合に発生する脆弱性
- 非常に影響の大きな脆弱性なので、絶対に混入しないようにすることが求められる

## どういう影響を受けるか

- DBの全ての情報が外部から盗まれる
- DBの内容が書き換えられる
- 認証を回避される
    - IDとパスワードを用いずにログインされる
- DBサーバ上のファイルの読み出し、書き込み、プロウラムの実行などが行われる

## 対策

- エスケープ処理を実施する
    - プログラムで使う特殊の記号を普通の文字をとして扱う
    - \（円記号）をつけることで、特殊文字を「普通の文字」として認識できる
        - 例） "（ダブルクォーテーション） → \"

# 参考文献

https://www.hypertextcandy.com/web-api-url-design-primer

https://www.ipa.go.jp/files/000024396.pdf

https://www.ipa.go.jp/security/awareness/vendor/programmingv1/a01_04.html
IAMのポリシーにジョブ機能ってあるけどこれなに？

## 勉強前イメージ

正直良くわからん・・・

## 調査

### IAMとポリシーについて

Identity and Access Management の略で、AWSのサービス。
ユーザを作ったり、そのユーザに対してサービスへのアクセス等の制御を行うことができます。
そしてポリシーとはユーザに対して「s3へのアップロードのみの権限」や、「EC2の閲覧のみの権限」など各サービスへの制御を行うものを指します。
今回そこに「ジョブ機能」というのがあったので調べてみました。
ちなみにマネジメントコンソールだとIAMのポリシーの以下になります。

![10IAM Management Console - Google Chrome 2022-02-05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129517/fa128881-b144-e34f-2bf4-639efe3321cc.png)


### ジョブ機能 とは

職務機能のAWS管理ポリシーと呼ばれていて、AWS管理ポリシーの一部です。
AWS管理ポリシーとは基本的にs3やEC2といったサービス単位の権限として作られていますが、
職務機能のジョブ機能ポリシーというのは利用する人の役割を考えて作られています。
どういうことかというと、そもそもAWSアカウントの管理者だったり料金だけ確認する人だったり、ガリガリネットワーク触る人だったり
アクセスする人は様々な役割を持っています。
その役割をAWSが想定して、「こういう人ならこのポリシーをアタッチするだけで安全に簡単にセキュリティを守れるよ」というポリシーをデフォルトで作ってくれているのがこちらのジョブ機能です。
想定されている役割は以下の10個です。

- SupportUser : サポート用ユーザ
- ViewOnlyAccess : 閲覧専用ユーザ
- Billing : 請求関連(請求情報の確認、支払いの設定、AWSのサービスコスト等)の確認するユーザ
- DatabaseAdministrator : データベース管理者
- SystemAdministrator : システムのセットアップやメンテナンスを行う管理者
- AdministratorAccess : 管理者(フルアクセス)
- SecurityAudit : セキュリティ監査用(セキュリティ要件のモニタリング等)ユーザ
- DataScientist : EMR等のデータ分析を行うユーザ
- NetworkAdministrator : ネットワーク管理者
- PowerUserAccess : アプリケーションのタスクの実行などのユーザ


また、以下のように1年程度でポリシーのメンテナンスがされバージョンアップされます。
変更がかかった際には確認しておいたほうが良さそうですね。

![11IAM Management Console - Google Chrome 2022-02-05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129517/2301755e-9e63-9ee5-e1e4-ab7eaea07a20.png)

### まとめ

まとめると以下です。
AWS管理ポリシーの一部の役割別のポリシーと覚えておいていただけるといいかなと思います。

- アイデンティティベース
	- インラインポリシー
	- 管理ポリシー
		- AWS管理ポリシー
			- ジョブ機能(職務機能) ← 今日のはコレ！！！！
			- その他のサービス単位のポリシー
		- カスタマー管理ポリシー


## 勉強後イメージ

役割別ってのもあったのか・・・
それに会社の権限とかもろもろがぴったしハマったらよさげ？

## 参考

- [AWSジョブ機能の 管理ポリシー](https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/access_policies_job-functions.html#jf_developer-power-user)
- [職務機能のAWS 管理ポリシーから昔を振り返る](https://dev.classmethod.jp/articles/job-functions-history/)
pythonの`zip()`を使うと、リストなどをまとめて扱うことができる。リストの大きさが違う場合に長さが長い方を基準に扱いたい場合は`zip_longest`を使うと便利である。

pythonの`zip()`を使うと、リストなどをまとめて扱うことができる。

> zip()は複数のイテラブルオブジェクト（リストやタプルなど）の要素をまとめる関数

```python:test.py
names = ['AAA', 'BBB', 'CCC', 'DDD']
ages = [10, 20, 30, 40]

for name, age in zip(names, ages):
    print(name, age)
```

```bash
$ python test.py
AAA 10
BBB 20
CCC 30
DDD 40
```

しかし、リストの大きさが違う場合は短い方を基準に扱われる。
（長い方は扱われない要素が出てくる）

```python:test.py
names = ['AAA', 'BBB', 'CCC', 'DDD']
ages = [10, 20, 30]

for name, age in zip(names, ages):
    print(name, age)
```

```bash
$ python test.py
AAA 10
BBB 20
CCC 30
```

リストの大きさが違う場合に長さが長い方を基準に扱いたい場合は`zip_longest`を使うと便利である。
長い方に処理を合わせてくれる。(存在しないデータは`None`と表示してくれる)

```python:test.py
from itertools import zip_longest
names = ['AAA', 'BBB', 'CCC', 'DDD']
ages = [10, 20, 30]

for name, age in zip_longest(names, ages):
    print(name, age)
```

```bash
$ python test.py
AAA 10
BBB 20
CCC 30
DDD None
```

それだけです。

# 参考

[Python, zip関数の使い方: 複数のリストの要素をまとめて取得](https://note.nkmk.me/python-zip-usage-for/)
ラテン超方格サンプリング（LHS）の実装（Python）

研究でラテン超方格サンプリング（LHS）を実装する機会があったのでまとめてみました。
間違いやご提案があればご連絡ください。

# ラテン超方格サンプリング（LHS）とは
実験計画法の一つでできるだけ探索空間から均一にサンプリングする手法の一つ
単純なランダムサンプリングよりも効率的にサンプリングできるらしい。

具体的には、サンプリング点数で探索空間を分割する。
例えば2次元空間から10点をサンプリングするなら、10×10の格子を生成する。
そこから、行と列が一致しないように格子を10個選び、その中でランダムサンプリングする。
以下は、2次元空間から5点サンプリングするときの例。

![LHS_2_5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2522022/eebb3fe9-0355-238c-fc7b-3c70867762b5.png)


# 実装
ここでは二次元空間からのサンプリングを例として実装を行う。

```
import numpy as np

n_dim = 2  # number of dimension
n_sample = 10  # number of sample

lhs_idx = np.zeros([n_sample, n_dim])
for i in range(n_dim):
    lhs_idx[:, i] = np.random.permutation(grid_array)

# array for storing values
lhs_result = np.zeros([n_sample, n_dim])
for i in range(n_sample):
    for j in range(n_dim):
        lhs_result[i, j] = (np.random.rand() + lhs_idx[i, j])/n_sample
```
これはPythonのpyDOEライブラリを使うと、

```
import pyDOE2 as doe

n_dim = 2  # number of dimension
n_sample = 10  # number of sample
lhs = doe.lhs(n_dim, samples=n_sample )
```
となる。


# 追加でサンプリングしたいとき
最初にn点サンプリングした後にm点サンプリングに変更したい場合について考える（n < m）。
この場合は、m×mでグリッドを生成し、n点サンプリングで追加されているグリッド以外から行と列が一致しないようにグリッドを選んでランダムサンプリングする。

下に、先ほど示した5点から追加で5点サンプリングする場合を示している。
この場合は下の青い領域から行と列が一致しないように格子を決めればいい。

![LHS_2_5+5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2522022/28ccd805-9220-8b1f-1309-cd116e02e7cd.png)



```
# 'init_array' is initial lhs array.
old_lhs_idx = np.floor(init_array / (1/n_sample)).astype('int32')
old_n_sample = init_array.shape[0]

new_n_sample = n_sample-old_n_sample
new_lhs_idx = np.zeros([new_n_sample, n_dim])

for i in range(n_dim):
    # remove the old index and permutation
    new_lhs_idx[:, i] = np.random.permutation(np.delete(grid_array, old_lhs_idx[:, i], 0))

new_lhs_result = np.zeros([new_n_sample, n_dim])
for i in range(new_n_sample):
    for j in range(n_dim):
        new_lhs_result[i, j] = (np.random.rand() + new_lhs_idx[i, j])/n_sample

lhs_idx = np.concatenate([old_lhs_idx, new_lhs_idx], axis=0)
lhs_result = np.concatenate([init_array, new_lhs_result], axis=0)
```


まとめたコードはGithubにあげときます。
[こちらから](https://github.com/kentoakiyama/LHS)
テスト60

```vb
'Excel
Sub Excel_SQL_JOIN()
'-----------------------------
'参照設定
'Microsoft ActiveX Data Objects 6.1 Library

'Excel内で2つのシートを使って右外部結合と
'左外部結合をするためのサンプルSQL....〆('ω' )
'-----------------------------

Dim CN As ADODB.Connection
Dim RS As ADODB.Recordset
Dim MyPath As String
Dim i As Long

Set CN = New ADODB.Connection
Set RS = New ADODB.Recordset

MyPath = ThisWorkbook.FullName

CN.Open "Provider=Microsoft.ACE.OLEDB.12.0;" & _
               "Data Source=" & MyPath & ";" & _
               "Extended Properties='Excel 12.0;HDR=YES' "
               
'左外部結合
Set RS = CN.Execute("SELECT A.商品カテゴリコード, B.商品カテゴリコード " & _
                    "FROM [テストデータ$] AS A " & _
                    "LEFT OUTER JOIN [テストデータ2$] AS B " & _
                    "ON A.商品カテゴリコード = B.商品カテゴリコード")

'右外部結合
'Set RS = CN.Execute("SELECT A.商品カテゴリコード, B.商品カテゴリコード " & _
'                    "FROM [テストデータ$] AS A " & _
'                    "RIGHT OUTER JOIN [テストデータ2$] AS B " & _
'                    "ON A.商品カテゴリコード = B.商品カテゴリコード")
i = 2

With ThisWorkbook.Sheets("テスト出力")
    
    .Cells.Clear
    
    .Range("A1:B1").Value = Array("商品カテゴリコード_A", "商品カテゴリコード_B")

    Do Until RS.EOF
    
        .Cells(i, 1).Value = IIf(IsNull(RS.Fields(0)), "Null", RS.Fields(0))
        .Cells(i, 2).Value = IIf(IsNull(RS.Fields(1)), "Null", RS.Fields(1))

        i = i + 1
        RS.MoveNext
    
    Loop
    
    .Columns("A:B").AutoFit

End With


RS.Close
CN.Close

Set RS = Nothing
Set CN = Nothing

MsgBox "処理が終了しました。", vbInformation

End Sub


'Sub Get_Com()
'
'Dim CN As ADODB.Connection
'Dim RS As ADODB.Recordset
'Dim tmp As Variant
'Dim com As Variant
'Set CN = CurrentProject.Connection
'
'Set RS = New ADODB.Recordset
'
'RS.Open "T_コメント", CN, adOpenKeyset, adLockReadOnly
'
'tmp = Split(RS.Fields(0), Chr(13) + Chr(10) + vbCrLf)
'
'For Each com In tmp
'
'    Debug.Print com
'
'Next com
'
'RS.Close: CN.Close
'
'Set RS = Nothing
'Set CN = Nothing
'
'End Sub
はんだ付けなしでピンソケットをRaspberry pi picoにたてる

##はじめに
　Raspberry pi picoで電子工作を行おうとすると、スルーホールの穴の部分にピンヘッダを立てたり、配線をしたりする必要があります。
![https___qiita-image-store.s3.ap-northeast-1.amazonaws.com_0_693019_44d63213-b8eb-aafc-896f-28c1a3c41937.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/693019/65a39210-7175-6053-6a68-b08cb5e664fd.png)

　多くの場合、はんだ付けすることになるのですが、テグスを使ってはんだ付け無しにピンヘッダを立てる方法を最近紹介しました。

https://qiita.com/kazueda/items/18128ff8f951161a424f

　ピンヘッダを立てた場合、ピンヘッダと電子部品の接続では、ブレッドボードやジャンプワイヤ等が必要となります。

![ブレッドボードとジャンプワイヤのLチカ (2).jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/693019/83c53b9c-0039-98e5-7c0b-24fb26a6d2df.jpeg "（左）ピンヘッダ付きPicoとブレッドっボードを使って配線したLチカ。（右）ピンヘッダ付きPicoとジャンプワイヤを使って配線したLチカ")
（左）ピンヘッダ付きPicoとブレッドっボードを使って配線したLチカ。（右）ピンヘッダ付きPicoとジャンプワイヤを使って配線したLチカ
　
　一方、ピンソケットを立てたRapsberry pi picoを使用する場合、下に示すように、ピンソケットに直接接続することが可能です。

![DSCF2677 (2).JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/693019/5d9702f3-5d27-bc43-fef7-46c87053a17c.jpeg)

　今回は、ピンソケットをはんだ付けしないでたててみます。

##ピンヘッダとピンソケットの足の形状
　ピンヘッダの足は直方体でしたが、ピンソケットの足は板状です。
![スライド3 (2).JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/693019/cd823f89-f114-b6a1-5c41-7803fb3e40f5.jpeg "ピンヘッダの足の形状")
ピンヘッダの足の形状

![スライド2 (2).JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/693019/cf1c16e5-be10-c3fe-0007-a6f81b193321.jpeg "ピンソケットの足の形状")
ピンソケットの足の形状

　ピンソケットが板状なので、ピンソケットを固定した時に使用したテグスより太い、直径0.7から0.9 mmのテグスが必要となります。
手芸用テグスの最大の太さは約0.47 mmなので、それより太いテグスは、釣り用の長いものになり高価になります。
比較的低価格で入手できるワイヤとして、手芸用品にブレスレット作成用のワイヤがありましたので、それらのうち、0.8 mmの太さのワイヤを使うことにします。
テグスとの違いは、より伸びやすく、弾力性がより大きいことです。

##波縫いしたワイヤとスルーホール

　下に、0.8 mmのワイヤを波縫いした様子を示します。
　![DSCF2671 (2).JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/693019/24e9c5d6-9d64-0827-e762-16a399ae61c0.jpeg "0.8 mmのワイヤを波縫いした様子")

##ピンソケットの足を差し込む
　<font color="Red">**基板を壊さないように、**</font>ピンソケットの足をワイヤとスルーホールの隙間に差し込みます。
私は、ワイヤが外側になるように差し込みました。
下に、差し込んだ後の写真を示します。
ピンソケットの足がスルーホールの壁に接触しているのがわかります。
![DSCF2674 (2).JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/693019/ff8db79d-aef9-2bdd-d121-2d1853887f48.jpeg "基板の裏側から見た様子")
基板の裏側から見た様子

![DSCF2675 (2).JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/693019/4a2d5e51-c2e1-125c-5bae-057632a6cf14.jpeg "基板の側面から見た様子")
基板の側面から見た様子

伸縮性が良いので、ピンソケットの足に押されて縫い目が飛び出しています。
余談ですが、ワイヤの端はピンソケットの足より長くしてから切ると、クッションになってよいようです。

　注意点は以下の通り。
1. ワイヤが伸びやすいので、スルーホールを縫う場合に引っ張らないようにします。伸びきっていると、ピンソケットの足を刺す際に、切れてしまう可能性があります。
2. ピンソケットの足の大きさに比べてワイヤの太さは大きいので、ワイヤをあまり傷つけないように、すべての足がワイヤに対して内側か、外側に刺さるように、差し込むほうが良いかと思います。
3. ワイヤのほうが太いため、差し込みにくくなるっています。<font color="Red">**くれぐれも、基板を壊さないように作業しましょう。**</font>

##無事Lチカできました
![DSCF2676 (2).JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/693019/c62a0533-93b8-44ed-9259-309a3d76afad.jpeg)
Kali LinuxをRaspberry Piに載せてみる

色々あって、セキュリティの勉強をもっとちゃんとやろうと思い、Kali Linuxの導入を考えていました。
メインで使っているMacBookに共存させようかなとも思いましたが、色々やるのにメインの端末使うのはちょっとリスクがあるなぁと悩んでいると目の前に魅力的な端末が転がっていました。
![IMG_0085.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2255713/f3159189-a6c9-393b-e273-48e771f7365a.jpeg)

**Raspberry Piくん。**
学生の頃にマルツで買い、後輩が3Dプリンタでケースを作ってくれた思い出の端末です。
静電気の時期なので、基板が剥き出しにならないこのケースにあらためて感謝を込めて、**OSをKaliに焼き直します**。

ちなみにこのラズパイくんは、学生の頃に作った全方位移動ロボットのCPUとして活躍してくれた子です。
なんかの懸賞で当たったオムニホイールを使いたくて作ったロボットで、さすがにいらないので大学に置いてきましたが今はどこにいるのやら。
![IMG_0935.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2255713/2043fb0c-09b4-e78a-cefc-bac37a5fce6c.jpeg)

話がそれまくりましたが、KaliをインストールしてSSHの設定をするまでの順番をメモしていきます。

#OSのダウンロード
まずはOSのダウンロードをします。仮想環境用からARM　CPU用などのラインナップがありましたが、ちょっと驚いたのが**Android端末用**もあったこと。UbuntuならともかくKaliをスマホにいれるってなんかクールですね。

https://www.kali.org/get-kali/

![スクリーンショット 2022-02-06 13.23.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2255713/ab6b2293-4960-78b8-ff75-20a81fa4aea4.png)

ということで、ラズパイのモデルによって焼くOSが変わるのですが・・・
**うちの子って2だっけ？3だっけ？**

まぁ、間違っていたらやり直せばいいかと思いとりあえず一番上の32bit版をダウンロードしました。
※結局合ってました

#Kaliのインストール
ダウンロードが終わりましたので、SDカードを初期化して焼き込みます。
Macであれば以下のコマンドで焼き焼きできます。

```terminal
$sudo dd if=/Users/userName/Downloads/kali-linux-2021.4-rpi-armhf.img of=/dev/rdisk2 bs=1m
```
上記のif以降のパスからimgまでは、ご自身の環境に合わせて変えてください。
OSのimgファイルを解凍した場所が該当します。
また、後半のディスク番号も人によって異なるため以下のコマンドなどで確認をして変更してください。
※ディスクユーティリティのアプリでも確認できた気がします。

```terminal
$diskutil list
```

OSをSDカードに焼けましたら、ラズパイに装着をしていよいよ起動です。

#Raspberry Piの起動
先ほどのSDカード、キーボードとHDMI、電源を接続してラズパイを起動します。
モデル1は無線モジュールが搭載されていなかった気がするので、LANケーブルも接続しましょう。

起動すると、CUI上でわらわらといろんなコマンドが走ってしばらく待つとログイン画面に遷移します。
ログイン画面自体はGUI上での表示でした。（スクショは忘れました⭐️）

初期のIDは「root」、パスは「toor」だと思っていましたが、**何度もdenyされます**。
悲しみながらググってみたところ、つい最近初期IDも初期パスも「**Kali**」になったみたいです。

https://news.mynavi.jp/techplus/article/20200108-951143/#:~:text=%E4%BB%8A%E5%BE%8C%E3%81%AF%E3%83%A6%E3%83%BC%E3%82%B6%E5%90%8Dkali,%E3%81%AB%E4%BD%BF%E3%81%86%E3%81%93%E3%81%A8%E3%81%AB%E3%81%AA%E3%82%8B%E3%80%82

ログインに成功して、なんとかホーム画面まで辿り着きました。
![Screenshot_2022-02-05_14_33_51.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2255713/bd9d5aa1-f6e2-f7b5-add9-534d48a03126.jpeg)

**わー、かっこいい！**
けど、こんなにラズパイって重かったっけ？と思うくらい処理はカクカクでした。
流石に何年も前の端末なので仕方がないですかね。

#SSHの設定
Kaliを使うためにいちいちラズパイを起動するの面倒なので、常時電源だけ接続してMac側で制御できるようSSHの設定をしていきます。
SSHの設定は以下のコマンドで行います。（先にaptコマンドをアップデートしときましょ。）

```terminal
$ sudo apt update
$ sudo apt install openssh-server
```
上記コマンドが問題なく実行できれば、あとはSSH serverの設定をオンにすればSSHの立ち上げは終わりです。

```terminal
$ sudo systemctl enable ssh
$ sudo systemctl start ssh
```
最後に自身のIPアドレスをifconfigで確認して、控えておきます。

続いては接続する端末側で作業をします。僕はMacなので、以下のコマンドでSSH接続をします。
Windowsの場合はTeraTermなどで接続しましょう（コマンドプロンプトからできるんだっけ）。

```terminal
$ ssh kali@192.168.3.11 
```
上記のIPアドレスは私の環境下でのアドレスなので、適宜ご自身のアドレスに変更してください。
特に問題がなければ以下のようにおしゃれなCUIが表示されます。
![スクリーンショット 2022-02-06 14.02.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2255713/56b45d96-ea0b-1c63-073b-ee245a432dc5.png)


ここまでの流れで、ラズパイにKaliを焼き込む方法とSSHを立ち上げるまでは完了です。

これで勉強も捗りますね。色々触ってみてまた文字にまとめてみます。
ただ、今回めちゃめちゃ思ったのは**ラズパイしょぼすぎて重い。**
Splunk: 秒単位の値をHH:MM:SS形式に変換してみる

ときどき必要となるのでメモ。

###### 実施環境： Splunk Free 8.2.2

 Splunk のジョブの実行時間ログなどは秒単位の値で出力されます。
それを HH : MM : SS 形式に変換する方法を考えてみます。

まず、元の秒単位の値を以下のように切り分けます。

* 時 : 60で2回割り、小数点以下を切り下げる
* 分 : 60で1回割り、小数点以下を切り下げ、60で割った余りをとる
* 秒 : 60で割った余りをとり、小数点以下を切り下げる
* ミリ秒 : 小数点以下を切り下げた値を元の値から引き、1000をかける

```Splunk:Splunk
| makeresults
| eval SECONDS = 7650.001
| eval TIME_H = floor(SECONDS / 60  / 60),
       TIME_M = floor(SECONDS / 60) % 60,
       TIME_S = floor(SECONDS % 60),
       TIME_Q = (SECONDS - floor(SECONDS)) * 1000
```

![スクリーンショット 2021-12-19 20.48.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1465018/4b8f6a1e-0a3e-a949-a882-fef7874b7dcf.png "時、分、秒、ミリ秒")

これだけだと上記のように桁数が揃わないので、 printf 関数を使用して桁数を揃えます。

```Splunk:Splunk
| makeresults
| eval SECONDS = 7650.001
| eval TIME_H = printf("%02d", floor(SECONDS / 60  / 60)),
       TIME_M = printf("%02d", floor(SECONDS / 60) % 60),
       TIME_S = printf("%02d", floor(SECONDS % 60)),
       TIME_Q = printf("%03d", (SECONDS - floor(SECONDS)) * 1000)
```

![スクリーンショット 2021-12-19 20.46.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1465018/b4a1f3d6-9679-053b-3c76-dfdb799ff59a.png "HH、MM、SS、QQQ")

あとはこれらを文字列として結合すれば完了です。

```Splunk:Splunk
| makeresults
| eval SECONDS = 7650.001
| eval TIME_H = printf("%02d", floor(SECONDS / 60  / 60)),
       TIME_M = printf("%02d", floor(SECONDS / 60) % 60),
       TIME_S = printf("%02d", floor(SECONDS % 60)),
       TIME_Q = printf("%03d", (SECONDS - floor(SECONDS)) * 1000)
| eval TIME = TIME_H + ":" + TIME_M + ":" + TIME_S + "." + TIME_Q
| table TIME, SECONDS
```

![スクリーンショット 2021-12-19 20.44.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1465018/7c6e1c17-e2c6-ba2d-ff79-5d5c9589840e.png "HH:MM:SS.QQQ")
AWS S3ストレージクラスまとめ

AWS SAAの勉強に向けたまとめなので、詳細は以下ページを参考にしてください。
[AWS公式 S3ストレージクラスの説明](https://aws.amazon.com/jp/s3/storage-classes/)


#ストレージクラスの種類
* スタンダード
* 標準低頻度アクセス
* 1ゾーン低頻度アクセス
* 低冗長化ストレージ
* Glacier Flexible Retrieval（旧名：Glacier）
* Glacier Deep Archive
* Intelligent-Tiering

##スタンダード
* デフォルトのストレージクラス
* **3ヶ所のAZ**で冗長化
* 耐久性は 99.999999999%（通称：イレブンナイン）

##標準低頻度アクセス
* 耐久性はスタンダードと同じ
* **読み取りに対して課金**<br>⇒長期保管やバックアップ向き

##低冗長化ストレージ
* **2か所のAZ**で冗長化するため安価

##Glacier Flexible Retrieval（旧名：Glacier）
* Glacier(=氷河)は、低頻度アクセスかつ長期保存向きストレージ
* **データアクセスに時間がかかる**が、データを安価に保管できる<br>⇒アーカイブ向き

##Glacier Deep Archive
* Amazon S3 の最も低コストのストレージクラスであり、1 年のうち 1 回か 2 回しかアクセスされないようなデータを対象とした長期保存

##Intelligent-Tiering
* 低頻度・高頻度の2階層ストレージがあり、アクセス頻度によって各オブジェクトを最適なストレージ層に自動で使い分ける。<br>⇒自動でコスト最適化

#まとめ
|       ストレージクラス      |   データ読み取りの即時性        |主な用途|ユースケース|
|:-----------------|:------------------|:-------------------|:-------------------|:-------------------|
| スタンダード            |        即時        |アクセス頻度の高いデータ|コンテンツ配信、ビッグデータ分析など、幅広いユースケース|
| 標準低頻度アクセス          |      即時       |アクセス頻度は低いが、必要時にすぐにアクセスが必要なデータの長期保存| データのバックアップ等|
|1ゾーン低頻度アクセス      |        即時        | 	アクセス頻度が低く、クリティカルではないデータの長期保存|サムネイル画像、データのセカンダリバックアップ等|
|Glacier Flexible Retrieval       |        数分から数時間        |アクセス頻度が非常に低く、必要時にすぐにアクセスが基本不要なデータの長期保存|長期アーカイブ(緊急性の高いアクセスあり)|
|Glacier Deep Archive       |        12時間以内        |アクセス頻度が非常に低く、必要時にすぐにアクセスが不要なデータの長期保存|長期アーカイブ(緊急性の高いアクセスなし)|
| Intelligent-Tiering        |        即時        |アクセスパターンが予測不能または変化し、必要時にすぐにアクセスが必要なデータの長期保存|アクセスパターンが予測できないコンテンツ配信など|
php開発者がやりやすいjava開発１．(Gradle vs Maven)

新規構築をPHPでやる予定ではありますが、個人情報とか、大容量データ扱いや大容量トランザクション処理などに不安な部分があり、javaのプロジェクトをやるかも知らないと思って、プロジェクト構成だけはやって置きたいと思いました。SPAタイプの内容だったら、vue3を使う予定なので、そちらの準備も行っているところです。
チーム内の認識合わせのために、このような資料作成もやり、時間が多めにかかっていますが、後でメンバーが少しでも楽に、よく理解した上で、仕事ができれば良いかと思って頑張っています。
メンバーがlaravelは既に経験があり、javaの中で、似ているし、開発しやすい面を考慮して、spring bootを考慮しています。spring bootやjavaプロジェクトを管理する時に、良いものを考えていて、経験から見ると、やはりGradleにしたいと思っています。


# GradleとMavenの差
| 項目 | Gradle | Maven |
|:-----------|------------:|:------------:|
| 設定言語 | script(groovy)| xml|
| エラー検出力| スクリプト実行エラー | 設定ファイルの誤り |
| エラー出力内容| 行単位エラー内容出力 | プラグイン内部エラーは✕ |
| プラグイン作り| script | pom>java>compile>package>install |
| ビルド対象| 差分 | 全体 |
| ビルドキャッシュ| 入力値 | プロジェクト |
| 依存性管理| プロジェクト毎 | バージョン毎 |

>http://sassembla.github.io/Public/12:05:27%2018-03-20/12:05:27%2018-03-20.html
WSLgとFcitx5はWaylandをdisableにして使う

#### 問題

WSLg使いたい、ext4マウントしたい。とりあえずWindows11にアップグレードした。日本語（個人的には中国語も）入力したい。

…日本語入力できないんだが。ということで半日くらい調査してみたところ、

https://yanqiyu.info/2021/06/29/wslg-gpu/

上記の記事を見つけて、なぜか変換候補パネルが出ないものの、一応変換はできるところまで来たので共有しておきます。

なお、いったん動いた？時点でメモ代わりに記載しておりますので、いろいろ勘違いしているところがあるかもしれません。

##### 余談: Ubuntu 20.04 で Fcitx5 は apt パッケージが足りていません

* `fcitx5-configtool`が起動しない…。ので、ここから先は無理やり Ubuntu 21.10にアップグレードしたWSL2を触っていきます。
* リリースアップグレードの方法は下記を参照しました。

https://howtofix.io/how-do-i-install-ubuntu-2110-in-wslg-on-windows-11-id61424

ここから先の理屈は、Ubuntu以外のディストロでも通用するのでは？もっと良い方法があったら教えてください。

### Ubuntu 21.10 になったら

```
# 使えるIMの確認
$ im-config -l
 ibus xim
# あとで使う fcitx5-configtool も一緒にインストールされる
$ sudo apt install -y fcitx5-mozc fcitx5-rime daemonize
# ユーザー用 IM をfcitx5にセットする。
$ im-config -n fcitx5
$ im-config -l
 ibus fcitx5 xim
```
##### とても大事

ここでいったん `wsl --shutdown` して再度 wsl を起動してください。
再起動後はfcitx5-configtoolでいろいろ設定してみてください。

##### .bash_profile に追加

```
# ワークアラウンド：いれなくてもいい？
daemonize -e /tmp/dbus-${USER}.log -o /tmp/dbus-${USER}.log -p /tmp/dbus-${USER}.pid -l /tmp/dbus-${USER}.pid -a
/usr/bin/dbus-daemon --address="unix:path=$XDG_RUNTIME_DIR/bus" --session --nofork  >>/dev/null 2>&1
export DBUS_SESSION_BUS_ADDRESS="unix:path=$XDG_RUNTIME_DIR/bus"

# fcitx5 をwaylandプラグインをカットして起動
daemonize -e /tmp/fcitx5.log -o /tmp/fcitx5.log -p /tmp/fcitx5.pid -l /tmp/fcitx5.pid -a /usr/bin/fcitx5 --disable=wayland
export INPUT_METHOD=fcitx
export GTK_IM_MODULE=fcitx
export QT_IM_MODULE=fcitx
export XMODIFIERS=@im=fcitx
```

みそはここで Fcitx5 の Wayland プラグインをカットしてあげるところです。

この後、geditやxfce4-terminalなどでMozcとRimeで変換ができたことを確認します。

##### 最後に

この方法では、変換候補パネルが出ないほかにもいろいろ不具合があります（Addonの設定を開くと勝手に閉じるとか）。
個人的な考えから、IBusに戻してまでWSLgを使う気はないのと、調べてどうのまでする体力的余裕が無いので、機会があって判明したことがあれば追記、でなければ半年ほど放置してみたいと思います。

#### 参考文献

https://fcitx-im.org/wiki/Fcitx_5
TypeScriptにおけるオブジェクト型の宣言の話

TypeScriptといえば、便利な型定義。
コードの可読性が非常によくなる。
がその反面、型で苦労することも…

今回、TypeScriptの型指定において困ったこと/解決策を紹介します。

# やりたいこと

予め型定義してある`Person`を使って、`customers`という変数には`Personオブジェクト`の配列が、`customer`には 配列ではなく `Personオブジェクト`が単体で入る、というように宣言したい。
至ってシンプル。

```ts
customers : Person[]
customer : Person 
```

```ts:person.d.ts
interface Person {
  id: number
  name: string
  age : number
}
```

# 問題点

上記のようにすると、次のエラーが。

```
TS2564: Property 'customers' has no initializer and is not definitely assigned in the constructor.
TS2564: Property 'customer' has no initializer and is not definitely assigned in the constructor.
```
今回、`Person`はclassではなくtypeとして定義しているので、`constructor`を持っていない。
んー、初期値としてに何か入れときゃなきゃいけないか。

ということで、次のようにしてみた。

`customers`はオブジェクトの配列で、`customer`はオブジェクトそのものだから...

```ts
customers : Person[] = []
customer : Person = {}
```

すると、配列の方は問題ないが、単数の方でエラーが。

```
TS2739: Type '{}' is missing the following properties from type 'Person': id, name, age
```
id, name, age の値を指定していませんよ、と。

ええええ、初期化だけの為に全てのフィールド埋めないといけないの？？
この後すぐにAPIから正しい情報を取得するのに？？？
配列の方は不要なのに？？？？

# 思いついた方法

### ① インスタンスを作成する
```ts
customer: person = new Person()
```
これでもエラーは回避できるが、modelクラスを定義しておかないといけない。
このためだけにクラスを作るのか…?

### ② ? を使う
```ts
customer? :person 
```
このやり方だと、modelクラスも作らずエラーも表示されなくなるが、`customer`が `undifined`となる可能性を許容してしまう。
別の箇所で`customer`を使う時に面倒になりそう。

# ベストプラクティス
チーム内で相談したところ、結局これが一番良さそうとのこと

```ts
customer :Person | null = null
```
`Person`か`null`を許容するようにして、最初に`null`を入れておく。
なるほど。
個人的には、配列と同じように書けると分かりやすい気がしたが、この書き方が他に影響を与えず宣言する最善策のよう。

# おしまい
型定義、慣れてくるとと面白いし、最強に便利。
完璧に理解するぞ〜
GitHub Actionsでmake testを実行する

## やること
1.  `.github` ディレクトリを作成
2.  `.github` 配下に `workflows` ディレクトリを作成
3.  `./github/workflows` にymlファイルを作成
4. pushする

[test.yml]

```yml
name: Run Make Test
on: [push]
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - name: Run Test.
        run: make test
	# run : [実行したいコマンド]
```

後はリポジトリにpushするごとに自動で走ります。

Actions項目を見ると自動でコマンドが走っていることが確認できます。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1010179/96c52ad9-3544-f90c-896a-38f4e1d13cf1.png" width="700">

##参考
[Quickstart for GitHub Actions](https://docs.github.com/ja/actions/quickstart)
AtCoder Beginner Contest 238(A~C問題)

2月5日のAtCoder Beginner Contest 238のA、B、C問題の解説です。
実行速度の点から、pypyで実行しています。

#A - Exponential or Quadratic

特に考えずに、問題通りに解く

```
n=int(input())
if 2**n>n**2:
    print("Yes")
else:
    print("No")
```

#B - Pizza
angleにそれぞれの角度を格納する。
n回目にangle(n)度を格納すると、
それぞれの角度は、

0度
angle(n)=angle(n)
angle(n-1)=(angle(n)+angle(n-1))％360
angle(n-２)=(angle(n)+angle(n-1)＋angle(n-2))％360
　　　　　・
　　　　　・
angle(1)=(angle(n)+・・・+angle(1))%360
360度

となる。
その後これらの角度をソートし、角度の差が一番大きいものが答えである。


```
A=[]
s=[]
angle=0
N=int(input())
A=list(map(int,input().split()))
for i in range(len(A)):
    angle=angle+A[-(i+1)]
    angle=angle%360
    s.append(angle)
s.append(0)
s.append(360)
s=sorted(s)
max=0
for i in range(len(s)-1):
    if(max<(s[i+1]-s[i])):
        max=s[i+1]-s[i]
print(max)
```

#C - digitnum 
それぞれの整数の時、
n<1の時
整数1~9                 1~9
n>=1の時、
整数10~99               1~90
整数100~999             1~900
より、
整数10^n~10^(n+1)-1　 9*10^n (1)

例えば、値が123 の時、
整数1~9
整数10~99の桁数を(1)の式を用いて加算する。
その後、
100~123の部分を加算する。


```
N=int(input())
MOD =998244353
sum=0
m=len(str(N))
for k in range(0,len(str(N))-1):
    i=k+1
    if i==1:
        p=9
    else:
        p=10**(i-1)*9
    sum=(sum+(1+p)*p//2)%MOD
last=(N-10**(m-1))+1
sum=sum+((last+1)*last)//2
sum=sum%MOD
print(sum)
```

#さいごに
よければTwitterのフォローもお願いします。
twitter(https://twitter.com/NLP_tk)
ごみ箱(Recycle Bin)がAmazon AMIをサポートしたので紹介＆その注意点

![Recycle Bin.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51320/7b321d33-1497-0128-3731-535c38604359.png)


昨年、EBSのSnapShotを対象に作られたRecycle Binが、AMIもサポートするようになりました。
Recycle Binに対する、AWS公式の和訳が「ごみ箱」です。

リアルなごみ箱でも間違って大事なものを間違って捨てた場合や、あとで必要と気づいたときには、拾い出しますよね？
このごみ箱も、同じように間違って捨てた後に拾い出すことができます。
MacやWindowsのごみ箱と同じです。

個人的に注目している機能の一つで、勝手な予想（願望）ですが、今後、他にもどんどん対象が増えて、リソースの削除に対する防御線の集中管理ができるのではと期待しています。

# 手順
## Retention Ruleの作成
まずは、Retention Ruleを作っておきます。
![Screenshot at Feb 06 11-10-03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51320/68960304-0d8e-d12b-5b40-d05f1c0d0794.png)


非技術者の方でも、監査とかを対応される際に、Retention Policyとかいう言葉を聞かれたことあるかもしれませんが同じものです。
保存期間についてのルールです。一般的に、Retention Rule/Policyでは、「何を、いつまで、どのように保管する」かを決めておきます。
AWSのRecycle Binでは、現状、以下となります。

- 何を　… Snapshot？またはAMI？。特定のタグ付きのもの？または全部？
- いつまで　… 日単位で指定。１〜３６５で指定可能。
- どのように　… Retention Rule対象外。保管場所はS3固定。暗号化して保管するかはSnapshot側で指定。

## AMIの破棄
Actionから「Deregister AMI（AMIを登録解除）」をすることで、AMIは破棄されます。
このとき、Retention Ruleに合致しているものは、ごみ箱のリソースに一時保管されます。

## ごみ箱の確認と復旧

![canvas (3).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51320/c41585d2-d9be-9b07-4804-65a7eb574b6d.png)

Retention Binのコンソールから、ごみ箱のリソースに、先ほど破棄したAMIが存在していることを確認できます。
選択して、復旧ボタンを押すことで、AMIは登録解除前の状態に戻すことができます。

# 注意点
AMIのRetention Ruleは、あくまでAMIについてのみ適用されます。
そのAMIにアサインされたSnapshotには適用されません。このAMIでは、snapshotは下側のカーソルのものになります。
![canvas (2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51320/42f26e02-2252-5c7b-d9c6-2b2685098e6f.png)

したがって、AMIの登録解除のときに、snapshotを削除してしまっていたら、ごみ箱のAMIは復元できません。

![エラー.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51320/8b6d2a32-ceba-d747-9248-9f421612d8e2.png)

この件は、Retention Rule設定時にも、注意書きで案内してくれています。
![Rule重要.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51320/4a00bdcf-82ea-53eb-dcb0-eb4fb6df4b6e.png)

Recycle Bin（ごみ箱）を利用する場合は、SnapshotのRetention Ruleも合わせて設定しておくことをお勧めします :)
1日目での実施内容について

#1日目：仮想環境構築、簡単な設計、テーブル作成ツール開発、データ登録ツール開発

## 前提条件
* python=3.9.0をインストールしておくこと
* リポジトリを適宜反映させるためにGithubを用いる(企業の場合は有料でセキュリティ面が担保される。)

### 仮想環境構築について

pythonでは標準的に仮想環境構築のためのコマンドが用意されているので、それを用いてまずは簡易的に開発環境を構築する。
以下手順

#### STEP❶ターミナルやコマンドプロンプトから適当にディレクトリを作成する。
{任意のディレクトリ名}=Kadai

```
$ mkdir {任意のディレクトリ名}
$ cd {任意のディレクトリ名}
```

#### STEP❷仮想環境構築
{任意の仮想環境名}=kadai_v

```
Kadai$ python3 -m venv {任意の仮想環境名}
```

#### STEP❸仮想環境のアクティベート

```
Kadai$ source {任意の仮想環境名}/bin/activate
({任意の仮想環境名})$ python -V
```

今後開発していく際にはこのように仮想環境を構築した状態で実施します。なのでデータベースなどを作成する際には仮想環境をアクティベート状態にして行うことです。

## 簡単な設計について
> 作成データベース
-- Kadai_DB

> 作成テーブルについて
-- user_table
-- auth_table
-- task_table

> テーブル関連ツールについて
-- テーブル作成ツール(DDLを適宜実行しテーブル作成を簡略化させるため)
-- テーブルデータ登録ツール(作成したテーブルに対してCSVファイルからデータを登録できるようにするため)
-- DDL文(Create tableにより構成)
iOSのスクリーンショットでコンテンツを消す方法

# はじめに

先日、PMからiOSアプリで動画配信画面のスクリーンショットや画面録画で撮られたときに
動画コンテンツの部分をNetflixやAmazon Prime Videoみたいに黒塗りにしたいけどできるかな？と相談を受けました。

スクショ対策はAndroidは`WindowManager.LayoutParams.FLAG_SECURE`を付けておくだけで上手くやってくれるのですが、iOSは`UIApplication.userDidTakeScreenshotNotification`で撮影後にファイルを削除する（これもできるのか不明）などの情報ばかりでした。

そんな中、StackOverFlowに投稿されていた回答を試したところ**動作するOSバージョンに制限はあった**ものの期待通りの動きになったので、その検証結果の記事になります。

検証といってもそのまま試しただけですが、探しても成功事例の情報が少なかったので情報を流して、今後似たような対応をする方がいれば、その方の参考になればいいなと思います。

元ネタの回答はこちらです。
[Prevent screen capture in an iOS app](https://stackoverflow.com/a/67054892)

# 試した結果 

画面は上がUIImageView, 下がAVPlayerになっています。
実機でスクショや画面録画しても何も映らないのでgifは Simulator を画面録画したものになります。
gifはスクショだけになりますが、実機で録画時も非表示になることは確認したのでどちらのパターンも動作します。

![take_screen.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64426/c5f4f5e6-06e8-a2c9-e95c-096f7271eb71.gif)

撮影後に表示されている文字列は階層を分けて後ろに仕込んでいます。
撮影禁止処理を有効にしたUIViewの領域がまるっと非表示になります。

# 動作確認について

すぐに手元で検証できる実機が iOS15 以上だけだったので以下は Simulator で検証しました。 
**スクショの撮影は Simulator メニューの`Device` -> `Trigger Screenshot`で撮影した場合に実機と同じようになります。**

元の回答には iOS13 以降で動作するというコメントがありますが iOS13 でも動作するバージョンとそうでないバージョンはありそうなのでサポートするなら確認は必要になります。

| OSバージョン | 結果 |
| --- | --- |
| 15.x | ○    |
| 14.0 | ○    |
| 13.4 | ○    |
| 13.0 | ×    |
| 12.4 | ×    |

あと Simulator で検証していると AVPlayer で[エラーが出ていて動かない問題](https://developer.apple.com/forums/thread/667921)がありましたが、iOS13.4 は AVPlayer のエラーが出ていても機能していたので、その辺りは関係ないと判断しています。


# 実装

撮影させたくない画像や動画をUIViewの入れ子にして
そのUIViewのレイヤーに`isSecureTextEntry`を有効にしたUITextFieldを加えるという方法で実現していました。

あとは対象の領域を囲ったUIViewで`makeSecure()`を呼び出すだけです。

```.swift
import UIKit

extension UIView {
    func makeSecure() {
        DispatchQueue.main.async {
            let field = UITextField()
            field.isSecureTextEntry = true
            self.addSubview(field)
            field.translatesAutoresizingMaskIntoConstraints = false
            field.centerYAnchor.constraint(equalTo: self.centerYAnchor).isActive = true
            field.centerXAnchor.constraint(equalTo: self.centerXAnchor).isActive = true
            self.layer.superlayer?.addSublayer(field.layer)
            field.layer.sublayers?.first?.addSublayer(self.layer)
        }
    }
}
```

なぜこれが機能するのかという回答者からの問いかけにはコメントでUITextFieldの内部の`_UITextLayoutCanvasView`が表示を隠す為に機能しているということでしたが、この辺りは詳しくないのでまた時間があるときに調べてみます。


gifのプロジェクトはこちらです。
[GitHub mittsu333/SecureScreen](https://github.com/mittsu333/SecureScreen)

# 注意点： 実装の弊害

OSバージョンで動作する・しない以外にもUITextFieldをレイヤーに差し込むことで**画面の作りによっては思わぬ弊害を生む可能性もあると思います。**

動画プレイヤーなどでレイヤー周りを操作している場合や、既存で配置している他のUITextFieldの動きがおかしくなる可能性もありますので、導入する際の検証はしっかり行った方が良いと思います。

# おわりに

最初に実装方法だけみてなるほどと思いつつ、すごい解決方法だな（回答者の方も悩んだのかな）という印象でしたが、要件を満たせる上に実装も単純なので助けられました。
【JS】ランダムシャッフルした配列を格納した多次元配列を作る

いきなりですが問題です。

以下のような処理を実装する際、どんな風に実装しますか？
・A,B,C,Dという文字列を含む配列を含む多次元配列を作る
・多次元配列中の二次元配列要素(ABCD)の順序は、1次元要素ことにバラバラである

### やりがちなパターン
コードで書くと、以下のような感じで書く方が多いんじゃないでしょうか。

```js
const list = [1, 2, 3, 4];
const result = [];

for (let i=0; i < 10; i++) {
    const item = list.sort(() => 0.5 - Math.random());
    result.push(item);
}
console.log(result);
```

しかし、実際にやってみると、これでは冒頭の条件を満たせていません。

```js
// 以下、上記コードを実行した結果
(10) [Array(4), Array(4), Array(4), Array(4), Array(4), Array(4), Array(4), Array(4), Array(4), Array(4)]
0: (4) [4, 2, 3, 1]
1: (4) [4, 2, 3, 1]
2: (4) [4, 2, 3, 1]
3: (4) [4, 2, 3, 1]
4: (4) [4, 2, 3, 1]
// 以下略
```
pushした配列の二次元配列の順序が、同じになってしまっています。
itemをconsole.logで出力するとわかりますが、ループごとでランダムシャッフルされています。

### 正解

```js
const list = [1, 2, 3, 4];
const result = [];

for (let i=0; i < 10; i++) {
    const item = list.sort(() => 0.5 - Math.random());
    result.push(item.concat());
}
console.log(result);
```
↑のようにpush時にconcat()を追加することで1配列要素ごとに内部の要素がバラバラば配列を作ることができます。

```js
(10) [Array(4), Array(4), Array(4), Array(4), Array(4), Array(4), Array(4), Array(4), Array(4), Array(4)]
0: (4) [4, 2, 1, 3]
1: (4) [3, 1, 2, 4]
2: (4) [4, 2, 1, 3]
3: (4) [4, 2, 1, 3]
4: (4) [3, 4, 2, 1]
```

なぜconcat()を足す必要があるのかというと、pushメソッドでは配列は参照渡しで要素が追加されるからです。

### pushメソッドの参照渡しについて
参照渡しとは「関数へ変数の値を記憶しているメモリ領域を渡す」ということです。
これに対して値渡し(関数へ変数の値を渡し、変数の記憶領域はそのまま)というのがあります。

参照渡しについてご存知の方はこのまま読み進めてもらうとして、
分かりやすく示したgifがvue3リファレンスページにあったので、よく分からないという方はイメージを掴むためにチェックするといいかも↓
[Vu3リファレンス:ref によるリアクティブな変数](https://v3.ja.vuejs.org/guide/composition-api-introduction.html#setup-%E3%82%B3%E3%83%B3%E3%83%9B%E3%82%9A%E3%83%BC%E3%83%8D%E3%83%B3%E3%83%88%E3%82%AA%E3%83%95%E3%82%9A%E3%82%B7%E3%83%A7%E3%83%B3)

push()が参照渡しであるということは、
forループで**毎回個別に作成していたつもりだった配列(item)は、list内に追加済の配列要素でもある**という状態だっため、
[新しい配列を返却するconcat()](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/concat)を使ってあげる必要があるのでした。


#### 参照渡し・値渡しになるかは引数の型次第
配列の他にも、`Object,クラス`をpushに渡した場合も参照渡しになります。
こちらも必要に応じて新しいObject,インスタンスをpush()に渡すなどの対応をするようにしましょう。

#### 参考

https://www.delftstack.com/ja/howto/javascript/javascript-pass-by-reference/#javascript-%25E3%2581%25AE%25E9%259D%259E%25E3%2583%2597%25E3%2583%25AA%25E3%2583%259F%25E3%2583%2586%25E3%2582%25A3%25E3%2583%2596%25E5%2580%25A4%25E3%2581%25AF%25E5%258F%2582%25E7%2585%25A7%25E3%2581%25AB%25E3%2582%2588%25E3%2581%25A3%25E3%2581%25A6%25E6%25B8%25A1%25E3%2581%2595%25E3%2582%258C%25E3%2582%258B