OmniAICreator/Qiita-1.07M huggingface dataset:
S3にあるPDFを取得してZIPにする

# 要件 : S3にあるPDFを取得してZIPにする

利用するライブラリ
- フェッチ処理 : [Axios](https://axios-http.com/)
- ファイル圧縮 : [Archiver](https://www.archiverjs.com/)
- S3からPDFのオブジェクト取得 : [AWS-SDK for javascript](https://docs.aws.amazon.com/ja_jp/sdk-for-javascript/index.html)


  ### アップロードのシーケンス(処理手順)

```mermaid
  sequenceDiagram
    participant フロント
    participant バックエンド(例 download.ts)
    participant S3

    フロント->>バックエンド(例 download.ts): ①ZIPダウンロードのリクエスト

    par ②PDF取得
        バックエンド(例 download.ts)->>S3: S3.getObject()
       S3 ->>バックエンド(例 download.ts): データ
    end
    par ③zip圧縮
        バックエンド(例 download.ts)->バックエンド(例 download.ts): 
    end
    
    バックエンド(例 download.ts)->>フロント: ④ZIPしたデータをレスポンス
```

#### ①ZIPダウンロードのリクエスト
- 取得したzipファイルをダウロードするために
    - aタグに`href属性`と`download属性`を追加してクリックする
```typescript: フロント
import axios from 'axios'

const download = () => {
    const { data }: any = await axios.get("http://localhost:8000/archive", {
        responseType: "arraybuffer",
    })

    // blobの作成
    const blob = new Blob([data], { type: "application/zip" });
    // URLの作成
    const url = window.URL.createObjectURL(blob);
    // aタグの作成
    const link = document.createElement("a");

    // urlの追加
    link.href = url;
    // download属性を付与, ファイル名も指定
    link.setAttribute("download", "ダウンロード.zip");
    // aタグをクリックしてダウンロード
    link.click();
    // urlの削除
    link.parentNode?.removeChild;
}
```

### ②PDF取得、③zip圧縮
AWS : [Amazon S3 オブジェクトに対する操作の実行](https://docs.aws.amazon.com/ja_jp/sdk-for-java/v1/developer-guide/examples-s3-objects.html)

- S3のgetObjectメソッドを利用してPDFデータ(Buffer)を取得
    - BufferをStreamにする
- archiverを利用してzip化させる
    - `response`にzip化した`archive`を`pipe`する
    - `stream`を`append`メソッドで`archive`に追加
        - `.pdf`の指定はappendメソッドの第二引数で行う
        - `/sample1`はディレクトリとなる
```typescript: バックエンド(download.ts)
import AWS from 'aws-sdk'
import * as archiver from 'archiver'

const S3 = new AWS.S3({'region':'region'});

// ダウンロード、zip化
const download = (request, response) => {
    // ②PDF取得
    const stream = S3.getObject(
        {
          Bucket:'test',
          Key:'hoge/huga.pdf'
        }).createReadStream()

    // ③zip圧縮
    const archive = archiver('zip')
    // レスポンスにarchiveを繋げる
    archive.pipe(response)
    // ファイルを追加
    archive.append(stream, '/sample1/test.pdf')
    // zipにする
    archive.finalize()

    // 一応、ヘッダーのContent-Typeを指定しておく
    return response.header('Content-Type', 'application/zip')
}

```


- 関連ワード
    - http://var.blog.jp/archives/62330155.html
    - [Stream](https://qiita.com/kosuke-17/items/4f44503d937d9ba1d583)
    - [ArrayBuffer](https://qiita.com/kosuke-17/items/a75a890ecff523f87bc8)
    - [Blob](https://qiita.com/kosuke-17/items/f8abbb89cb0ea7b93b9c)
AWSでMFAの設定

AWSでMFAの設定をする備忘録的なものとして残しておきます。

AWSログイン後 IAMを選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2781615/1ebe9d33-5719-6eee-545b-637a734bdffa.png)

MFAを追加を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2781615/02d63b5d-0b0f-c579-b1c4-da597c05ec93.png)

MFAを有効化を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2781615/7265cbc6-4d18-81ab-fc33-a3d42ddae90e.png)

以降各自設定したに要素認証アカウントに合わせて設定する
本番環境でBootstrapが反映されない時に解決した方法

## デプロイはできたが…
本番環境にデプロイすることはできたが、Bootstrapだけが反映されてない、、という不具合をなんとか解消できた話です。

## 原因
恐らく、Bootstrapの最新版を使っていたための不具合でした。

## なぜ最新版だと不具合が生じるの？？
色々なものが日々アップデートされていますが、それらは全ての環境下で挙動を確認されているか、というとそうではないからです。
そのため、最新版を使っていればいい、というものではなく常にその時の安定版というものがありますので安定版を使うようにしましょう。

## 公式ドキュメントには…

公式ドキュメントには、Bootstrap5.2.0（最新）が安定版となりました！というブログが掲載されています。
これで動くはずだ！と思ってしまいますが、先輩エンジニアさんの方々の意見をしっかり聞くようにしましょう😭

https://blog.getbootstrap.com/

![スクリーンショット 2022-08-11 11.10.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2759696/f250e8c0-c1d9-e99e-6b0b-a0f9d1b4791b.png)


## 私が最新版を使ってしまっていた原因
では、どうしたら最新版を使わずに済むかという話ですが、私が最新版を使ってしまっていた原因は、バージョンの指定なしでインストールしていたからです。
つまり、、、
```
username:~/environment/"アプリ名" $ yarn add bootstrap
```
このように導入していたんです。
（yarnでのインストールを選びました。他にも色々あります。）

## バージョンを落とそう
どうやってバージョンを落とすか、という話ですが、もう一度yarnで入れ直せばOKです。
以下のコマンドでバージョンの指定をしてインストールすることができます。
```
username:~/environment/"アプリ名" $ yarn add bootstrap@5.1.3
```
### バージョンの確認
入れ直しが完了したら、ターミナル上にバージョンが表示されるはずですが、「しっかりバージョン落とせたかな？」と心配になる方や途中で「あれ？何使ってたっけ？」と忘れてしまう方もいると思います。
そんな時は、アプリ直下にあるpackage.jsonを見てみるとバージョンを確認できますよ！！
```ruby
#こんな感じ
{
  "name": "アプリ名",
  "private": true,
  "dependencies": {
    #割愛〜
    "bootstrap": "5.1.3",
    #割愛〜
```
しっかりバージョン落とせてますね！！
## 本番環境に反映する方法
#### ①githubにpushする
開発環境でバージョンを落とせたことを確認したら、いつものようにpushしてください。

#### ②pullする
本番環境にpullしてくれば反映されているはずです。

## まとめ
スクールのメンターさんを頼れた時は意識していなかった問題にぶち当たり2日間ほど時間がかかってしまいました😱
色々便利なものを使うにしてもしっかりバージョンを確認しようと反省しました。
Linux リダイレクトについて（自分用メモ

シェルは標準入力、標準出力および標準エラー出力の3つのストリームを制御することができます。

デフォルトで標準入力の入力元はキーボード、標準出力と標準エラー出力（エラーメッセージ）の出力先はディスプレイ。

●リダイレクト
入力元や出力先を変更できます。リダイレクトを使うには「>」や「<」などのリダイレクト演算子と、ファイルディスクリプタを組合せた記号を用います。0と1のファイルディスクリプタは省略可能です。

記号
・< 標準入力の入力元を指定（0<と同義）
・<< 標準入力の入力元を指定し、終了文字まで入力（0<<と同義）
・> 標準出力の出力先を指定（1>と同義）
・>> 標準出力の出力先を指定し、出力先に追記（1>>と同義）
・2> 標準エラー出力の出力先を指定
・2>>標準エラー出力の出力先を指定し、出力先に追記
・>&2 標準出力の出力先を標準エラー出力の出力先と同じにする（1>&2と同義）
・2>&1 標準エラー出力の出力先を標準出力の出力先と同じにする

※「>(1>)」
指定したファイルが存在しない場合はファイルが新規作成されますが、指定したファイルが既に存在する場合は「>」「1>」はファイルを上書きします。

※「>」「>>」「2>」「2>>」
指定したファイルが存在しない場合はどちらもファイルが新規作成されますが、指定したファイルが既に存在する場合は「>」、「2>」はファイルを上書きし、「>>」、「2>>」はファイルの最後尾に追記


●標準出力に出力されたコマンドの実行結果を、別のコマンドの標準入力に渡すにはパイプ(|)を利用

●trコマンドは変換対象を標準入力からのみ受け付けます。つまり、変換・削除したい文字列が記載されているファイルをコマンドの引数として指定することが出来ません。そのため、設問のようにリダイレクト(<)を使用してtrの標準入力にファイルの内容を渡す。

●catコマンドの引数にファイルを複数指定すると、ファイルを連結して出力します。ファイル名が指定されない場合、または「-（ハイフン）」が指定された場合は標準入力から受け取ったデータを標準出力に表示。
入力ファイルを引数に指定しない場合は、キーボード(デフォルトの標準入力元)から入力した内容を、エンターキーを押すたびに標準出力に出力。

※catコマンドはファイルを引数に指定しない場合は、標準入力(デフォルトはキーボード)からの入力をエンターキーを押すたびに標準出力に出力します。catコマンドを終了するにはCtrl+cキーなどを使用

●teeコマンド
標準入力の内容を、まさにTの字のように、標準出力先（デフォルトはディスプレイ）とファイルの双方に出力するコマンド。

コマンド | tee [-a] ファイル

ファイルに追記する場合は「-a」オプションを使用します。
teeコマンドは通常、パイプ(|)と共に使用。パイプを使用して、コマンドの標準出力をteeコマンドの標準入力に渡します。


●dmesgコマンド
起動時に出力されたメッセージを表示する。出力内容が多いので、そのまま出力すると内容が把握しきれない場合があります。lessコマンドに出力内容を送ればページごとに確認できます。


●コマンドが出力する全てのメッセージを破棄したい（ディスプレイに表示させたくない）

コマンド > /dev/null 2>&1

「/dev/null」は入力された全てのデータを消すという特殊なファイル


●標準入力から渡された文字列を、指定のコマンドの引数として実行するコマンドはxargsです。

xargsコマンドの標準入力に文字列を渡すと、xargsコマンドで指定したコマンドがそれらの文字列を引数として実行されます
Herokuで複数環境にデプロイする


基本の進め方はこちらの記事を参考にさせていただきました。

https://qiita.com/vossibop/items/8f70000927a2adcc2911

https://casualdevelopers.com/tech-tips/how-to-make-both-staging-and-production-environments-and-deploy-to-both/



少し詰まった点としては、



```
 heroku config:add DATABASE_URL='mysql2://.....'
```

する前に一度`git push heroku master`してデプロイする必要があったこと



二つ目以降の環境を作るときは全てのherokuコマンドの最後に`--remote staging (production環境だったらproduction) `を付け加える必要があること
Elasticsearchクラスタ検証(3): Elasticsearch 8.xのクラスタ化(HTTPS未対応)

##### [前回] [Elasticsearchクラスタ検証(2): Elasticsearch 8.xを導入](https://qiita.com/mingchun_zhao/items/9de73d39aad82b78cf3e)

## はじめに

今回は、3ノードのElasticsearchクラスタを設定します。

- node1: `AlmaLinux8-1`
- node2: `AlmaLinux8-2`
- node3: `AlmaLinux8-3`

## node1で以下実施(管理者権限)

### ファイアウォール設定

- ノード間通信を可能にするため、ポート9200、9300へのアクセス許可

```shell
# firewall-cmd --add-port={9200,9300}/tcp --zone=public --permanent
# firewall-cmd --reload
# firewall-cmd --list-port
9200/tcp 9300/tcp
```

### `/etc/hosts`に3ノードのIPアドレスを追加

```/etc/hosts
172.21.192.11 node1
172.21.192.12 node2
172.21.192.13 node3
```

### Elasticsearchのデータディレクトリを削除

- Elasticsearchが既にシングルノードのクラスタで開始されたため、停止しデータディレクトリを削除

```shell
# systemctl stop elasticsearch
# rm -rf /var/lib/elasticsearch/*
```

### Elasticsearch設定ファイルを変更

`/etc/elasticsearch/elasticsearch.yml`で下記項目を設定し保存

- クラスタ名
    - cluster.name: mycluster
- クラスタ参加ノード
    - discovery.seed_hosts: ["node1", "node2", "node3"]
- Elasticsearchサービスに他のノードからアクセス可能に
    - network.host: 0.0.0.0
- セキュリティ機能を一旦無効に
    - xpack.security.enabled: false
    - xpack.security.enrollment.enabled: false
    - ※ クラスタ検証に集中するためで、実運用では有効にすべき
        - セキュリティ機能は重要であり、別途取り上げる予定です

### Elasticsearchを起動しステータス確認

```shell
# systemctl start elasticsearch
# curl -q http://localhost:9200
{
  "name" : "node1",
  "cluster_name" : "mycluster",
  "cluster_uuid" : "1ry3LhAFRWCpBk2oGtowZA",
  "version" : {
    "number" : "8.3.3",
    "build_flavor" : "default",
    "build_type" : "rpm",
    "build_hash" : "801fed82df74dbe537f89b71b098ccaff88d2c56",
    "build_date" : "2022-07-23T19:30:09.227964828Z",
    "build_snapshot" : false,
    "lucene_version" : "9.2.0",
    "minimum_wire_compatibility_version" : "7.17.0",
    "minimum_index_compatibility_version" : "7.0.0"
  },
  "tagline" : "You Know, for Search"
}
```

## node2でも上記と同じ手順を実施

## node3でも上記と同じ手順を実施

## いずれかのノードで、クラスタのステータスを確認

```shell
# curl -q http://localhost:9200/_cat/nodes?v
ip            heap.percent ram.percent cpu load_1m load_5m load_15m node.role   master name
172.21.192.12           23          96   4    0.24    0.20     0.08 cdfhilmrstw *      node2
172.21.192.13           18          93   3    0.19    0.17     0.08 cdfhilmrstw -      node3
172.21.192.11           20          96   4    0.11    0.10     0.03 cdfhilmrstw -      node1
```

期待とおり、クラスタにノードが三つ存在し、masterはnode1となっています。

## おわりに

3ノードのElasticsearchクラスタを構築できました。
次回も続きます。お楽しみに。

##### [次回] [Elasticsearchクラスタ検証(4): Elasticsearch 8.xのクラスタ化(HTTPS対応)](https://qiita.com/mingchun_zhao/items/05dd4ed7197bd2e27d6e)
Salesforceのダッシュボード登録上限について調べてみた

Salesforceについてダッシュボードの登録という機能がございます

今回はこの登録機能の上限について調べてみました

![登録01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/ee0e37a7-b14a-1f92-04b2-68411518b478.png)


###組織ごとのダッシュボード登録上限について

## ダッシュボードの登録上限数について
後述するようにダッシュボード登録数は
・Salesforceユーザ数
の数で決まります。
なので　組織あたりに登録できるダッシュボード数は、
最大で [ ユーザ数 × 7(1ユーザが登録できる最大ダッシュボード数) ] となります


## ユーザごとの上限について　詳細
1ユーザには最大７つまでしかダッシュボードの登録を行うことができません
もしも７つ以上のダッシュボードを登録すると、以下のようなエラーが発生します

![ダッシュボードエラー.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/5376d48b-4bd2-caf6-5c4c-8f85e96b4ab1.png)

エラーメッセージ：
すべての登録が使用されています
このダッシュボードを登録するには、最初に別のダッシュボードを登録解除してください。


なお、現在（2022年8月現在）はSalesforceヘルプ上では
「各ユーザは最大 5 つのダッシュボードの登録を設定できます。」
と書いてありますがこちらは過去の内容をそのまま記載しているだけのようです。
現状の動作としては、１ユーザあたり最大７つの登録が可能です

ヘルプ
レポートおよびダッシュボードの制限、制約、および割り当て
https://help.salesforce.com/s/articleView?id=sf.rd_reports_dashboards_limits.htm&type=5

![ダッシュボード登録上限.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/79bc0b9e-c6a6-295e-7a73-737e70574e0c.png)

## その他の注意点～組織で1時間あたりに登録できるダッシュボード数は500個まで

その他のダッシュボード登録上限として組織で1時間あたりに登録できるダッシュボード数は500個までがあります

===ヘルプより抜粋====
各 Salesforce 組織は、特定の曜日の特定の時間 (月曜日の午前 9:00 など) に最大 500 件のダッシュボード登録
と 500 件のレポート登録をスケジュールできます。
==ここまで==


これは最低でも組織のダッシュボード登録可能なユーザ数が72ユーザ以上（72×7＝504）の環境の場合注意が必要ですね


# まとめ
・　ユーザには最大７つまでダッシュボードの登録可能
・　よって組織あたりに登録できるダッシュボード数は、
最大で [ ユーザ数 × 7(1ユーザが登録できる最大ダッシュボード数) ] 
・組織で1時間あたりに登録できるダッシュボード数は500個まで
Ubuntu22.04 nginx最新の安定版をインストールする

## 概要
2022/08/11現在最新の安定版のバージョンは1.22.0ですが、リポジトリ追加していないUbuntu22.04でsudo apt install nginxを実行すると1.18.0がインストールされてしまいます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2744334/a72d6771-53d2-f8aa-43f0-6630f02167f8.png)
そのため、[nginx公式の方法](https://nginx.org/en/linux_packages.html#Ubuntu)で最新の安定版のnginx1.22.0をインストールしていきます。

## 手順1 nginxインストールに必要なパッケージをインストール
curl、gnupg2、ca-certificates、lsb-release、ubuntu-keyringをインストールします。
```
$ sudo apt install curl gnupg2 ca-certificates lsb-release ubuntu-keyring
```

## 手順2 nginxの署名鍵を取得して確認
sudo apt update実行時にnginxパッケージの信頼性を検証できるように、nginx公式で公開されている署名鍵を取得します。
```
$ curl https://nginx.org/keys/nginx_signing.key | gpg --dearmor \
    | sudo tee /usr/share/keyrings/nginx-archive-keyring.gpg >/dev/null
```
署名鍵の確認をします。
```
$ gpg --dry-run --quiet --import --import-options import-show /usr/share/keyrings/nginx-archive-keyring.gpg
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2744334/823614df-5922-76f9-bec6-f1e7f45ea8e8.png)
573BFD6B3D8FBC641079A6ABABF5BD827BD9BF62ならOKです。

## 手順3 リポジトリの追加
sudo apt install nginxの実行で最新の安定版がインストールされるように、リポジトリを追加します。
```
$ echo "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] \
http://nginx.org/packages/ubuntu `lsb_release -cs` nginx" \
    | sudo tee /etc/apt/sources.list.d/nginx.list
```

## 手順4 インストール
パッケージ一覧を更新してインストールします。
```
$ sudo apt update
$ sudo apt install nginx
```

## 手順5 起動と確認
```
$ sudo systemctl start nginx
$ sudo systemctl status nginx
$ nginx -v
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2744334/ab7ac2b2-92c7-f0e5-d54f-1866812cdac7.png)
1.22.0がインストールできました。
LPIC Lv1-101　仮想化のゲストOS付近についてまとめてみた

# はじめに
LPIC Lv1-101　仮想化のゲストOS付近についてまとめてみた

# 最終更新日
2022年08月11日

# 環境の情報
OS
Ubuntu20.04

# 注意
最新の状態を確認して下さい。

# 公式さま
https://www.lpi.org

# 参考さま
https://mondai.ping-t.com/

https://info.securesamba.com/term/uuid/#:~:text=UUID%E3%81%A8%E3%81%AF%E3%80%81%E2%80%9DUniversally%20Unique,%E7%99%BB%E9%8C%B2%E3%81%99%E3%82%8B%E5%BF%85%E8%A6%81%E3%82%82%E3%81%82%E3%82%8A%E3%81%BE%E3%81%9B%E3%82%93%E3%80%82

https://access.redhat.com/documentation/ja-jp/red_hat_enterprise_linux/6/html/resource_management_guide/ch01

https://www.docker.com/

https://linuxcontainers.org/ja/



# コンテナ型の仮想化のソフトウェア

Docker
LXC


# コンテナ型の仮想化の特徴

・オーバーヘッド（さまざまな処理や負荷や時間のこと）が少ない。
・リソース・構築・管理の面がシンプルである。
・Linuxのカーネルの機能によって、
コンテナごとのユーザ管理やリソース制限ができる。



# cloud-init 

・ ソフトウェアパッケージ。
・システムが動く時に
クラウドインスタンスの初期化を自動化する。



# ハイパーバイザー型
・仮想化の種類の1つ。
・物理マシンで動く、ハイパーバイザー（仮想化のための専用のOS）の上で、直接仮想マシンを動かして、ゲストOSを動かす。



# UUID
・Universally Unique IDentifier
・文字列。
インターネットの上のオブジェクトを識別するためにある。


# SaaS
Software as a Service
・クラウドサービスを作り方によって、
分けた呼び名のうちの1つ。
・ソフトウエアをサービスとして提供する。
・ユーザはインフラも開発環境も意識することなく、単純にソフトウェアを使うことが出来る。
・準備がかさむことがある。



# 重複してはならない

・1つの仮想化ソフトウェアの上で
同じ仮想マシンのクローンをいくつか動かしたい場合、重複してはならないもの。

UUID
IPアドレス
SSHホスト鍵
マシンID
electron-builderでbuildするとき

忘れないために
```json
{
  "name": "app",
  "version": "1.0.0",
  "description": "my first desktop app",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "electron-builder build --win portable"
  },
  "build":{
    "files":[
      "./index.js",
      "./index.html",
      "./test.js",
      "./node_modules/**/*",
      "./package.json"
    ]
  },
  "author": "",
  "license": "ISC",

  "devDependencies": {
    "electron-builder": "^23.3.3"
  }
}
```

の中の
```json
  "build":{
    "files":[
      "./index.js",
      "./index.html",
      "./test.js",
      "./node_modules/**/*",
      "./package.json"
    ]
  },
```
ビルドするファイルを指定しないとダメ
忘れるとファイルが読み込めない。
git  main(自分のいるbranch)以外のbranchを全削除



## main・develop以外の「mainにマージ済み」のローカル・リモートブランチ削除
~~~zsh
git checkout main
git branch -r --merged main | grep -vE "develop|main" | cut -d "/" -f2- | xargs -t -I{} git push --delete origin {}
git branch --merged|egrep -v '\*|develop|main'|xargs git branch -d
~~~

# ローカルブランチ
## main以外のローカルブランチ削除
~~~zsh
git checkout main
git branch | xargs git branch -D
~~~
## mainとdevelop以外のローカルブランチ削除
~~~zsh
git branch --merged|egrep -v '\*|develop|main'|xargs git branch -d
~~~
# リモートブランチ

## fetch前になくなったリモートブランチの削除
~~~zsh
git fetch --prune
または
git fetch -p
~~~

## mainにマージ済みのリモートブランチ全削除
~~~zsh
git branch -r --merged main | cut -d "/" -f2- | xargs -t -I{} git push --delete origin {}
~~~
## mainにマージ済みのリモートブランチでdevelop(mainも)だけ避けて全削除
~~~zsh
git branch -r --merged main | grep -vE "develop|main" | cut -d "/" -f2- | xargs -t -I{} git push --delete origin {}
~~~

参考
- [【git】リモートブランチを一括で削除するコマンドを発見](https://nana-engineer.com/deleteremote/)
- [Gitでマージ済みブランチを一括削除](https://qiita.com/hajimeni/items/73d2155fc59e152630c4)
- [Git マージ済みのブランチを一括削除する](https://qiita.com/ucan-lab/items/97c53a1a929d2858275b)
- [【git】ローカルにある不要なブランチを一括で削除](https://zenn.dev/yumiyoshi/scraps/363a710df362b8)
- [不要なリモートブランチを一気に削除するコマンドのgit fetch –pruneはVSCodeでも実行可能](https://amateur-engineer.com/git-fetch-prune/)
【ASP.NET Core MVC】URLにパラメータを指定してもコントローラー側で値を取得できない

## 環境
ASP.NET MVC
.NET Core 3.1

## 概況
ASP.NETを勉強し始めたばかり(web系も初めて)の初心者です。
備忘録のために残しています。

## 状況
ルーティングは以下の通りでした。(デフォルトのまま)

```c#:startup.cs
app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllerRoute(
                    name: "default",
                    pattern: "{controller=Home}/{action=Index}/{id?}");
            });
```


パラメータが受け取れなかったStudentControllerのIndexは以下の通りです。

```c#:StudentController.cs
public ActionResult Index(int biPage)
{       
    //中身は省略
    return View();
}
```

## 原因
Indexメソッドの引数をルーティングで指定した「id」という名前にしていなかったからでした。
(ページを指定していたのでbiPageという名前にしていた。)

引数の数が合っていれば名前は変更しても大丈夫だと思い込んでいたので、
かなり悩んで時間を使ってしまいました。。。
STM32G031とOLED、秋月の0.96 128x64(OLED)で12345678を表示(16x24)(HAL)


x 過去ログを見よ
x PA_0をOBでGPIOに出来る人むけ
x STM32G031は、秋月で売っているSTM32G031J6M6の事
x SMALL_HAL_SSD1308_128x64_I2Cのライブラリを入れてください。


目的
OLEDのテスト

秋月の0.96 128x64(OLED) P-15870


![o_con647.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/92ca6e00-080b-c453-41a9-aaaaf2bd442b.jpeg)


![o_con648.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/ddcfa80d-8a7b-d2e4-e038-a021ca715af8.jpeg)


![o_con649.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/a291b1ed-495d-dc0c-6c20-f5cc2f5587d7.jpeg)



改造元


https://os.mbed.com/users/wim/code/SSD1308_128x64_I2C/


忙しい人よう


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




```c++



//HAL_oled_16x24_031_1


#include "mbed.h"
#include "SSD1308.h"


int main() {

    __HAL_RCC_GPIOA_CLK_ENABLE();

    GPIO_InitTypeDef GPIO_InitStruct = {0};

    GPIO_InitStruct.Pin = GPIO_PIN_11|GPIO_PIN_12;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    GPIO_InitStruct.Alternate = GPIO_AF6_I2C2;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = GPIO_PIN_0;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);


    __HAL_RCC_I2C2_CLK_ENABLE();

    I2C_HandleTypeDef hi2c2;

    hi2c2.Instance = I2C2;
    hi2c2.Init.Timing = 0x10707DBC;
    hi2c2.Init.OwnAddress1 = 0;
    hi2c2.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
    hi2c2.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
    hi2c2.Init.OwnAddress2 = 0;
    hi2c2.Init.OwnAddress2Masks = I2C_OA2_NOMASK;
    hi2c2.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
    hi2c2.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
    HAL_I2C_Init(&hi2c2);    

    HAL_I2CEx_ConfigAnalogFilter(&hi2c2, I2C_ANALOGFILTER_ENABLE);

    HAL_I2CEx_ConfigDigitalFilter(&hi2c2, 0);


HAL_Delay(200);


    SSD1308 oled = SSD1308( &hi2c2 , SSD1308_SA0);


    //char n1_8[] = "12345678";
    char n1_8[] = "87654321";
    //char n1_8[] =   "88888888";

    int ii=0;
    for(int nn=0; nn<8; nn++) {
        //                y   x
        oled.writeBigChar(0, ii*16,n1_8[nn]);
        ii = ii + 1;
    } //for

    while(1) {

         HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_SET);
         HAL_Delay(200);

         HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_RESET);
         HAL_Delay(200);
      
    }//while

}//main




```
夏休み中の(若い)プログラマーのみなさんにぜひオススメしたい(古めの)映画

# π(1998)
タイトルは3.14から続いていくあの数字のこと。株価予測のプログラム作りに没頭する青年が、数字の魔力に取り憑かれ、狂気の世界に足を踏み入れていく、といった内容です。エーメンブレイクを使ったテーマ音楽が興奮を誘います。内容は相当イカれてます。まず、トレーラーを見て、合わないと思ったら視聴はやめておくのが無難です。プログラムコードに美を見出すような人間の頭の中を覗いてみたい、と思うような人にはオススメです。

こういうものを面白がって見れる人と、ただただ嫌悪感しか感じない、というような人に人間は二分されるような気がします。私はもちろん前者です。

テレビドラマの歴史に名を刻んだ「ブレイキングバッド」(2008-2013)のヘクター・サラマンカ役でキレた演技を見せていたマーク・マーゴリスという役者さんが、主人公の碁友だちの役で出てますね。私あの役者さん好きなんですよ。映画をたくさん観ているとこういうことがあるから楽しいですよね。昔の友達に人混みの中で偶然再会した時のような。


＊公開当時、渋谷のあちこちの路上にπのペインティングが出現する騒ぎがあって、けっこう話題になりました。もう覚えている人いないかな。

# GHOST IN THE SHELL 攻殻機動隊(1995)
アニメです。これを観ていない人はあまりいないと思いますが、万が一そんな人がいたら可哀想、と思ったので紹介します。(最近「スターウォーズ」を観たことがない、という可哀想な人に会って驚いたので)。

海外での人気がすごいです。日本の精神性と先端のテクノロジーの融合に彼らが感動したのはよく理解できます。「スゲえなあ日本人って」かつてそんな時代があったんですよ。

# 七人の侍(1954)
1954年といえば、第二次世界大戦で日本がボコボコに負けてからたった9年後のことです。ストーリーは、汗水垂らして作った農作物を、役所に税金で取られた上に、盗賊たちに略奪されて苦しんでいる農民が、生きるか死ぬかをかけて、サムライを雇って立ち向かうというもの。愛、勇気、善意、友情、ユーモア。よくできたシナリオはハリウッドでもリメイクされました。優れたリーダーの元に気概を持ったプロたちが集まれば、数で上回る悪党を相手にしてもひけを取ることはない。その物語そのままに、黒澤明という天才の元に集まった、俳優、スタッフたちが作り上げたこの作品は、世界中の人々に愛されることになりました。
*古い映画ですので、今では禁止されている差別用語が遠慮なく出てきます。ご了承の上、鑑賞してください。

# チャッピー(2015)
兵器を作っている企業のエンジニアが作り出した知能を持ったロボットの話。創造主から命を吹き込まれたAIが世界について学んでいく過程がとても面白く惹きつけられます。ロボットは街のワルどもの手に渡ってしまうんですが、子供のように何でも吸収してしまうこのロボットがワルに染まっていくというところが、すっごい面白い。やがて愛、怒り、嘆きといった感情が彼の心に宿る、それがストーリーとリンクしていく様はまさに白眉。
監督は南アフリカのニール・ブロムカンプという人で「第９地区」(2009)で注目を集めました。彼の起用する役者は地元の南アフリカの人たちが多く、みんな英語がナマっている、アレがいいんですよね。この作品の後、ハリウッドでの企画がコケたりして、大きな作品から遠ざかっているようで少し心配です。

# ブレードランナー(1982)
人造人間は愛を理解するのか？　という映画。少し前にこの映画をネタに記事を書きました。

https://qiita.com/tnar-f/items/3d0d53f4b409b5b02153

笑ってもらえるかな、と思って書いたんですけどね。意外とそういう反応は少なかったです。

プログラマーは技術だけでなく、知性を身につけるべきだと私は思っています。知性を身につけるには、よい映画をたくさん観て、よい本をたくさん読んで、よい音楽をたくさん聴くこと。

スティーブ・ジョブズはiPodのことを”Device for heart”と呼びました。ここで私が知性と呼んでいるものは、そのハートのことです。

この記事が、これからみなさんが面白いものを見つけていくきっかけになってくれればうれしいです。
大規模データ、MLワークロードのオーケストレーション：ワークスペースで10,000のジョブを作成、管理

[How to Orchestrate Data and ML Workloads at Scale \- The Databricks Blog](https://www.databricks.com/blog/2022/08/10/orchestrating-data-and-ml-workloads-at-scale-create-and-manage-up-to-10k-jobs-per-workspace.html)の翻訳です。

:::note warn
本書は抄訳であり内容の正確性を保証するものではありません。正確な内容に関しては原文を参照ください。
:::

[Databricksワークフロー](https://qiita.com/taka_yayoi/items/871bf30f6edf00d3ee1e)は、データ、分析、AIのための完全マネージドのオーケストレーターです。本日、最も需要のあるデータとML/AIのワークロードを容易にクラウドに導入できるようにする幾つかのエンハンスメントを発表できることを嬉しく思っています。

ワークフローは、主要な複数のクラウドプロバイダー: GCP、AWS、Azureに対して高い信頼性を提供します。これまでは、Databricksワークスペースで管理できるジョブの数は1000(これはプランによって[異なります](https://docs.databricks.com/resources/limits.html))に限定されていました。このプラットフォームの制限を回避するために、お客様は多くのデータ、ML/AIワークロードを別のワークスペースのジョブに割り振らなくてはなりませんでした。本日、この制限を**10,000にまで大幅に引き上げ**られることを発表できて嬉しく思っています。新たなプラットフォームの制限は全てのお客様のワークスペースに自動で適用されます(シングルテナントは除きます)。

多くのお客様は、CI/CDシステムを含む自分達のアプリケーションからジョブを作成、管理するために[Jobs API](https://docs.databricks.com/dev-tools/api/latest/jobs.html)を活用しています。ジョブの制限の増加とともに、高速かつページネーションされたバージョンの[jobs/list](https://docs.databricks.com/dev-tools/api/latest/jobs.html#operation/JobsList) APIを導入し、ジョブのページにページネーションを追加しました。
![](https://www.databricks.com/wp-content/uploads/2022/08/db-308-blog-img-1.png)
*ページネーションを伴うジョブのリスト*

また、ワークスペースの制限の引き上げによって、名称、タグ、ジョブIDによる検索を可能とする整理された検索体験も提供します。
![](https://www.databricks.com/wp-content/uploads/2022/08/db-308-blog-img-2.png)
*名称、タグ、ジョブIDによる検索*

まとめると、新機能によってワークスペースを大量なジョブにスケールさせることができます。上述した機能の変化が望ましくないようなレアケースにおいては、Adminコンソールから古い挙動に[戻す](https://docs.databricks.com/administration-guide/workspace/enable-increased-jobs-limit.html)ことが可能です(最大3000ジョブを持つワークスペースのみで可能です)。特に数千のジョブを保存しているワークスペースにおいては、ジョブの一覧を取得するためにこの新しいページめくりバージョンのAPIに切り替えることを全てのお客様に強くお勧めします。

Databricksワークフローを使い始めるには、[Databricksジョブのクイックスタート](https://qiita.com/taka_yayoi/items/932e211757e697fe9d5e)をご覧ください。また、体験したことや知りたい他の機能に関してフィードバックがあれば是非[お知らせください](https://forms.gle/C5n1m5HgCpfoFDCy8)。

**詳細はこちら**

- [ワークフローによる複雑なタスク依存関係の取り扱い](https://qiita.com/taka_yayoi/items/871bf30f6edf00d3ee1e)
- [まもなく導入されるワークフローの機能](https://qiita.com/taka_yayoi/items/a9fe1af72d2929b3d68b)

### Databricks 無料トライアル

[Databricks 無料トライアル](https://databricks.com/jp/try-databricks)
CSharp to PlantUMLが実行されない場合

F1を押して、「CSharp to PlantUML」を選択しても「plantuml」が自動生成されない場合、
.NetのRuntimeがインストールされていない可能性がある。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/114606/5bc93df7-4753-230a-8fc3-5b1f6bca16da.png)
自分の場合はRuntimeのインストールで無事実行できるようになった。
（ない場合でも特にエラーなどは表示されない）
【Docker】Docker in Docker やってみた

# 環境

ホストマシン：Amazon Linux2
AMI：amazon/amzn2-ami-kernel-5.10-hvm-2.0.20220719.0-x86_64-gp2

# Docker in Docker コンテナを起動する

公式ドキュメントは以下になります。

https://hub.docker.com/_/docker

Docker in Docker を起動します。

```
docker run --privileged --name dind -d docker:stable-dind
```

起動したコンテナに入ります。

```
docker exec -it dind /bin/ash
```

次はコンテナの中で docker バージョンを確認してみます。

```
/ # docker --version
Docker version 19.03.14, build 5eb3275
```

# コンテナの中でコンテナを起動する

Dockerfile を作成します。

```
mkdir /sample
cd /sample
vi Dockerfile
```

```Dockerfile:Dockerfile
FROM centos:7

COPY ./sample.sh /sample/sample.sh

CMD cd /sample; sh sample.sh
```

`CMD` 部分にある sample.sh は以下のように作成します。

```shell:sample.sh
uname -a
echo 'Hello!'
```

ビルド・起動します。

```
docker build -t my-centos7 .
docker run my-centos7
```

標準出力には以下のように表示されます。

```
Linux 7c789b2a326f 5.10.130-118.517.amzn2.x86_64 #1 SMP Wed Jul 13 16:51:52 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux
Hello!
```

以下のコマンドでコンテナに入ることができます。

```
docker run -it my-centos7 bash
```

# 参考記事

https://hub.docker.com/_/docker

https://blog.nijohando.jp/post/docker-in-docker-docker-outside-of-docker/
【SwiftUI】BindingのあるViewでPreviewを表示させる方法

# 解決方法
```swift
import SwiftUI

struct TextView: View {
    @Binding var text: String
    var body: some View {
        Text(text)
    }
}

struct TextView_Previews: PreviewProvider {
    static var previews: some View {
        TextView(text: .constant("プレビュー用デフォルトテキスト"))
    }
}
```

# 解説
こちらで囲うことによって`Binding<Value>`に変換されます。
```swift
.constant()
```
https://developer.apple.com/documentation/swiftui/binding/constant(_:)

# おわり
BindingはSwiftUIに絶対に付いてくるので知ってて損はないと思います。
【JavaScript】文字列とUnicode

# 概要
JavaScriptを学習、理解を深めるため「[JavaScript Primer 迷わないための入門書](https://jsprimer.net/)」を読み、
理解した内容等を記載していく。

「[【JavaScript】JavaScript入門一覧](https://qiita.com/andota05/items/22fae452225b785fd405)」に他の記事をまとめています。

# この記事で理解できること
* JavaScriptにおける、Unicodeの構成要素との関係

# Code Point
* Unicodeはすべての文字に一意のIDが定義されており、そのIDを`Code Point（符号位置）`と呼ぶ。
* Code Pointを扱うメソッドとして`codePointAt`メソッド、`String.fromCodePoint`メソッドが存在する。
* それぞれ`ES2015`から導入された。

## codePointAtメソッド
* 文字列の指定インデックスにある文字のCode Pointの値を返す。

```js
// 引数にインデックスを指定し、"あ"のCode Pointを取得
console.log("あいうえお".codePointAt(0)); // => 12354
```

## String.fromCodePointメソッド
* 指定したCode Pointに対応する文字を返す。
* Code Pointを16進数に変換後、`Unicodeエスケープシーケンス`で指定しても同じように文字を返す。

```js
// "あ"のCode Point(12354)を指定
console.log(String.fromCodePoint(12354)); // => あ

// "あ"のCode Point(12354)を16進数に変換
const hex = "あいうえお".codePointAt(0).toString(16);
console.log(hex); // => 3042

console.log("\u{3042}"); // => あ
```

# Code PointとCode Unitの違い
* Code Point(符号位置)は、その文字の`ID`
    * 文章にすると..「この文字のIDはXXXです」
* Code Unit(符号単位)は、文字列の`構成要素の最小単位`
    * 文章にすると..「JavaScriptの内部的に、この文字列はCode Unit2つで構成されている」
    * JavaScriptが内部的に採用している`UTF-16`では1Code Unitでは`65536種類`しか表現できない。
    * `65537種類目`以降を表現する場合、`サロゲートペア`という仕組みを用いて文字列を表現する。

# サロゲートペア
* 2つの`Code Unit`を組み合わせて(合計4バイト)1文字を表現する仕組み。
* UTF-16では`\uD800～\uDBFF(上位サロゲート)`、`\uDC00～\uDFFF(下位サロゲート)`として範囲を設けている。
* `上位サロゲート`と`下位サロゲート`がペアとなる。

```js
// 1文字なのにlengthが2(Code Unitが2つで表現されているため)
console.log("𩸽".length) // => 2

// Code Unitを出力
for (let i = 0; i < "𩸽".length; i++) {
  console.log("𩸽".charCodeAt(i).toString(16));
}
// => d867(上位サロゲート)
// => de3d(下位サロゲート)

console.log(`\ud867\ude3d`); // => 𩸽
```

# 正規表現の`.`とUnicode
* `ES2015`から正規表現に`u（Unicode）フラグ`が追加された。
* uフラグありの場合、文字列を`Code Point`が順番に並んだものとして扱う。
* uフラグなしの場合、文字列を`Code Unit`が順番に並んだものとして扱う。

```js
const str = "𩸽は白米に合う";

// キャプチャで𩸽を取得し検証
const pattern1 = /(.)は白米に合う/;
const pattern2 = /(.)は白米に合う/u;

console.log(str.match(pattern1)); // => [ '\ude3dは白米に合う', '\ude3d', index: 1, input: '𩸽は白米に合う', groups: undefined ]
console.log(str.match(pattern2)); // => [ '𩸽は白米に合う', '𩸽', index: 0, input: '𩸽は白米に合う', groups: undefined ]

// uフラグなしの場合は、下位サロゲートのみが取得され、正しく表示されていない
// uフラグありの場合は、Code Pointとして扱うため"𩸽"が取得できている
```

# Code Pointの数を数える
* JavaScriptには、文字列における`Code Pointの個数`を数えるメソッドは存在しない。
* 文字列をCode Pointごとに区切った`配列へ変換`して、配列の長さを数えるのが簡潔とされている。


## Array.fromメソッド
* 引数に`iterableなオブジェクト`を受け取り、それを元にした新しい配列を返す。
* 文字列も[iterableオブジェクト](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/String/@@iterator)であるため、Array.fromメソッドによって`1文字ごとに区切った配列`へと変換できる。

> **iterableなオブジェクト**とは
> Symbol.iteratorという特別な名前のメソッドを実装したオブジェクトの総称。
> for...of文などで反復処理が可能なオブジェクト。

```js
// 以下の文字列の長さは7ではなく8
const str = "𩸽は白米に合う";
console.log(str.length); // => 8

// 配列を作成
const strings = Array.from(str);

console.log(strings);         // => [ '𩸽', 'は', '白', '米', 'に', '合', 'う' ]
console.log(strings.length);  // => 7(1文字ごとに区切った配列の長さ = 実際に人間が目で見た文字の数となっている)
```
【JavaScript】配列⑤ 〜メソッドチェーン〜

# 概要
JavaScriptを学習、理解を深めるため「[JavaScript Primer 迷わないための入門書](https://jsprimer.net/)」を読み、
理解した内容等を記載していく。

「[【JavaScript】JavaScript入門一覧](https://qiita.com/andota05/items/22fae452225b785fd405)」に他の記事をまとめています。

# この記事で理解できること
* 配列におけるメソッドチェーンを利用した処理方法

# メソッドチェーンとは
* メソッドを呼び出した返り値に対して、さらにメソッド呼び出しを行うパターンのこと
* `.`で繋げていく。
* 処理の`見た目を簡潔にできる`ことが特徴(途中の一時的な変数を省略できたり..)<br>※メソッドチェーンのことを知らないと最初は複雑に見える(た)
* `長過ぎるメソッドチェーン`は読みにくくなる。

```js
const numbers1 = [1, 2, 3, 4];
const numbers2 = [5, 6, 7, 8];

// 異なる配列を結合(concat)し、結合した配列から2で割り切れる要素を集めた新たな配列を作成(filter)
// ↑をメソッドチェーンで処理する
const newNumbers = numbers1.concat(numbers2).filter(val => {
  return val % 2 === 0
});
console.log(newNumbers);
```

```js
const numbers1 = [1, 2, 3, 4];
const numbers2 = [5, 6, 7, 8];

// 下記は先ほどのメソッドチェーンと同じことをしている
// 異なる配列を結合
const newArray = numbers1.concat(numbers2);

// 2で割り切れる要素を集めた新たな配列を作成
const newNumbers = newArray.filter(val => {
  return val % 2 === 0
});
console.log(newNumbers); // => [ 2, 4, 6, 8 ]
```
【JavaScript】配列④ 〜配列を反復処理するメソッド〜

# 概要
JavaScriptを学習、理解を深めるため「[JavaScript Primer 迷わないための入門書](https://jsprimer.net/)」を読み、
理解した内容等を記載していく。

「[【JavaScript】JavaScript入門一覧](https://qiita.com/andota05/items/22fae452225b785fd405)」に他の記事をまとめています。

# この記事で理解できること
* 配列の反復処理方法およびメソッド

# 配列の反復処理でよく利用されるメソッド
* `foreach`、`map`、`filter`、`reduce` メソッド。

## Array.prototype.forEach
* 配列の要素を`先頭から順番にコールバック関数へ渡し`、反復処理を行う。
* コールバック関数へ`要素`、`渡された要素のインデックス`、`反復処理対象の配列`を引数として渡す。

```js
const array = ["One", "Two", "Three"];

// forEachでの反復処理
array.forEach((val, index, array) => {
  console.log(`渡された要素の値は${val}で、要素のインデックスは${index}です。配列の各要素は${array}です。`);
});
// => 渡された要素の値はOneで、要素のインデックスは0です。配列の各要素はOne,Two,Threeです
// => 渡された要素の値はTwoで、要素のインデックスは1です。配列の各要素はOne,Two,Threeです
// => 渡された要素の値はThreeで、要素のインデックスは2です。配列の各要素はOne,Two,Threeです

// 要素の値のみコールバック関数へ渡す
array.forEach(val => {
  console.log(`渡された要素の値は${val}です。`);
});
// => 渡された要素の値はOneです。
// => 渡された要素の値はTwoです。
// => 渡された要素の値はThreeです。
```

## Array.prototype.map
* 配列の要素を`先頭から順番にコールバック関数へ渡し`、コールバック関数が返した値から`新しい配列を作成`する。
* コールバック関数へ`要素`、`渡された要素のインデックス`、`反復処理対象の配列`を引数として渡す。

```js
const array = ["One", "Two", "Three"];

// mapでの反復処理
const newArray = array.map((val, index, array) => {
  const description = index + 1;
  return `${val}: ${description}`;
});
console.log(newArray); // => [ 'One: 1', 'Two: 2', 'Three: 3' ]

// 要素の値のみコールバック関数へ渡す
const otherArray = array.map(val => val );
console.log(otherArray); // => [ 'One', 'Two', 'Three' ]

// 新しい配列オブジェクトを作成されるため、比較しても一致しない
console.log(otherArray === array);
```

## Array.prototype.filter
* 配列から`不要な要素を取り除いた配列を作成したい場合`に利用する。
* 配列の要素を`先頭から順番にコールバック関数へ渡し`、コールバック関数がtrueを返した要素だけを集めた`新しい配列を作成`する。
* コールバック関数へ`要素`、`渡された要素のインデックス`、`反復処理対象の配列`を引数として渡す。

```js
const numbers = [2, 5, 7, 20, 21];

const newArray = numbers.filter((val, index, array) => {
  return val % 2 === 0;
});
console.log(newArray);    // => [ 2, 20 ]

// こちらも要素だけコールバック関数に渡すことができる
const overElevens = numbers.filter(val => {
  return val > 11;
});
console.log(overElevens); // => [ 2, 21 ]
```

## Array.prototype.reduce
* 累積値（アキュムレータ）と配列の要素を順番にコールバック関数へ渡し、1つの累積値を返す。
* コールバック関数へ`累積値`、`要素`、`渡された要素のインデックス`、`反復処理対象の配列`を引数として渡す。
* reduceメソッドの第二引数には`累積値の初期値`となる値を渡せます。(省略時は`0`を指定したのと同じ)

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

// reduceの第二引数として初期値0を指定
const result = numbers.reduce((totalVal, val, index, array) => {
  return totalVal + val;
}, 0);
console.log(result); // => 10
```
【JavaScript】配列③ 〜配列を操作(要素の追加・削除)するメソッド〜

# 概要
JavaScriptを学習、理解を深めるため「[JavaScript Primer 迷わないための入門書](https://jsprimer.net/)」を読み、
理解した内容等を記載していく。

「[【JavaScript】JavaScript入門一覧](https://qiita.com/andota05/items/22fae452225b785fd405)」に他の記事をまとめています。

# この記事で理解できること
* 配列の要素の追加、削除方法
* 配列の結合方法
* 配列の展開方法

# 配列の要素の追加、削除
* 要素を配列の末尾へ追加(`push`)
* 配列の先頭へ要素を追加(`unshift`)
* 末尾から配列の要素を削除(`pop`)
* 配列の先頭から要素を削除(`shift`)

## 要素を配列の末尾へ追加(`push`)

```js
const numbers = [ 100, 200, 300 ];

// 配列の末尾へ要素を追加
numbers.push(400);
console.log(numbers); // => [ 100, 200, 300, 400 ]
```

## 配列の先頭へ要素を追加(`unshift`)

```js
const numbers = [ 100, 200, 300 ];

// 配列の末尾へ要素を追加
numbers.unshift(400);
console.log(numbers); // => [ 400, 100, 200, 300 ]
```

## 末尾から配列の要素を削除(`pop`)
* popメソッドの返り値として、`末尾から削除した要素`が返される。

```js
const numbers = [ 100, 200, 300 ];

// popメソッドは末尾から削除した要素を返す
console.log(numbers.pop()); // => 300

// 要素削除後の配列
console.log(numbers);       // => [ 100, 200 ]
```

## 配列の先頭から要素を削除(`shift`)
* shiftメソッドの返り値として、`先頭から削除した要素`が返される。

```js
const numbers = [ 100, 200, 300 ];

// shiftメソッドは先頭から削除した要素を返す
console.log(numbers.shift()); // => 100

// 要素削除後の配列
console.log(numbers);         // => [ 200, 300 ]
```

# 配列同士を結合(`concat`)
* 配列と配列を結合し、新しい配列を生成することができる。
* 配列だけではなく、`任意の値`を要素として結合できる。

``` js
const numbers1 = [100, 200, 300];
const numbers2 = [400, 500, 600];

const newNumbers = numbers1.concat(numbers2);
console.log(newNumbers); // => [ 100, 200, 300, 400, 500, 600 ]

// 数値リテラルを結合してみる
const newArray = newNumbers.concat(700);
console.log(newArray);   // => [ 100, 200, 300, 400, 500, 600, 700 ]
```

# 配列の展開(`...Spread構文`)
* concatメソッドで配列同士を結合するのと同様の結果を取得できる。
* 異なる点としては、配列リテラルの`任意の位置`に展開できる。
* `ES2015`から導入。

```js
const numbers = [400, 500, 600];

// concatで結合
const newNumbersConcat = [100, 200, 300].concat(numbers);
console.log(newNumbersConcat);   // => [ 100, 200, 300, 400, 500, 600 ]

// spread構文...(ドットを3つ)
const newNumbersSpread1 = [100, 200, 300, ...numbers];
console.log(newNumbersSpread1);  // => [ 100, 200, 300, 400, 500, 600 ]

// 任意の位置に展開してみる
const newNumbersSpread2 = [100, 200, ...numbers, 300];
console.log(newNumbersSpread2);  // => [ 100, 200, 400, 500, 600, 300 ]
```

# 配列から全要素・任意の要素を削除する方法
* `Array.prototype.splice`メソッドを使用
* `length`プロパティへの代入
* `空の配列`を代入

## Array.prototype.spliceメソッドを使用
* 第一引数に`削除開始位置のインデックス`、第二引数に`削除する要素の数`を指定する。
* 削除した要素は`自動で詰められる`。

```js
const array = ["A", "B", "C"];

// 配列のインデックス1から一つの要素を削除
array.splice(1, 1);
console.log(array);    // => [ 'A', 'C' ]

// 自動で要素が詰められている
console.log(array[1]); // => C
```
```js
const array = ["A", "B", "C"];

// 全要素を削除
array.splice(0, array.length);
console.log(array); // => []
```

## lengthプロパティへの代入
```js
const array = ["A", "B", "C"];

// lengthに0を代入することで全要素を削除
array.length = 0;
console.log(array); // => 0
```

## 空の配列を代入
```js
// 再代入を行うのでletで定義する必要がある
let array = ["A", "B", "C"];

// 空の配列を代入することで全要素を削除
array = [];
console.log(array); // => []
```
【JavaScript】配列① 〜配列の作成とアクセス〜

# 概要
JavaScriptを学習、理解を深めるため「[JavaScript Primer 迷わないための入門書](https://jsprimer.net/)」を読み、
理解した内容等を記載していく。

「[【JavaScript】JavaScript入門一覧](https://qiita.com/andota05/items/22fae452225b785fd405)」に他の記事をまとめています。

# この記事で理解できること
* 配列とは
* 配列の要素の取得
* 配列の分割代入

# 配列
* 値に`順序をつけて`格納できるオブジェクト。
* 配列に格納した値を`要素`、位置を`インデックス`と呼ぶ。
* `配列[インデックス]`と指定することで`要素`を参照できる。
* インデックスは`1`ではなく`0`から始まるということがポイント。

```js
// 配列リテラルで名簿のような配列を作成(変数:nameListに代入)
const nameList = ["Taro", "Hanako", "Mike"]; // インデックス:要素 = 0:Taro、1:Hanako、2:Mike

// nameListの要素「Taro」を出力(配列のインデックスは0から..)
console.log(nameList[0]); // => Taro

// 存在しないインデックスを指定すると「undefined」が返される
console.log(nameList[3]); // => undefined
```
```js
// 配列の配列(多次元配列)も作成できる
const arrayOnArray = ["A", "B", "C", [1, 2, 3]];
// インデックス3(=[1, 2, 3]の配列)、その配列内のインデックス0(=1)を指定
console.log(arrayOnArray[3][0]); // => 1 
```

# 要素数の取得
* 配列には要素数を取得できる`length`プロパティが存在する。

```js
// 配列リテラルで名簿(変数:nameListに代入)
const nameList = ["Taro", "Hanako", "Mike"];

// lengthプロパティを出力
console.log(nameList.length); // => 3
```

# オブジェクトが配列かどうかを判定する
* あるオブジェクトが配列かどうかを判定するには`isArray`メソッドを利用する。
* 配列の場合は、`true`が返される。

```js
const nameList = ["Taro", "Hanako", "Mike"];
const obj = {};

console.log(Array.isArray(nameList)); // => true
console.log(Array.isArray(obj));      // => false

// typeofでは判定できない(配列もオブジェクトのため)
console.log(typeof array); // => object
```

# 配列と分割代入(ES2015〜)
* 配列の指定したインデックスの値を変数に再定義する方法に、`分割代入`が存在する。
* 左辺に`配列リテラルに指定したい変数名`を、右辺の`配列`を定義する。
* `右辺から左辺`へ、それぞれのインデックスに該当する位置に要素の代入が行われる。

```js
const array = ["one", "two", "three"];

// 左辺:配列リテラル 右辺:配列で分割代入
const [One, Two, Three] = array;

console.log(One);   // => one
console.log(Two);   // => two
console.log(Three); // => three
```
【JavaScript】値の評価と表示

# 概要
JavaScriptを学習、理解を深めるため「[JavaScript Primer 迷わないための入門書](https://jsprimer.net/)」を読み、
理解した内容等を記載していく。

「[【JavaScript】JavaScript入門一覧](https://qiita.com/andota05/items/22fae452225b785fd405)」に他の記事をまとめています。

# この記事で理解できること
* 値の評価とは
* ブラウザにおける値の評価、表示方法

# 前提
当記事における動作環境
* PC：MacBook
* コードエディタ：Visual Studio Code
* ブラウザ：Google Chrome

# 値の評価とは
* 入力した値を評価してその結果を返すこと。

> **評価**(※Wikipedia一部参照)
> 数学や計算機科学において、変数に関連づけられた値などをもとに関数（関数 (数学)、関数 (プログラミング)）などの式・表現が表す値を計算すること。> あるいは、不等式により値の範囲を絞り込むこと。

# ブラウザでJavaScriptのコードを評価する
ブラウザで評価する方法として、大きく分けると以下の方法がある。
* ブラウザの開発者コンソールを利用する。
* HTMLでJavaScriptのコードを読み込む。

# ブラウザの開発者コンソールを利用する
* Google Chromeを開き、開発者コンソールを開く(`⌘ + option + i`)
* 以下のキャプチャのような`REPL`と呼ばれる開発者向けの機能を使用することで簡単に評価を行える。

![スクリーンショット 2022-08-11 6.26.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/640274/0aeef952-09c9-6b84-2b0a-6273c056df75.png)

```js
//　以下の例を開発者コンソールに入力してみる
1 + 2 + 3;
// => 6(計算結果を返している)

const name = "Taro";
// => undefined(JavaScriptにおける式は何らかの結果(値)を返す特性があり、明示的に何らかの値を返さない場合は、undefinedを返す)

console.log(name);
// => Taro

console.log("Hello JavaScript");
// => Hello JavaScript
// => undefined(console.logは、文字列を出力するという式(正式には式文)であり、値は返していないのでundefinedが返されている)
```

# HTMLでJavaScriptのコードを読み込む
今回は例として任意の場所に「demo」というフォルダを作成し、demoフォルダ内に以下のファイルを作成した。

* index.html
* script.js

![スクリーンショット 2022-08-11 6.58.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/640274/62d68da7-cb93-29aa-69ed-5753e6577e94.png)

```index.html
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>値の評価と表示</title>
</head>
<body>
  <!-- 同一階層に存在する「script.js」を読み込んでいる -->
  <script src="script.js"></script>
</body>
</html>
```

```script.js
// 先ほどと同一の例を試すため以下のように作成する
// 「.js」ファイルから評価 + ブラウザで確認を行うには、Console APIを使用する必要がある
console.log(1 + 2 + 3);

const name = "Taro";
console.log(name);

console.log("Hello JavaScript");
```

作成したindex.htmlを`右クリック`→「`開く`」→「`開発者コンソールを開く`(⌘ + option + i)」
すると以下のような結果が開発者コンソールに表示されている。
```js
console.log(1 + 2 + 3);
// => 6

const name = "Taro";
console.log(name);
// => Taro

console.log("Hello JavaScript");
// => Hello JavaScript
```

# コードの評価とエラー
評価時には、構文の誤りなど様々な要因でエラーが発生し、大きく分けると以下2種類のエラーが存在する。

* 構文エラー
* 実行時エラー

## 構文エラー
* 書かれたコードの文法が間違っている場合に発生するエラー。
* エラーメッセージに`SyntaxError`というキーワードが含まれていることが多い。

```js
//　例：constというJavaScript側で予約済みキーワードを変数名に使用する
const const = "test1";
// => Uncaught SyntaxError: Unexpected token 'const'
```

## 実行時エラー
* プログラムを実行している最中に発生するエラー。
* 実行時（ランタイム）におきるエラーであるため、`ランタイムエラー`と呼ばれることもある。
* エラーメッセージに`TypeError`や`ReferenceError`というキーワードが含まれていることが多い。

```js
// console.log()をconsol.log(eがない)と存在しない関数を実行する
consol.log("test2");
// => Uncaught ReferenceError: consol is not defined
```

上記の例をはじめ、各種エラーメッセージにおける詳細については『[JavaScript エラーリファレンス](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Errors)』などで確認できる。
AccessDeniedException,User: <s3-batch-operation> is not authorized to perform: lambda:InvokeFunction on resource: <myfunction> because no identity-based policy allows the lambda:InvokeFunction action　エラーの対処

# 経緯
　[チュートリアル:S3 バッチ操作、AWS Lambda および AWS Elemental MediaConvert](を使用したバッチトランスコーディング動画https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/userguide/tutorial-s3-batchops-lambda-mediaconvert-video.html)
　ステップ6：S3 バッチ操作の IAM ロールを作成する、でのエラー
![スクリーンショット 2022-08-06 9.32.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2778864/38787688-477c-8ee2-fb39-2a70a66b1567.png)

　Lambdaを呼び出すためにS3バッチのロールとして下記のポリシーをアタッチする。
![スクリーンショット 2022-08-10 21.57.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2778864/c7dc5b66-728b-436f-5a08-80f5508f2136.png)


　その後S3バッチオペレーションのジョブを実行すると下記のエラーが発生
~~~
tutorial-bucket-1,mov_hts-samp002.mp4,,failed,403,AccessDeniedException,User: arn:aws:sts::<userID>:assumed-role/tutorial-s3batch-role/s3-batch-operations_2d09be84-8186-496a-9457-3c5023895557 is not authorized to perform: lambda:InvokeFunction on resource: arn:aws:lambda:ap-northeast-1:<userID>:function:test-lambda-convert:$LATEST because no identity-based policy allows the lambda:InvokeFunction action
~~~

　S3バッチのロールにアタッチしたポリシーを見にいくと警告が出ていることに気づく。
![スクリーンショット 2022-08-10 21.32.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2778864/b997bf88-d1f4-1af5-4d56-591d1891d8e3.png)

# 対処
　問題は2つあるようでした。
1.　IAMユーザーにLambdaを実行する権限がない。
2.　IAMロールのポリシーの設定が適切でない。
> [Lambda での呼び出しに関する問題のトラブルシューティング](https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/troubleshooting-invocation.html) 

### 1.　IAMユーザーにLambdaを実行する権限がない。
　ユーザーにはAdministoratorAccessがアタッチされているので問題なし

### 2.　IAMロールのポリシーの設定が適切でない。
　ポリシーのResourceの欄を関数のARNではなくフルアクセスにする
![スクリーンショット 2022-08-10 21.41.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2778864/9717a051-b640-01b5-c80b-b9b4984336c0.png)

> [AWS Lambda関数の呼び出し](https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/userguide/batch-ops-invoke-lambda.html)

　警告もなくなり結果成功
![スクリーンショット 2022-08-10 21.47.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2778864/d6cdf41a-edf1-547b-4b97-3c75ab739a9b.png)

~~~
tutorial-bucket-1,mov_hts-samp004.mp4,,succeeded,200,,The input video object was converted successfully.
~~~

　ただこの場合S3バッチに全てのLambdaの実行許可を与えることになっているので推奨されるやり方ではないと思われる。Lambdaにadd-permissionを与えたり他にもいろいろ試しましたがうまくいかなかったので現状はこの方法のみ記載。
　より良い方法が見つかれば記載する予定。
STM32G031のmbed-osでのHT16K33(I2C)でナイトライダー HAL


x 過去ログを見よ
x PA_0をOBでGPIOに出来る人むけ
x STM32G031は、秋月で売っているSTM32G031J6M6の事

目的
最軽量化
I2Cのテスト
PA_0(4ピン)をLチカする。

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

![o_con646.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/0f620109-d984-b908-f683-7dc98badbe4b.jpeg)


関連


https://qiita.com/caa45040/items/3686753c90e7e85ea7e4


```c++

//HAL_HT16K33_031_1


#include "mbed.h"

#define ADDR        (0x70<<1)  //  address

int main() {

    __HAL_RCC_GPIOA_CLK_ENABLE();

    GPIO_InitTypeDef GPIO_InitStruct = {0};

    GPIO_InitStruct.Pin = GPIO_PIN_11|GPIO_PIN_12;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    GPIO_InitStruct.Alternate = GPIO_AF6_I2C2;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = GPIO_PIN_0;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);


    __HAL_RCC_I2C2_CLK_ENABLE();

    I2C_HandleTypeDef hi2c2;

    hi2c2.Instance = I2C2;
    hi2c2.Init.Timing = 0x10707DBC;
    hi2c2.Init.OwnAddress1 = 0;
    hi2c2.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
    hi2c2.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
    hi2c2.Init.OwnAddress2 = 0;
    hi2c2.Init.OwnAddress2Masks = I2C_OA2_NOMASK;
    hi2c2.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
    hi2c2.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
    HAL_I2C_Init(&hi2c2);    

    HAL_I2CEx_ConfigAnalogFilter(&hi2c2, I2C_ANALOGFILTER_ENABLE);

    HAL_I2CEx_ConfigDigitalFilter(&hi2c2, 0);


    uint8_t buf[16];

    buf[0]=0x21;
    HAL_I2C_Master_Transmit(&hi2c2, ADDR, buf, 1, 3000);HAL_Delay(1);

    buf[0]=0x81;
    HAL_I2C_Master_Transmit(&hi2c2, ADDR, buf, 1, 3000);HAL_Delay(1);

    buf[0]=0xef;
    HAL_I2C_Master_Transmit(&hi2c2, ADDR, buf, 1, 3000);HAL_Delay(1);

    for(int ii=0;ii<16;ii++){
        buf[0]=ii;
        buf[1]=0x00;
        HAL_I2C_Master_Transmit(&hi2c2, ADDR, buf, 2, 3000);HAL_Delay(1);
    }//for

    while(1) {

        for(int ii=0;ii<8;ii++){

            buf[0]=0;
            buf[1]= (1<<ii);
            HAL_I2C_Master_Transmit(&hi2c2, ADDR, buf, 2, 3000);HAL_Delay(600);

            HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_SET);
            HAL_Delay(200);
            HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_RESET);
            HAL_Delay(200);

        }//for
    }//while
}//main





```
ABC098 D - Xor Sum 2 別解メモ

# はじめに

昔の問題ではあるんだけど、自分の解法が公式解説・ユーザ解説とは違ったのでメモ的に残しておく。

# 問題

https://atcoder.jp/contests/abc098/tasks/arc098_b


# 考察

```
Al​ xor Al+1​ xor ... xor Ar ​= Al​ + Al+1​ + ... + Ar​
```
を満たすケースの個数を数える、という問題である。

一見、`l`と`r`を全探索する必要があるように見えるが、bit毎に考えると、
要素を増やしたときに同じbitが立っている場合左辺側は小さくなる、ということが起きる。
```
0b10 ^ 0b11 = 0b01
0b10 + 0b11 = 0b101
```
というわけで、ある`l`を固定して、bitが被る前まで`r`を増やしつつカウントする。



さて、0が含まれないケースを考えてみる。（というかそういう問題だと当初誤読していた）
そもそもbitが被らずにどれくらい要素を増やせるのか、を考えてみると、実はそんなにないことが分かる。
`Ai<2**20`なので、要素を増やすごとに20bitのどこかは埋まっていく。
したがって、実はlを走査しながら`r`を`(l,l+20]`の範囲で動かし、bitが被るかを確認していけばいいので、
`O(N*log(max(A))`で間に合う。

もちろんこのままだと0が含まれているケースが考慮されていないのでWAになる。（なった）

https://atcoder.jp/contests/abc098/submissions/33929332

次に0が含まれるケースを考える。
入力例2のような感じで、0が続くとbitは埋まっていかない。
従って、例えば0が200個続いたとき、20個先までで打ち切ったら答えは合わなくなる。
とすると、結局はrは末尾まで見る必要が出てきてしまう。

なので、この例外的なふるまいをする0の部分について圧縮してみよう。
`A = [0 0 0 0 1 0 0 0 0]`
を0の個数をマイナスで数えて、
`B = [-4 1 -4]`
という感じにする。

こうすれば、0がいくら連続しても走査量は増えていかない。
(`0 1 0 1 ...`みたいなケースに備えて,`r`の範囲は2倍にしておく）

改めて、`l`を固定して`r`を動かすことを考えると、
`B[l]`が負数の時は、
- 内部での数え上げ `-B[l](-B[l]+1)//2`
- `r`が増やせる場合に`-B[l]`の個数分カウントする

r側で負数が出てきた時はその分数えあげればいい。




# 自分の提出

https://atcoder.jp/contests/abc098/submissions/33929406
【SwiftUI】onDisappearで動的にページを再生成して無限に横ページ移動

# 内容
定数個の`View`を横に並べたカルーセルの記事はよく拝見しましたが、動的に前ページ、現在ページ、次ページを作り替えていくパターンはぱっと見つからなかったのでやってみました。
**移動アニメーションが終わった後に、移動前のページを新しい現在ページとする**にはアニメーション終了検知が必要ですが、自分のスキル的にまだ難しそうだったので、`onDisappear`を利用して近いことを実現しました。
軽い頭の体操くらいの気持ちで見てもらえればと思います。自分はこれをやったことで`State`と再描画の理解が深まりました。

# 開発環境
macOS Monterey v.12.5
Xcode v.13.4.1
主にiPhoneSE(3rd)(iOS15.5)のシミュレーターを利用

# 結果gifとコード
![git_move_page.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2734189/1fde82cd-b79b-9c12-b15d-0b847b0414e6.gif)
タップするごとに無限に1ページずつ減っていきます。
最初に用意しているのは5,6,7ページのみで、`onTapGesture`を実装しているのは現在ページのみです。タップのたびに「横移動->終了後に1ページずらして各ページ再生成」をやってます。

実装の大きな流れは
- page5(前ページ), page6(現在ページ), page7(次ページ)を作って`HStack`で横に並べる
- 現在ページの`onTapGesture`で`@Stateのphase`が変更される
    - HStack全体のoffsetが更新されて前ページに移動する（ように見える。実際は全体が右に動く）
    - これだけでは移動して前ページが画面範囲に入っただけで、現在ページという扱いではなく、タップで前ページに移動することはできない
        - そこで`@Stateのphase`が変わると`onDisappear`が発火するようダミーViewを配置しておき、そこでページ生成元の`@Stateのpages`を更新し、前ページの内容が現在ページになるよう再描画 

コードです↓
```swift
import SwiftUI
struct ContentView: View {
    @State var phase:String = "init"
    @State var pages:[Int] = [5,6,7]
    var body: some View {
        return (
            HStack(spacing:0){
                // prev page
                VStack{
                    Text("page \(pages[0])")
                    Text("タップして前ページへ").foregroundColor(Color.blue)
                }.frame(width: UIScreen.main.bounds.width)

                // dummy
                if phase=="init"{
                    // initではなくなった時にonDisappearを走らせるためのダミーView
                    ZStack{
                        Text("")
                    }.onDisappear{
                        // 移動完了と同じタイミングでstateを更新して、prev pageの内容をcurrent pageに割り当て直す
                        pages = [pages[0]-1, pages[1]-1, pages[2]-1]
                        phase = "init"
                    }
                }
                
                // current page
                VStack{
                    Text("page \(pages[1])")
                    Text("タップして前ページへ")
                        .foregroundColor(Color.blue)
                        .onTapGesture{
                            withAnimation(.linear(duration: 1)){
                                phase = "tapped"
                            }
                        }
                }.frame(width: UIScreen.main.bounds.width)
                
                // next page
                ZStack{
                    Text("page \(pages[2])")
                    Text("タップして前ページへ").foregroundColor(Color.blue)
                }.frame(width: UIScreen.main.bounds.width)
            }
            .offset(x: phase=="init" ? 0 : UIScreen.main.bounds.width)  // tappedに変わったときに全体を動かしてページ移動
        )
    }
}
```
おわり
アイテムとして使用するとスキルが発動する武器・防具を作る

ドラゴンクエストでいう所の「いかづちの杖」のような、道具として使うと効果を発揮する装備品を作ります。

今回は以下のような仕様で作成します。


1. 発動するスキルは「吹雪」。スキル自体は別に作成する。
1. 道具として使った場合のスキルは魔法の使用を制限する「沈黙」状態の影響を受けないようにする。
2. 対応する装備品は「吹雪の杖」。スキルを習得する形で処理する。
3. スキルタイプは専用の物を用意する。

 # スキルタイプ「道具使用を作成する。」
沈黙状態の影響を受けないように「道具使用」という専用のスキルタイプを作ります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/92869/1c999fe8-573a-a06c-fb1b-76aaf693abe5.png)


 # スキルを作成する
発動するスキルを作成します。
ゲームの初期データにある「ブリザード３」をコピーしています。
スキルタイプを「道具使用」にし、沈黙状態(魔法の使用を制限する状態異常)の影響を受けないようにします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/92869/dbbbdb79-eefc-6d74-2692-9c81d93a6eba.png)


 # 装備品を作成する
対応する装備品を作ります。
スキル「吹雪」を追加します。
そのままではスキルを選択できないので、スキルタイプ追加「道具使用」を特徴に入れます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/92869/d4a6003f-1c77-b7cb-cdb6-19df6baa5665.png)


 # まとめ
以上で終わりです。
基本的な機能の組み合わせで表現が可能です。
防具でも同じ設定は使えます。