OmniAICreator/Qiita-1.07M huggingface dataset:
[AWS Q&A 365][ECS]Daily Five Common Questions #80

# 1. What is a cluster in Amazon ECS? 
A cluster is a logical grouping of tasks or services in Amazon ECS. It is a container management service that allows you to run and scale containerized applications across a cluster of Amazon EC2 instances or AWS Fargate resources. 

# 2. How do I create a cluster in Amazon ECS? 
You can create a cluster using the Amazon ECS console, AWS CLI, or AWS SDKs. To create a cluster, you need to specify the cluster name, the launch type (EC2 or Fargate), and the VPC and subnets where the cluster will be launched. 

# 3. What is capacity provider in Amazon ECS clusters? 
Capacity providers are a way to manage the capacity of your Amazon ECS clusters. They allow you to define the capacity required for your tasks and services, and automatically provision and scale the required resources based on demand. 

# 4. How do I manage clusters in Amazon ECS? 
You can manage clusters in Amazon ECS using the Amazon ECS console, AWS CLI, or AWS SDKs. You can view the status of your clusters, update the cluster configuration, and monitor the performance of your tasks and services. 

# 5. Can I use a single cluster for multiple applications in Amazon ECS? 
Yes, you can use a single cluster for multiple applications in Amazon ECS. You can define multiple services or tasks within a single cluster, each with its own configuration and resource requirements. This allows you to manage multiple applications within a single cluster and optimize resource utilization.
【Laravel備忘録】「Target class [○○Controller] does not exist.」②

# 【Laravel備忘録】
以前、「Target class [○○Controller] does not exist.」についての記事を書きましたが、もう1つエラー回避方法があったので今回はそちらを紹介します。

## useでコントローラをインポートする
前回はファンクション内の参照の仕方でエラーを回避しました。
今回も参照の仕方を変えるので回避方法としては似たようなやり方ですが、違う書き方なのでご紹介します。
まずはrouteのファイルでuse宣言してコントローラをインポートします。
```
use App\Http\Controllers\HelloController;
```
そしたら次にRouteの中でコントローラを参照する方法ですが下記のように参照します。
```
Route::get('hello', [HelloController::class, 'index']);
```
この記載方法でもエラー回避できましたのでもし困っている方がいましたらこの方法も試してみてください。

では本日はこの辺で。
ありがとうございました。
いい週末をお過ごしください。
[新機能追加！] Amazon CloudWatch Logs のコンソールに「Live Tail」機能が追加されたよ！

# 概要

本日(2023年6月15日)に、Amazon CloudWatch Logs に新機能として「Live Tail」が追加されました。
今回は、追加された機能について実際にどんな感じに見えるのか見ていこうと思います。

https://aws.amazon.com/jp/blogs/mt/announcing-live-tail-feature-for-amazon-cloudwatch-logs/

# 一言で何がいいの？？

* 今回の新機能である「Live Tail」を使用することにより、Amazon CloudWatch Logs 上で**リアルタイムでログを監視すること**ができ、それにより迅速に問題の特定ができるようになります。

それ以外の機能としては、ログのフィルタリングや詳細な検索が可能となっております。
Amazon CloudWatch Logs を使用し、ログ調査を行なっている方がいれば是非活用してみましょう！

# 実際に使ってみた。

* 「Live Tail」 を開始するには、IAM の Admin Role か、AWS管理ポリシー[CloudWatchLogsReadOnlyAccess]を使用するか、logs:*を許可するIAMポリシーを持っているか、logs:StartLiveTail と logs:StopLiveTail アクションをポリシーに追加する必要があります。

ポリシー例は以下となります。

```json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "logs:StartLiveTail",
        "logs:StopLiveTail",
        "logs:Get*"
    ],
      "Resource": [
        "arn:aws:logs:*:*:*"
    ]
  }
 ]
}
```

(引用元: https://aws.amazon.com/jp/blogs/mt/announcing-live-tail-feature-for-amazon-cloudwatch-logs/)


## Amazon CloudWatch のコンソールを見てみる

* お、何やら「live tail」なるものが追加されてますね。

![スクリーンショット 2023-06-16 22.41.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563635/dfd46bd0-4d64-21a3-30ff-b95f32fa851c.png)


### ちなみになのですが、「live tail」を使用する方法は３つあるようです。

#### 方法 ①

* まずはじめに、CloudWatch コンソールを開きます。
* 左横のナビゲーションペインで、[ログ]、[Live Tail]を選択します。

[ロググループの選択]で、Live Tail セッションでイベントを表示するロググループを選択します。**最大10個のログ￥グループを選択できるようです。**

![スクリーンショット 2023-06-16 22.45.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563635/d363bfd8-d618-737f-2854-80b4fd110299.png)


#### 方法 ②

* まずはじめに、CloudWatch コンソールを開きます。

* 左横のナビゲーションペインで、[ログ]を選択し、[ロググループ]を選択します。

* 1つ以上のロググループを選択します。「テーリングを開始」ボタンが表示されていますね！

![スクリーンショット 2023-06-16 22.48.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563635/93519802-c4a0-767e-ce44-dd492c12d9a0.png)


* クリックしてみると、先ほどの画面に遷移する動きになるようです。
![スクリーンショット 2023-06-16 22.48.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563635/47b6a594-586f-0ab1-a568-95b1b470b76d.png)


#### 方法 ③
* まずはじめに、CloudWatch コンソールを開きます。

* 左横のナビゲーション ウィンドウで、[ログ]を選択し、[Logs Insights]を選択します。

* [ロググループの選択]ドロップダウンで、1つ以上のロググループを選択します。「テーリングを開始」ボタンが表示されていますね！

![スクリーンショット 2023-06-16 22.50.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563635/e9774ff7-79ab-698e-07d3-570fa49e78e4.png)


## その他の機能

* ログのリアルタイム表示ができるようになったのと、今回の機能により、ログストリームのフィルタリングや詳細な検索が可能になります！
* ガシガシデバックなどに使っていきましょう！！


# 参考資料

https://aws.amazon.com/jp/blogs/mt/announcing-live-tail-feature-for-amazon-cloudwatch-logs/
いろいろ３D イジリ(妄想編)

# ステレオカメラが使いたいという冗談
- 3Dとか複眼とかいろいろあるようです
1. 一番知られている気がするのはReal Sense。言わずもがなインテル
2. PythonばっかやっているとOAK-D(OpenCV-DepthAI）カメラ
2. 昔、勇者が使っていたZEDカメラ
2. ものものしいなこれ、Matterport
2. 単眼で疑似的に見るとか赤外線カメラかしら？

***

- 個人的に使うなら 1か2ですよね。これらは情報も多いし。
- 3は勇者の生きざまを見たのでぜーーーーったいいじらない(爆)
- 記事にはしてなかったけど、ネットつながりで4番ちょっと見てみる。 

:::note alert
うっかり８兵衛
これ、高いっすね。多分触れないんじゃ・・・
:::

# 軽く妄想で情報収集してみる。

**もう使っている会社の記事**

https://dev.classmethod.jp/articles/the-matterport-sdk-for-embeds-package-tutorial/

- こちらはいろいろな製作でお世話になってます！
- SDKってフリーじゃないのか⁉
- チュートリアルで見る限り、今はポイってしたJetsonのOpen3Dっぽい感じ

https://qiita.com/akira-sasaki/items/6e3d6d63586cbe8302f2

:::note info
インフォメーション
自分でもＰＣ上で軽く３Ｄ表示でもしてみました。
これはなんか秘密の機器が必要な予感。
:::

**こう見るとOAK-DとReal Senseのコスパが抜けている感じがします**

## Real senseだと

https://www.tegakari.net/2019/04/realsense_compare/

- こちらのサイトの記事はすごくためになりますね。必読だと思います。

## OAK-Dだと

https://www.arducam.com/product/opencv-ai-kit-oak-d-ov9282x2imx378intel-oak-d/

- 見ての通り、基本的なモデルが入っているので、いきなり遊べます。
- たしか、そんなに高くないはず（といっても円安の貧乏人には高い！）


## Matterportだと

https://zenn.dev/yuma_ito_bd/scraps/1b150ca7219224

- これは使うまでに詳しいですな。
- でも、Webベース？Javascript？なんかちょっとできるかな⁉


<details><summary>エスパーサンプル</summary>


```javascript:javascript

<!DOCTYPE html>
<html>
<head>
  <script src="https://static.matterport.com/showcase-sdk/2.2.1-beta3/sdk.js"></script>
  <style>
    #viewer {
      width: 800px;
      height: 600px;
    }
  </style>
</head>
<body>
  <div id="viewer"></div>

  <button onclick="moveCamera(0, 0, 0)">Reset</button>
  <button onclick="moveCamera(-Math.PI/2, 0, 0)">Rotate Up</button>
  <button onclick="moveCamera(Math.PI/2, 0, 0)">Rotate Down</button>
  <button onclick="moveCamera(0, Math.PI/2, 0)">Rotate Right</button>
  <button onclick="moveCamera(0, -Math.PI/2, 0)">Rotate Left</button>
  <button onclick="zoomCamera(0.5)">Zoom In</button>
  <button onclick="zoomCamera(-0.5)">Zoom Out</button>

  <script>
    const showcase = window.MP_SDK.connect(
      'https://myshowcase.matterport.com/',
      'my_access_token'
    );

    showcase.on('ready', function () {
      showcase.Stage.loadAsync('my_scene_sid').then(function (scene) {
        scene.viewPort.show({
          immersiveMode: true,
          highlightHotspots: true,
          initialCameraPose: { position: { x: 0, y: 0, z: 0 } }
        });
      });
    });

    function moveCamera(rotateX, rotateY, rotateZ) {
      showcase.Stage.getActiveCamera().then(function (camera) {
        const newPose = {
          position: camera.pose.position,
          rotation: {
            x: camera.pose.rotation.x + rotateX,
            y: camera.pose.rotation.y + rotateY,
            z: camera.pose.rotation.z + rotateZ
          }
        };
        camera.lookAt(newPose);
      });
    }

    function zoomCamera(amount) {
      showcase.Stage.getActiveCamera().then(function (camera) {
        camera.zoomIn(amount);
      });
    }
  </script>
</body>
</html>

```

</details>

### やっぱり公式も覗く

https://matterport.com/ja/pro2

- アメリカンででかそう。ただ画素数とかからざっと見ると35㎜ではないのかな？
- 大きいみたいです。

# 今のところ
- 自腹なら断然Real sense ： アリエクスプレスってあれ、人民币吗？
- 日本で買うならOAK-D
- 会社があてがってくれるなら何でもOK


## 使っているとの言語との親和性(個人的）
OAK-D >= Real sense >> ZED camera = Matterportかな？
SwiftUIで書いたMacAppで自ウィンドウを閉じる方法


その方法をネットで調べたところ、モーダルを閉じるときと同じでした。
下記コードで実現できます。

```swift
struct ContentView: View {
    @Environment(\.dismiss) var dismiss
    var body: some View {
        Button("Close") {
            dismiss()
        }
    }
}
```

これで、`NSApplicationDelegate`の`applicationShouldTerminateAfterLastWindowClosed`メソッドが呼ばれます。このメソッドで`true`を返せば、アプリを終了できます。


`NSApplication.shared.terminate(nil)`を呼ぶと`applicationShouldTerminateAfterLastWindowClosed`メソッドが呼ばれずにアプリが終了します。

どちらの方法でアプリを終了させても
`NSApplicationDelegate`の`applicationWillTerminate`メソッドが呼ばれるため、アプリの後処理はここに書くのがよさそうです。

<hr>


[`@Environment`でやれることが沢山ある](https://developer.apple.com/documentation/swiftui/environmentvalues)ので、覚えられません。
PostgreSQL の pg_dump/psql のデータコピーを冪等に行う。


## `pg_dump`コマンド

データのダンプの際には、

- デフォルトでは、`CREATE ○○ IF NOT EXISTS`
- `--clean` オプションを指定すると、`DROP ○○` してから、`CREATE ○○ IF NOT EXISTS`
- `--clean --if-exists` オプションを指定すると、`DROP ○○ IF EXISTS` してから、`CREATE ○○ IF NOT EXISTS`


## `psql`コマンド

リストアの際には、

- デフォルトでは、途中のクエリが失敗しても中断せずに最後までリストアする。
- `--set=ON_ERROR_STOP=1` で途中で失敗したら中断する。DBは途中までリストアされた状態で残る。
- `--single-transaction` オプションを指定すると、シングルトランザクション内でのリストアしてくれる。(途中で失敗すると最初の状態までロールバックする)


## 冪等にするには

いずれかかな。

- `pg_dump` + `psql --single-transaction`
- `pg_dump --clean --if-exists` + `psql --set=ON_ERROR_STOP=1`
- `pg_dump --clean --if-exists` + `psql --single-transaction`
Nuxt+S3+CloudFrontでAccess deniedが発生する

# 課題
Nuxt.js+S3+CloudFrontでJamstackなWebサイトを構築した時に、トップページ以外のページにURLを直接入力してアクセスするとAccess deniedになりアクセスができない

# 原因
Nuxtのデフォルトの設定でSPAになっていたことが大きな原因

# 手順・実装内容
nuxt.config.jsの設定を変更し、サーバサイドレンダリング（SSR）を有効化することでSPAにならないようにした。
```js
export default {
  ssr: true, // ここをfalseから変更した
  target: "static",
```

この設定をしてnpm generateを実行すると各階層にindex.htmlが生成されるようになる
![スクリーンショット 2023-06-16 22.06.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3476743/eac2afb1-ad92-63e4-f5b9-5bd53c7e0e9d.png)

この状態でS3にアップロードした場合、index.htmlにアクセスをしないとページの内容が見えない

× https://example.com/blog/0001
○ https://example.com/blog/0001/index.html

これを是正するためにCloudFrontの関数とビヘイビアの設定を修正する。

まずはCloudFrontに下記の関数を作成する
```javascript
function handler(event) {
    var request = event.request;
    var uri = request.uri;

    // /で終わる場合はindex.htmlを足す
    if (uri.endsWith('/')) {
        request.uri += 'index.html';
    }
    // URLに拡張子が含まれていない場合もindex.htmlを足す
    else if (!uri.includes('.')) {
        request.uri += '/index.html';
    }

    return request;
}
```

次にこの関数をビヘイビアに設定する
ビヘイビアの設定の一番下にある関数の関連付けのビューワーリクエストに先ほど作成した関数を紐付ける
![スクリーンショット 2023-06-16 22.15.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3476743/35aa5d20-0fa6-e008-c590-1986723606ab.png)

これでCloudFront経由でアクセスがきた場合にindex.htmlに自動的に　ルーティングされるようになり、https://example.com/blog/0001 にアクセスした場合も https://example.com/blog/0001/index.html の内容が表示されるようになる。
RubyでAtCoder ABC241(A, B, C)を解いてみた

# はじめに
Webエンジニアを目指して、RubyやRailsをいじってます。
今回は、RubyでAtCoder ABC241のA, B, Cを解きました。備忘録として解き方をまとめていきたいと思います。

# A - Digit Machine
https://atcoder.jp/contests/abc241/tasks/abc241_a
```ruby:a-241.rb
a = gets.split.map(&:to_i)
puts a[a[a[0]]]
```

# B - Pasta
https://atcoder.jp/contests/abc241/tasks/abc241_b
```ruby:b-241.rb
# 修正前
gets.split
a = gets.split.tally
b = gets.split.tally

b.keys.each do |length_of_pasta|
  if !a[length_of_pasta] || b[length_of_pasta] > a[length_of_pasta]
    puts "No"
    exit
  end
end
puts "Yes"
```
```ruby:b-241.rb
# 修正後
gets.split
a = gets.split.tally
a.default = 0
b = gets.split.tally

puts b.keys.all?{ b[_1] <= a[_1] } ? "Yes" : "No"
```
## 解説
`tally`メソッドを使ってA, Bそれぞれの長さのパスタがいくつあるかを保持させます。そして、Bの要素である各長さのパスタを食べることができるかを調べることで、高橋君が最後まで食事計画を実行することができるかどうかを判定することができます。

# C - Connect 6
https://atcoder.jp/contests/abc241/tasks/abc241_c
```diff_ruby:c-241.rb
n = gets.to_i
array = Array.new(n){ gets.chomp.chars.map{ |x| x == "#" } }

dy = [1, 0, 1, -1]
dx = [0, 1, 1, 1]
n.times do |i|
  n.times do |j|
    4.times do |k|
-     next unless i + dy[k] * 5 < n && 0 <= i + dy[k] * 5 && j + dx[k] * 5 < n
+     next unless (i + dy[k] * 5 < n) && (0 <= i + dy[k] * 5) && (j + dx[k] * 5 < n)
      # 以下でも可
      # next unless (i + dy[k] * 5).between?(0, n - 1) && (j + dx[k] * 5 < n)
      # next unless (0...n).cover?(i + dy[k] * 5) && j + dx[k] * 5 < n
      count = 0
      6.times do |l|
        count += 1 if array[i + dy[k] * l][j + dx[k] * l]
      end
      if 4 <= count
        puts "Yes"
        exit
      end
    end
  end
end
puts "No"
```
## 解説
Nが1000以下と小さいので、縦・横・斜め方向のそれぞれについて全探索することで、`#`が6つ以上連続するようにできるかどうかを判定することができます。

https://qiita.com/shoya15/items/50fd17e37d7c64f2b166
GitHub Actionsで静的ジェネレートした時に環境変数を使う

# 課題
Nuxt.js+S3+CloudFrontを使ったJamstackなWebサイトで、変更があった場合に自動的に静的出力とS3への配置、キャッシュの更新が実行されるようにGitHub Actionsを使っている。
その時に.envで定義している環境変数が必要になるので、それを渡せるようにしたい。

# 手順・実装内容

まずGitHubに環境変数を登録する。
該当のリポジトリでSettings > secrets and variables > Actionsと進んで設定を行う。
![スクリーンショット 2023-06-16 21.49.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3476743/f2902f50-b138-9b40-78d4-6a6dbb6398c0.png)

次にGitHub Actionsの設定ファイルに環境変数として先ほど登録したsecretsを使うように設定を行う

```yml
- name: Build
        run: |
          npm install 
          npm run generate
        env:
          MICRO_CMS_API_KEY: ${{ secrets.MICRO_CMS_API_KEY }}
          MICRO_CMS_API_ROOT: ${{ secrets.MICRO_CMS_API_ROOT }}
```
これで環境変数にsecretsで登録した内容が使われるようになる。

ymlファイルに直接記述した場合に公開レポジトリだと大事な情報が漏洩する可能性があるが、上記方法であれば公開リポジトリでも問題なく公開ができる。
Proxyサーバ経由のBox接続（box-java-sdk使用）の開発環境

### はじめに
プロキシサーバ経由でBoxにファイルアップロードする環境をローカルPCに構築しようとした。
Boxへのファイルアップロードは、box-java-sdkを用いたJavのクライアントプログラム。
プロキシは、goproxyを使用した。

goproxyは以下のとおりに構築した。

https://qiita.com/nasum/items/1adc83c66489d2ddd426


### 環境
* Windowss 10
* CentOS 9 Stream(docker)
* Java8
* box-java-sdk 4.1.2
* go 1.20.4

### Proxyサーバ設定
モジュールインストール後、Proxyのコードは一番簡単そうなサンプルをそのまま使用した。
```go
package main

import (
    "github.com/elazarl/goproxy"
    "log"
    "net/http"
)

func main() {
    proxy := goproxy.NewProxyHttpServer()
    proxy.Verbose = true
    log.Fatal(http.ListenAndServe(":8080", proxy))
}
```

Windowsの設定から手動プロキシを設定後、ブラウザから外部にアクセスしてログが出力されることを確認した。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1284235/4004a65c-b67b-9135-5e38-b4906fed0c18.png)

### Box接続部分のコード

JWT認証を使用。
BoxConfigに読み込んでいるのは、Boxアプリケーションを作成してダウンロードしたjsonファイル。java.net.Proxyを生成してBoxAPIConnectionにセットした。

【Proxyの設定部分】
```java
        	private BoxAPIConnection boxApi;
    		BoxConfig config = BoxConfig.readFrom(reader);
            // リリースした環境では、configのみ渡すとハングアップした。
			//boxApi = BoxDeveloperEditionAPIConnection.getAppEnterpriseConnection(config); 
    		boxApi = new BoxDeveloperEditionAPIConnection(config.getEnterpriseId()
					,DeveloperEditionEntityType.ENTERPRISE
					,config.getClientId()
					,config.getClientSecret()
					,config.getJWTEncryptionPreferences());
	
			Proxy proxy = null;
			try {
				proxy = new Proxy(Proxy.Type.HTTP,
							new InetSocketAddress(InetAddress.getByName("127.0.0.1"), 8080));
					
			} catch (UnknownHostException e) {
				LOG.error("UnKnownHostException: {}", e.getMessage());
				e.printStackTrace();
			}

			boxApi.setProxy(proxy);
     ((BoxDeveloperEditionAPIConnection)boxApi).authenticate();
			LOG.info("BOX Connection ClientID： {}", boxApi.getClientID());
```

動作確認してみたが、最初のコネクション取得時に一回ログが出るが、それ以降は出力されない。。。
```bash
2023/06/16 09:15:46 [001] INFO: Running 0 CONNECT handlers
2023/06/16 09:15:46 [001] INFO: Accepting CONNECT to api.box.com:443
```
tinymce6 いろいろあって頭の<p>タグとおしりの</p>タグを取りたい

なんでそんなことしたいねん、という話ではあるが……。

## 理由
tinymce6になってから、必ず編集後にpタグが入るようになった。
DBに入れるときに普通に邪魔なのでpタグが取りたい。
ただし普通に文中にあるpタグは残したい。
どうしたらよいか。


## 結論
いろいろissueとか読んだけど絶対にpタグは入るらしいので、無理やり取る

```TypeScript
const deleteItem = (
  stringList: string[],
  deleteString: string,
  isBack: boolean
): string[] => {
  const loopStrings = isBack ? [...stringList].reverse() : stringList;
  const loop = (list: string[], inspected: string[]): string[] => {
    if (isEmpty(list)) return inspected;
    const [head, ...tail] = list;
    if (head !== deleteString) return loop(tail, [...inspected, head ?? ""]);
    return [...inspected, ...tail];
  };
  const result = loop(loopStrings, []);
  return isBack ? result.reverse() : result;
};
```
これは再帰で文字を消すだけの関数でござる。
引数によって前からも後ろからも消せるでござる。


```TypeScript
const deleteP = (stringList: string[]): string[] => {
  const delFirstP = deleteItem(stringList, "<p>", false);
  const delEndP = deleteItem(delFirstP, "</p>", true);
  return delEndP;
};
```
べつに関数にまとめるほどでもないがまとめてみたでござる。

```TypeScript
  // tinyMCEからtextという変数に値を入れている
  const regex = /(<\/?[a-z]*>)/g;
  const parsed = text
    .trim()
    .split(regex)
  const deleted = deleteP(parsed);
```
こんな感じでtinyMCEから取得したtextをうまいことパースしてpタグの頭とおしりを消すことに成功したのだった。

しかし、もうちょっとスマートなやり方があるんじゃないかなぁ、といつも思う。
普通に文字をstring[]にしてfindかなんかで消したらよかったのでは……？

なんだかもうちょっと簡単に書けるような……。
もっともっときれいにソースコード書けるようになりたいなぁ……。
microCMSで投稿した画像をS3にも保存する

# 課題
microCMS+Nuxt.js+S3+CloudFrontの構成ででJamstackなWebサイトを構築している中で、microCMSから投稿した画像などのメディアファイルについてもS3でファイルを保管して、CloudFrontでCDN配信できるようにすることでより高速な表示ができるWebサイトを構築したい

# 考えた方法

microCMSのメディア投稿にはwebhookの機能がついており、メディアを追加/変更/削除した時にその内容をAPI経由で受け取ることができる。
そこで、webhookで受け取った情報を元にS3にファイルを保存するAPIをAPIGateway+Lambdaで作ることにした。

# 手順・実装内容

まずはLambda関数を作成した。

``` Python
import boto3
from urllib.request import urlopen

# microCMSでメディアが追加/更新/削除されたらS3にも反映する
def lambda_handler(event, context):
    # バケット名,オブジェクト名
    s3 = boto3.resource('s3')
    bucket = s3.Bucket('YOUR-BUCKET-NAME')

    if event['type'] == 'new':
        # S3に画像をアップロード
        url = event['new']['url']
        s3_path = url.replace('https://images.microcms-assets.io/', '')       
        bucket.upload_fileobj(urlopen(url), s3_path)
    elif event['type'] == 'edit':
        # 古いファイルを削除
        old_url = event['old']['url']
        old_s3_path = old_url.replace('https://images.microcms-assets.io/', '')
        bucket.Object(old_s3_path).delete()

        # 新しいファイルをアップロード
        new_url = event['new']['url']
        new_s3_path = new_url.replace('https://images.microcms-assets.io/', '')
        bucket.upload_fileobj(urlopen(new_url), new_s3_path)
    elif event['type'] == 'delete':
        # S3から画像を削除
        url = event['old']['url']
        s3_path = url.replace('https://images.microcms-assets.io/', '')
        bucket.Object(s3_path).delete()

    # JSONを返す
    return {
        "statusCode": 200,
    }
```
APIから通知された内容に応じてそれぞれ保存、差し替え、削除をするだけ。
「https://images.microcms-assets.io/」 より下の部分にはID的なものが２種類入った後にファイル名がくる形式で、これをS3上でもそのまま使うことで同名のファイルでも保存できるようにするとともに、microCMSとの紐付けを別途持たなくてもいいようにした。

次にこのLambda関数を使うAPIGatewayを作成する。
webhookはPOSTで送信されるのでAPIもPOSTにしておくこと。
（作業手順に特殊な部分ないので割愛）

あとはmicroCMSのメディア管理 > メディア設定 > webhookに作成したAPIのURLを記載すればメディアが追加/変更/削除されるたびにAPIが起動され、S3と同期される。

![スクリーンショット 2023-06-16 21.26.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3476743/66877e9e-31db-701e-185e-aab4b6ae2b75.png)
え？！WSL2のホストOSって変えれるの？！じゃあAmazon Linuxにしなくっちゃ！！

**Amazon Linux 2023大好き！！**

## 手順

1. Amazon Linux 2023コンテナを起動する

    ```shell:shell
    docker run amazonlinux:2023
    ```
    ```
    Unable to find image 'amazonlinux:2023' locally
    2023: Pulling from library/amazonlinux
    91bcc9cfee80: Pull complete 
    Digest: sha256:ba9b575c9c9df3b4b7be350adf5db26bd7cee4aa5e826c6b9d0f40a26d002435
    Status: Downloaded newer image for amazonlinux:2023
    ```

1. 起動したコンテナIDを取得する

    ```shell:shell
    docker ps -lq
    ```
    ```
    f3ac9bc8339d
    ```

1. コンテナイメージをエクスポートする

    ```shell:shell
    docker export -o wsl.tar f3ac9bc8339d
    ```

    `wsl.tar`が出力されます。

1. デスクトップに`amazonlinux`フォルダーを作成する

    ```powershell:PowerShell
    mkdir $ENV:USERPROFILE\Desktop\amazonlinux
    ```

1. `wsl.tar`を`amazonlinux`フォルダーに格納する

1. WSL2にインポートする

    ```powershell:PowerShell
    wsl --import amazonlinux $ENV:USERPROFILE\Desktop\amazonlinux\ $ENV:USERPROFILE\Desktop\amazonlinux\wsl.tar
    ```

    | 項目 | 設定値 | 説明 |
    | --- | --- | --- |
    | \<Distro\> | amazonlinux | WSL2に登録するディストリビューション名 |
    | \<InstallLocation\> | $ENV:USERPROFILE\Desktop\amazonlinux\  | vhdxファイルが作成されるフォルダー |
    | \<FileName\> | $ENV:USERPROFILE\Desktop\amazonlinux\wsl.tar | インポートするイメージ |

**かんたん！**

## 起動

WSL2でディストリビューションを指定して起動します。

```powershell:PowerShell
wsl -d amazonlinux
```

OSの種類を確認します。

```shell:shell
cat /etc/os-release
```
```
NAME="Amazon Linux"
VERSION="2023"
ID="amzn"
ID_LIKE="fedora"
VERSION_ID="2023"
PLATFORM_ID="platform:al2023"
PRETTY_NAME="Amazon Linux 2023"
ANSI_COLOR="0;33"
CPE_NAME="cpe:2.3:o:amazon:amazon_linux:2023"
HOME_URL="https://aws.amazon.com/linux/"
BUG_REPORT_URL="https://github.com/amazonlinux/amazon-linux-2023"
SUPPORT_END="2028-03-01"
```

**Amazon Linux 2023！！**

やったぜ

## よりAL2023っぽくする

ユーザーはやっぱり`ec2-user`じゃないとね！
sudoして使う感じを再現します。

```shell:shell
dnf install shadow-utils sudo -y
```
```shell:shell
adduser ec2-user
```
```shell:shell
echo "ec2-user ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers
```
```shell:shell
cat << EOF >> /etc/wsl.conf
[user]
default=ec2-user
EOF
```

一度ログアウトしてWSL2を一度シャットダウンします。

```powershell:PowerShell
wsl --shutdown
```

再度WSL2にログインするとec2-user

```powershell:PowerShell
wsl -d amazonlinux
```

id確認

```shell:shell
id
```
```
uid=1000(ec2-user) gid=1000(ec2-user) groups=1000(ec2-user)
```

**やっほーい！！**

## おまけ：例のやつを表示させる

例のアレ、出したいですよね。（アレですよ、アレ）

```shell
sudo dnf install update-motd
```

アレとは？

```shell
cat /lib/motd.d/30-banner
```
```
   ,     #_
   ~\_  ####_        Amazon Linux 2023
  ~~  \_#####\
  ~~     \###|
  ~~       \#/ ___   https://aws.amazon.com/linux/amazon-linux-2023
   ~~       V~' '->
    ~~~         /
      ~~._.   _/
         _/ _/
       _/m/'
```

**!!**

こうしておけばログインするたびに表示できます！

```shell
echo 'cat /lib/motd.d/30-banner' >> ~/.bashrc
```

ロングバージョンも書きました。

https://moritalous.pages.dev/2123b0e5faf9ed8e7a71


## 参考

https://learn.microsoft.com/ja-jp/windows/wsl/use-custom-distro
Spring Boot Controller編

# Spring Bootのコントローラークラスについて
本記事は，Spring Bootのコントローラーについて，主な役割や基本的な記述方法について説明する．
「Spring Boot」とは何かについては，以下の記事にまとめたのでそちらを参照してください．

https://qiita.com/thirai67/items/0944561dd46da84abdfa

# 主な役割
コントローラークラスの役割を簡単に説明すると，<ins>クライアントからのリクエストを受け取り，適切な処理を実行してレスポンスを返すこと</ins>である．
コントローラークラスに，処理内容とその処理を呼ぶためのURLを記述することによって，クライアント(Webブラウザなど)はそのURLをリクエストとして送ることによって，対応した処理の結果を受け取ることができる．

# 基本的な記述方法
コントローラークラスを作成するために以下の３つを記述する．
１．Controllerアノテーション
２．Mappingアノテーション
３．処理内容
それぞれについてもう少し詳しく説明する．

```Java
//例
@Controller // <= Controllerアノテーション
public class HelloController {
    @RequestMapping(value = "/hello") //　<= Mappingアノテーション
    public String hello(){
        return "Hello, World"; // <= 処理内容
    }
}
```

## １．Controllerアノテーション
クラスに``@Controller``または``@RestController``というアノテーションを付与する．そうすることで，Spring Bootはそのクラスをコントローラーとして認識するようになる．

**``@Controller``と``@RestController``の違い**
この２つはコントローラーの機能として記述したメソッドがリクエストを受けた際に返すものが異なる．

１．RestControllerアノテーション
```Java
@RestController
public class HelloRestController {
    @GetMapping("/hello")
    public String hello(){
        return "Hello, World"; //文字列を返す
    }
}
```
``@RestController``は<font color="Red">JSON</font>や<font color="Red">XML</font>を返す．例のように，文字列を返すこともできるし，オブジェクトを返すこともできる．

２．Contollerアノテーション
```Java
@RestController
public class HelloController {
    @GetMapping("/hello")
    public String hello(){
        return "hello"; //hello.htmlを返す
    }
}
```
画面遷移用で，戻り値は遷移先の<font color="Blue">HTMLのファイル名</font>を返す．上記の例では，"hello.html"に遷移する．

## ２．Mappingアノテーション
Mappinngアノテーションをクラスやメソッドに付与することで，マッピングすることができる．そもそもマッピングとは，<ins>HTMLのフォームリクエストとそれに対する処理をつなげること</ins>で，ビューの特定の処理によって提供する処理を分けることができる．

### 基本的なMappingアノテーション
**１．HTTPリクエストに対応するMappingアノテーション**
Spring Bootには，以下のようなHTTPリクエストに対応するアノテーションが用意されている．
|アノテーション|HTTPリクエスト|役割|
|:--:|:--:|:--:|
|``@GetMapping``|GET|データの取得|
|``@PostMapping``|POST|データの変更(主に新規データの作成)|
|``@PutMapping``|PUT|データの変更（主に既存データの更新）|
|``@DeleteMapping``|DELETE|データの削除|

このようなHTTPリクエスト応じた使い分けをすることで，HTTPメソッドを作成することができる．

**２．RequestMappingアノテーション**
``@RequestMapping``はHTTPメソッドを限定しないでマッピングすることができる．１つのメソッドに対して，複数のHTTPメソッドを実装できる(例えば，GetMappingとPostMappingなど)．

<使用する属性>
それぞれのアノテーションには，以下のように属性を指定することでマッピングを限定する．
```Java
@RequestMapping(value = "/hello", method = RequestMethod.GET)
String hello(){
    //処理
}
```
* Value属性
メソッドを紐づける<ins>URLパス</ins>を指定する属性．
* Method属性
GET，POSTなどの<ins>HTTPリクエスト</ins>を指定する属性．

## ３．記述する主な処理
それぞれのアノテーションを記述した後は，実際に行う処理をメソッド内に記述する．記述する内容としては以下の５つの機能で構成する．

**１．リダイレクト処理**
リダイレクトは処理の結果や条件に応じて別のURLにユーザを転送する機能
**２．ビュー(HTMLテンプレート)との連携**
ビューとなるHTMLにデータを渡す機能
**３．モデルの更新**
フォームから受け取ったデータで，データベースなどを更新する機能
**４．ビジネスロックの実行**
アプリケーションとしてのコアとなる処理を実行する機能
**５．エラー処理**
フォームのデータ処理中にエラーが発生した場合，エラーに対して適切な処理を行う機能

# 参考
https://qiita.com/TEBASAKI/items/267c261db17f178e33eb
Java Spring Boot

# Spring Frameworkとは
<font color="Yellowgreen">Spring Boot</font>より先に，よく似た言葉である<font color="Green">Spring Framework</font>について説明する．

**○Spring Frameworkとは**
<font color="Green">Spring Framework</font>とは，企業レベルのJavaアプリケーションの開発するための包括的なオープンソースのフレームワークであり，特にWebアプリケーションの開発に必要となるさまざまな機能を提供している．JavaのWebアプリケーション開発の標準となっていて，Javaのフレームワークの"集合体"ともいうことができる．

**○Spring Frameworkの欠点**
<font color="Green">Spring Framework</font>はさまざまな機能が提供されている反面で，<ins>機能が多すぎる，設定が複雑，環境構築に手間と時間が掛かる</ins>といった，簡単なWebアプリケーションを作るのには少し使いづらいという欠点がある．

# SpringBootとは
<font color="Yellowgreen">Spring Boot</font>は先ほど挙げた欠点を解消するために，<font color="Green">Spring Framework</font>の一部の機能を取り出して作られたフレームワークである．つまり，<font color="Yellowgreen">Spring Boot</font>は<font color="Green">Spring Framework</font>を，より簡単にWebアプリケーションを作れるようにしたものであると言える．

# SpringBootのMVC
<font color="Yellowgreen">Spring Boot</font>はSpring MVCというMVCモデルを構築する別のフレームワークを含んでいるので，MVCモデルのWebアプリケーションの開発を行うことができる．

Spring Bootを使わずにMVCモデルを構築する場合は，ServletやJSP，Java Beansなどの技術を利用することでMVCモデルを構築する．Spring Bootは，MVCモデルをサポートするための機能を提供しており，これらの技術を利用しなくてもMVCモデルの実装を簡素化することができる．

このように，Spring BootはMVCを提供しているため，フロントエンドとバックエンドの両方の実装ができる．しかし，Spring bootのフロントエンド機能はあくまで限定的である．ReactやAngularなどのフロントエンドフレームワークと組み合わせることによって，より複雑なアプリケーションの構築が可能である．

# Spring Bootアプリケーションのプロジェクト作成
ここでは，EclipseでSpring Bootアプリケーションを作成する方法について説明する．
（開発環境はMacOS を使用．）

**０．Java(JDK)とEclipse(IDE)をインストール**
環境構築として，Eclipse上でJavaの開発が行えるようにする．

**１．Spring Tool Suite(STS)のインストール**
Spring Tool Suite(STS)はEclipseでSpringのフレームワークを利用するための拡張機能である．これをEclipseにインストールすることで簡単にSpring Bootアプリケーションを開発することができる．

〜以下からプロジェクトの作成〜

**２．ファイル→新規→Springスタータープロジェクト(Spring Initializr)を選択**
![sp1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3133563/0e52512e-4580-5a46-7c88-b77aef1a4157.png)

**３．Spring Bootプロジェクトの基本設定**
![sp2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3133563/1a0adbde-1467-7390-4f91-b0473f17b928.png)
* サービスURL
参照するプロジェクトの初期化ツールまたはリソースの参照先を指定する．
初期値には``https://start.spring.io``が指定されており，これは「Spring Initializr」というウェブサイトにアクセスし，プロジェクトの初期設定を行ってくれる．（基本的にそのままでいい）

* 名前
プロジェクトの名前を指定する．

* タイプ
Javaプロジェクトの依存関係管理やビルド自動化を行うためのビルドツールを指定する．"Maven"か"Gradle"を選択できる．

* Javaのバージョン
開発に利用するJavaのバージョンを指定する．インストールしているJavaを選択する．

* パッケージング
プロジェクトの実行・配布する際の方式を指定する．"Jar"または"War"を指定できるが，Webアプリなら"War"選ぶ．

* 言語
開発に利用するプログラム言語を指定する．

**４．　依存関係の設定**
![sp3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3133563/51868ae8-897a-40b2-a3a0-e3107221c8be.png)
以下の２つを指定して，完了でプロジェクトの作成が完了する．

* Spring Bootバージョン
利用するSpring Bootフレームワークのバージョンを指定する．

* 使用する機能の設定
Spring Bootが提供している機能から実際に利用するものを選ぶ．

上記の２つに関しては，ビルドツールのファイルに記入すれば変更可能．
（Maven→pom.xml，Gradle→build.gradle）

# MVCの記述方法
Spring Bootを利用したMVCについて，それぞれの記述方法は別の記事にまとめました．

https://qiita.com/thirai67/items/cf82fded0c4c3485aa7c

https://qiita.com/thirai67/items/a99623ec536ed024baf3

https://qiita.com/thirai67/items/a805e7bf90e92c7eee3f
【Unity】Opaqueなマテリアルをランタイム上でTransparentに変更する

# はじめに
ランタイム上で不透明なマテリアルを半透明に切り替える方法についてメモを残します。

# スクリプト
```cs:
// ベースシェーダのサーフェスタイプを透明に設定
material.SetFloat("_Surface", 1);

// デフォルトのレンダータイプタグを 'Transparent' に上書き
material.SetOverrideTag("RenderType", "Transparent");

// マテリアルのレンダーキューを透明に設定
material.renderQueue = (int)RenderQueue.Transparent;

// ソースブレンドを SrcAlpha に設定
material.SetInt("_SrcBlend", (int)BlendMode.SrcAlpha);

// ディスティネーションブレンドを OneMinusSrcAlpha に設定
material.SetInt("_DstBlend", (int)BlendMode.OneMinusSrcAlpha);

// Zライトを 0 に設定
material.SetInt("_ZWrite", 0);

// アルファテスト無効
material.DisableKeyword("_ALPHATEST_ON");

// アルファブレンド有効
material.EnableKeyword("_ALPHABLEND_ON");

// アルファプレマルチプライ無効
material.DisableKeyword("_ALPHAPREMULTIPLY_ON");

// マテリアルの色を取得
var color = material.color;

// 色のアルファ値設定
color.a = アルファ値(0〜1f);

// マテリアル色更新
material.color = color;
```
私が経験した、PCが起動しない「信じられない原因」

# はじめに
自作PCとか長年やってると勘と経験が身についてきますが、たまに経験したことのない「信じられない原因」でPCが起動しないことがあります。備忘録も兼ねて以下に書いていきます。（順次追加していきます。）

## メモリが奥まで刺さっていない
「カチッ」っていうまで刺せば大丈夫だと思いますよね？
LGA775時代から自作してて初めて出会った、「カチッのさらに奥まで押し込まないとエラーを吐くマザボ。」
GIGABYTEのB550 Visionってやつですが、他のマザーボードでも同様の現象があるかもしれないので、指でぎゅっと押してみると案外メモリ周りのエラーが解決するかもです。

## ディスプレイ変換ケーブルを使っている
高校の文化祭、当時の環境は第四世代i5とGTX960でした。学校の部室で自作。モニターがアナログ入力だったのでhdmi to VGAを使って接続するとPOST画面すら出ず、ビープ音が鳴り響きました。
一時間ぐらい意味が分からなかったのですが、最終的にhdmiにネイティブで対応しているモニターだと起動しました。起動後に変換ケーブルを刺すと無事に使用できたので、おそらく初回ブート時に映像変換ケーブルは地雷っぽい感じなのでしょう。また一つ勉強になった出来事でした。

## CMOSのバッテリーが切れている
「CMOSのバッテリーって時刻とか設定情報を保存するだけなので別に無くても起動する」
ってのは定説っぽくて、実際ほとんどの環境だとCMOS電池なしでも起動するんですけど、稀にCMOS電池が切れたらBIOSすら立ち上がらなくなる機種も存在するようなので覚えておくといいかもしれません。
djangoのtemplateでformset.is_validがTrueでも、formset.errorsの結果が[{}, {}, {}]になる問題について 

# はじめに

djnagoに関する非常にピンポイントでマニアックな投稿ですが、「え？そんな挙動するの？」と驚いた & 調べても解決策があまり出てこなかったので、自分の頭の整理と、誰かのためになればと共有します。

よりよい可決策があるかもしれないので、もし何か知っている方がいれば教えてください！

# 何が問題か？

## こんな場合
- djangoを使っている
- djangoのformset, inline_formsetでフォームを作成している
- formsetのvalidationでエラーが出た場合に、特別な処理をしたい（if分岐の条件に入れたい）

## 想定していた値
- `{{ formset.errors }}` の値は `[]` （空のリスト）

## 実際の値
- `{{ formset.errors }}` の値は `[{}, {}, {}]` （空の辞書が入ったリスト）

   空の辞書の数は、formsetの数に対応している
   ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/925749/7884b4d4-a008-68b7-d659-8b173d63c09f.png)


## ダメなパターン
```django:template.html
{% if formset.errors %}
    # 任意の処理
{% endif %}
```
## ダメな理由
- is_validがTrueでも、リストは空でないため（上記のif条件の結果はTrueになり、フォームの中身に問題はないのに）エラー時の処理が実行される

## 解決策
- is_boundと組み合わせる。
```django:template.html
{% if formset.is_bound!=formset.errors %}
    # 任意の処理
{% endif %}
```
## 解決できた理由
- `is_bound`がTrueの時は、formsetに値が入っている
   formsetに値が入っている状態で
   - validationを通った場合（エラーがない場合）、`is_valid` は True
   - validationではじかれた場合（エラーがある場合）、`is_valid` は False
- `is_bound`がFalseの時は、formsetに値が入っていない
   formsetに値が入っていない状態で
   - `is_valid` は False

⇒ `is_bound` の値と、`is_valid` の値が **異なる場合**、 Validation エラーがあると定義できる


### 参考サイト
- stackoverflow
[django InlineFormsets errors reporting with formset error list being empty](https://stackoverflow.com/questions/49128304/django-inlineformsets-errors-reporting-with-formset-error-list-being-empty)
【SwiftUI】触覚フィードバックボタンを実装する

# はじめに
iOS17からSwiftUIの標準機能で触覚フィードバックが追加されました！

https://developer.apple.com/documentation/SwiftUI/View/sensoryFeedback(_:trigger:)

しかし、iOS16以下でも触覚フィードバックは使用したいです。
今回はiOS16以下でも簡単に触覚フィードバックを使用できる方法を記事にします。

# 実装
```swift:Haptics
import class UIKit.UIImpactFeedbackGenerator
import class UIKit.UINotificationFeedbackGenerator
import class UIKit.UISelectionFeedbackGenerator

public func playImpactHaptic(_ style: UIImpactFeedbackGenerator.FeedbackStyle) {
    let generator = UIImpactFeedbackGenerator(style: style)
    generator.impactOccurred()
}

public func playNotificationHaptic(_ type: UINotificationFeedbackGenerator.FeedbackType) {
    let generator = UINotificationFeedbackGenerator()
    generator.notificationOccurred(type)
}

public func playSelectionHaptic() {
    let generator = UISelectionFeedbackGenerator()
    generator.selectionChanged()
}

public enum Haptics {
    case impact(_ style: UIImpactFeedbackGenerator.FeedbackStyle)
    case notification(_ type: UINotificationFeedbackGenerator.FeedbackType)
    case selection
    
    public func play() {
        switch self {
        case let .impact(style):
            playImpactHaptic(style)
        case let .notification(type):
            playNotificationHaptic(type)
        case .selection:
            playSelectionHaptic()
        }
    }
}
```

```swift
import SwiftUI

public struct Button<T: View>: View {
    private let haptics: Haptics

    private let action: () -> Void
    
    private let label: () -> T
    
    public init(haptics: Haptics, action: @escaping () -> Void, label: @escaping () -> T) {
        self.haptics = haptics
        self.action = action
        self.label = label
    }

    public var body: some View {
        SwiftUI.Button {
            haptics.play()
            action()
        } label: {
            label()
        }
    }
}
```

# 使い方
### ボタンとして使う
```swift
import SwiftUI

struct ContentView: View {
    var body: some View {
        Button(haptics: .notification(.success)) {
            // action
        } label: {
            Text("ボタン")
        }
    }
}
```

### 関数で使う
```swift
import SwiftUI

struct ContentView: View {
    var body: some View {
        SwiftUI.Button {
            playImpactHaptic(.medium)
        } label: {
            Text("ボタン")
        }
    }
}
```

# おわり
今回使用したコードでライブラリを作成しました！

https://github.com/SNQ-2001/HapticsButtonSwiftUI
VSCode のターミナルでbashのキーバインディングを使えるように。

コマンドパレットから `keybindings.json` を開いて下記を追加。

```bash
    {
        "key": "ctrl+p",
        "command": "",
        "when": "terminalFocus"
    },
    {
        "key": "ctrl+e",
        "command": "",
        "when": "terminalFocus"
    },
    {
        "key": "ctrl+f",
        "command": "",
        "when": "terminalFocus"
    },
    {
        "key": "ctrl+k",
        "command": "",
        "when": "terminalFocus"
    }
```

ターミナルにフォーカスされているときのキーバインドをカラにしているのでbashのキーバインディングが使える。
コンピュータの基本構成と原理

# コンピュータの基本構成

コンピュータを構成する要素は5つあり、これを「5大装置」という。

以下がコンピュータの5大装置である。

- 入力装置
- 記憶装置
- 制御装置
- 演算装置
- 出力装置

### 入力装置
入力装置は、ユーザーや外部デバイスからの情報やデータをコンピュータに提供するための装置。キーボード、マウス、スキャナ、センサーなどが一般的な入力装置。

### 記憶装置
記憶装置は、データやプログラムを保存するための装置。主記憶装置(メモリ)と補助記憶装置(HDD、SSDなど)が含まれる。

### 制御装置
制御装置は、コンピュータの動作を制御し、各ブヒにゃ装置の協調動作を調整する。
命令のフェッチ、デコード、実行の制御を担当する。

### 演算装置
演算装置はコンピュータ内で算術演算や論理演算を行うための装置。数値の計算や論理的な操作を担当する。

### 出力装置
出力装置は、コンピュータからのデータや結果をユーザーや外部に表示や出力するための装置。ディスプレイ、プリンタ、スピーカーなどが一般的な出力装置。
コマンド自動実行ツール

# コマンド実行ツールの使い方

このツールは commands.txt ファイルに記述されたコマンドを順に実行します。コマンドとそれに関連する説明を#で区切って記述することができます。

## commands.txt の記述例

bash

```sh
echo 'コマンド 1'#コマンド1の説明
echo 'コマンド 2'#
vi hoge.txt#viエディタでhoge.txtを開く
```

このツールを実行すると、各コマンドの説明が表示された後に、そのコマンドを実行するかどうかの確認メッセージが表示されます。確認メッセージに対して y または Y を入力すると、該当のコマンドが実行されます。

s または S を入力すると、そのコマンドはスキップされ、次のコマンドに進みます。それ以外を入力すると、ツールは終了します。

説明がない場合はコマンドの末尾に#のみつけてください。


### execute.sh
```sh
# コマンドを格納する配列を初期化
commands=()
# commands.txt ファイルを一行ずつ読み込み、その内容を配列 commands に追加
while IFS= read -r line; do
  commands+=("$line")
done < commands.txt

# 配列 commands の各要素（コマンド）について処理
for cmd in "${commands[@]}"
do
    # 各コマンドから説明部分とコマンド部分を分離
    cmd_part=${cmd%%#*}
    explanation_part=${cmd#*#}

    # 説明部分が存在すれば表示
    if [ "$explanation_part" ]; then
        echo "※$explanation_part"
    fi

    # ユーザーに対しコマンドの実行確認メッセージを表示し、入力を待つ
    read -p "=====$cmd_part を実行しますか？(y/n/s)" -n 1 -r
    echo    # 改行

    if [[ $REPLY =~ ^[Yy]$ ]]   # 'Y' または 'y' が入力された場合
    then
        # コマンドを実行
        echo "=====$cmd_part 実行"
        eval $cmd_part
        echo    # 改行
    elif [[ $REPLY =~ ^[Ss]$ ]]   # 'S' または 's' が入力された場合
    then
        # 何もせずに次へ
        true
    else
        # 上記以外の入力がされた場合、スクリプトを終了
        echo "YySs以外が押された為、ツールを終了します"
        exit 1
    fi
done

```

### commands.txt
```
echo 'コマンド1'#
echo 'コマンド2'#
vi hoge.txt#hogehogeな内容を記入し、fugafugaな内容が記載されていれば消してください。
```

# ブログ
[個人のブログ](https://dev63.hatenablog.com/entry/2023/06/16/201421)にも書いてます。 

# 感想

作ったけど&&でコマンド繋ぐ方が普通に良くて使っていない。。
cmake command一覧

### 同階層にあるCMakeLists.txtを実行したい
```
cmake .
```
※この場合、ビルド物はバラバラ出てくる。


### 叩くCMakeLists.txtを指定する
```
cmake ../CMakeLists.txt
```

### ビルドの出力先を指定する
```
cmake -B ./build
```
WSL2 + docker を使っていると PC の容量が足りないよ！っていうときに見る記事

:::note info
※この記事は社内 wiki にあった記事を移植したものです！ところどころ古いものがありますがご了承ください
:::

docker の扱いを知らなくてこうなってしまったので、Ubuntu の容量を減らします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1748702/b9bc7f8a-ddc2-62c3-aa06-257f9a2a1587.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1748702/f7420ade-c397-6b14-a602-cc0f4ce38c72.png)

## Ubuntu の容量を減らす

```sh
# 必要なコンテナを保護する
docker compose up

# いったん確認
docker image ls -a
# ↓ どんどんつよくなる ↓
# dangling image を削除
docker image prune

# unused image を削除
docker image prune -a

# image と他を削除
docker system prune -a

# image と他と volume を削除
docker system prune -a --volumes

# はじめに立ち上げたコンテナを止める
docker compose down
```

各コマンドの詳細はここを参照 -> https://docs.docker.jp/config/pruning.html

`docker system prune -a --volumes` をするとこうなりました！笑っちゃいました。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1748702/560d9a29-66e8-ac9f-7d43-96dee8e23b3e.png" height="100">

----

## Windows から見た WSL の容量を減らす

さて、このコマンドで内部 (Ubuntu) をきれいにしても、外部 (Windows) から見た容量は変わりません。なので、Windows 側から見る容量を減らします。

まずは PowerShell を開きます。管理者権限が必要かも。

はじめに WSL をシャットダウン
```sh
wsl --shutdown
```

サイズ最適化

```sh
optimize-vhd -Path C:\Users\dareka\AppData\Local\Packages\CanonicalGroupLimited.Ubuntu20.04onWindows_79rhkp1fndgsc\LocalState\ext4.vhdx -Mode full
```

※ ここででてくるパスは、対象のディレクトリに行った後に、 [Shift] を押しながら右クリックをすると現れる [パスのコピー] という隠しコマンドを使うと楽に取得できます。

ここを参考にしました。

-> https://www.curict.com/item/f4/f46da60.html


`optimize-vhd` とやらができなければこちら。私はこちらでやりました。

:::note alert
ここで手順を間違えると最悪 WSL が使えなくなるのでご注意ください。
:::

```sh
diskpart
```

```sh
select vdisk file="C:\Users\dareka\AppData\Local\Packages\CanonicalGroupLimited.Ubuntu20.04onWindows_79rhkp1fndgsc\LocalState\ext4.vhdx"
attach vdisk readonly
compact vdisk
detach vdisk
exit
```

ちなみに、ファイルへのパスをコピーするときには Shift + 右クリックが便利です。メニューに「パスのコピー」がでてきます。


`diskpart` の操作はここを参考にしました。

-> https://qiita.com/siruku6/items/c91a40d460095013540d

## 結果

無事に容量を減らせました

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1748702/ea7ddf6f-c54a-1df5-5878-77c224ef95fb.png)


## 追記

社内でこのような話がありました。容量をさらにあけたい方はどうぞ。(抜粋します。)

----

`docker system prune -a --volumens` で容量をあける方法の記事がながれていましたが、どうもそれだけでは消えないようで、
↑のコマンドを実行しても、130Gほどのファイルが残っているようでした。

```sh
root@:/# du -sh  /var/lib/docker/

130G    var/lib/docker/
```

なので、

```sh
rm -rf /var/lib/docker/volumes/*
```

とやってみました。
そうしたら、99%までいってしまっていたストレージの使用容量が、

```sh
~$ df
Filesystem                1K-blocks     Used Available Use% Mounted on
udev                        8057676        0   8057676   0% /dev
tmpfs                       1624784     2276   1622508   1% /run
/dev/mapper/vgubuntu-root 242730404 78103552 152223960  34% /
tmpfs                       8123908   363636   7760272   5% /dev/shm
tmpfs                          5120        4      5116   1% /run/lock
tmpfs                       8123908        0   8123908   0% /sys/fs/cgroup
```

にまで戻りました。Dockerはゴミファイル( `docker system prune` とやっても消えないファイル)が大量に出るのでしょうか。

※消した後は docker の deamon を再起動してください。

```sh
sudo service docker start
```
【備忘録】AWS Batchのコンピューティング環境のAMIをアップグレード

# はじめに

https://docs.aws.amazon.com/ja_jp/batch/latest/userguide/al1-ami-deprecation.html
>AWS Batch2023 年 6 月 30 日 Amazon Linux AMI のサポートを終了します。Amazon Linux の標準サポートは、2020 年 12 月 31 日に終了しました。Amazon Linux のメンテナンスサポートは、2023 年 6 月 30 日に終了します。アマゾン Linux の詳細については、「アマゾン Linux end-of-life AMI の更新」を参照してください。 end-of-life

ということで、Amazon Linux AMIのサポート終了に伴い、AWS Batchのコンピューティング環境をアップグレードすることになったので備忘録的にアウトプットします。

# やったこと

コンピューティング環境を編集してのAMI更新ができなかったので、既存のリソースからJSONをコピーしてAWS CLIから作成しました。

```bash:例
aws batch create-compute-environment --cli-input-json file://batch-compute-environment.json
```

jsonでAMIの指定がない場合は、自動的にAmazon Linux 2のAMIで作成されます。


https://docs.aws.amazon.com/cli/latest/reference/batch/create-compute-environment.html#examples

:::note warn
`file://`は必須なので注意。
:::

あとは、ジョブキューのコンピューティング環境の指定を更新するくらいでした。

Cloud Formationで環境を構築しているのであれば、テンプレートのコンピューティング環境の名前(ComputeEnvironmentName)を変更してスタックの更新をすることでAMIのアップグレードができそうです。

以上です！

# おわりに
誰かの参考になれば嬉しいです。
Kotlin + Jackson (+@field:JsonProperty)のシリアライズで属性が複数出力されてしまう件

## 現象

次のような `data class` があったとする。
```kotlin: Foo.kt
data class Foo(
    @field:JsonProperty("iPhone")
    val iPhone: Boolean
)
```

これを Jackson を使用してシリアライズすると以下のようになる。
```json
{"iPhone":true,"iphone":true}
```

小文字1文字 + 大文字ではじまるプロパティの場合にこの挙動となる。

## 原因

(Jackson の中の方までは追っていないので、おそらくという感じですが)

`iPhone` のようなプロパティは、class ファイル上では(というか Java からは)、以下のようになる。
```java
public final class Foo {
    @JsonProperty
    private final boolean iPhone;
    public final boolean getIPhone() { ... };
}
```

getter の名称がプロパティ名の1文字目を大文字にしたものとなっている。
これ自体は `getiPhone` というメソッド名とされるよりも、まったく見やすいものなのでおかしくはない。


しかし、JavaBeans 仕様に従いプロパティ名が決定されると、この getter によるプロパティの名称は `iphone` となる。
これは`getURL()` のようなメソッドがあった場合に、そのプロパティ名が `uRL` となってしまわないように、先頭で連続する大文字はすべて小文字にする仕様となっているからだと思う(ちょっと正確には覚えていない)

このため、`iPhone` -> `getIPhone` -> `iphone` となり、Jackson は `iphone` という属性を出力する。

一方で `@field:JsonProperty("iPhone")` があるので、Jackson はこの指定にも従いフィールドを `iPhone` という属性で出力する。

ちなみに、Jackson は getter から導出されるプロパティ名から実際に値を持っているフィールドを、本来はちゃんと推測して関連付けているっぽいので、以下のようなプロパティの場合は2つ出たりしない。
```kotlin
@field:JsonProperty("bar")
val foo: String
```

また、通常であれば Jackson はフィールドを出力対象としていないので、`@field:JsonProperty` がなければ(あるいは `@get:JsonProperty` であれば)、やはり2つ出たりはしない。
```kotlin
data class Foo(
    val iPhone: Boolean // {"iphone":true} が出力される
)
```
```kotlin
data class Foo(
    @get:JsonProperty("iPhone") // {"iPhone":true} が出力される
    val iPhone: Boolean
)
```

## その他

OpenAPI Generator を使用して kotlin 用のコードを生成した場合に、この問題が発生した。

モデル生成(リクエストやレスポンスで使用する DTO)のテンプレートが、data class のプロパティに `@field:JsonProperty` を付けているので、そこが `@get:JsonProperty` だったら良かったのに……となった。
テンプレートを入れ替える方法もあるが、あまりカスタマイズ箇所を増やしたくなかったのもあって、プロパティ名の方を変えることで対処した。
コミットメッセージをGitHub Copilotに考えてもらう

## [Copilot.vim](https://github.com/github/copilot.vim) を使ってCLIからコミットする際に、コミットメッセージを補完してもらう。

基本的には、[Copilot.vim](https://github.com/github/copilot.vim)の`Getting started`に記載があるとおりに進める。

### 1. NeovimかVimか
> 1. Install Neovim or the latest patch of Vim (9.0.0185 or newer).

[Neovim](https://github.com/neovim/neovim)でいくか、[Vim](https://github.com/vim/vim)でいくか、お好きな方で。

 

### 2. Node.jsのインストール
>2. Install Node.js.

もしインストールしていなければ、[Node.js](https://nodejs.org/en/download)をインストールする。

 
### 3. copilot.vimのインストール
> Install github/copilot.vim using vim-plug, packer.nvim, or any other plugin manager. Or to install manually, run one of the following commands:

ご自身の環境に合うインストール方法で。
自分はNeovim, Linux/macOS なので↓
```
$ git clone https://github.com/github/copilot.vim.git \
  ~/.config/nvim/pack/github/start/copilot.vim
``` 

### 4. GitHub Copilotと連携する
Neovim/Vimを起動して、`:Copilot setup `
指示に従って連携していく。
`Copilot: Authenticated as GitHub user hogehoge` って表示されたらOK。
IDEとかで既に連携済みなら、↑が表示されると思う。

### 5. ファイルタイプの有効化
どうやらデフォルトではコミットメッセージやmarkdown等のファイル形式でのサジェストは無効化されているらしいので、設定ファイルで下記を有効化しておく。

ref. [Tips for using Github Copilot in Vim](https://codeinthehole.com/tips/vim-and-github-copilot/)

```
let g:copilot_filetypes = {
    \ 'gitcommit': v:true,
    \ 'markdown': v:true,
    \ 'yaml': v:true
    \ }
```

自分は設定ファイルは[Lua](https://neovim.io/doc/user/lua.html)で記述しているため、init.luaに↓を追記。

```init.lua
vim.g.copilot_filetypes = { markdown = true, gitcommit = true, yaml = true }
```
 

### 6. コミットする際はdiffも表示する
コミットメッセージテンプレートにdiffが表示されていた方がサジェストの精度が上がった印象。
コミットする際は、`-v`オプションを付けてあげた方が良さそう。

 
これで良い感じにコパ君が補完してくれる。はず。
![スクリーンショット 2023-06-16 9.25.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/539971/6c9af74a-3a06-19b6-71bd-8079eab1addf.png)
Java Servlet JSP JavaBeans

# 基本的な開発方法
Javaを利用したWebアプリケーション開発において，MVC(Model-View-Controller)モデルの開発が一般的である．JavaでのMVCモデル開発の方法として以下の２つが挙げられる．

**１．Servlet・JSP・JavaBeansを利用して開発**
MVCのControllerとして**Servlet**，Viewとして**JSP**，Modelとして**JavaBeans**を利用して開発を行う．

**２．SpringBootなどのフレームワークを利用して開発**
Javaにはさまざまなフレームワークがあり，それらを利用することでMVCモデルの開発を行う．
SpringBootに関しては以下の記事にまとめた．

https://qiita.com/thirai67/items/0944561dd46da84abdfa

この記事では，**１．Servlet・JSP・JavaBeansを利用して開発**についてまとめる．

# Servlet
**Servletとは**
ServletはHTTPリクエストの受け取りと処理，及びHTTPレスポンスの生成と送信を行うコンポーネント．Servletは<ins>Webコンテナ(サーブレットコンテナ)</ins>で実行される．

:::note warn
Webコンテナ(サーブレットコンテナ)とは
HTTPリクエストを受け取り，適切なサーブレットを実行し，HTTPレスポンスを生成してクライアントに送信する実行環境(ソフトウェア)のこと．
:::

**Servletの役割**
１．リクエストの受信
HTTPリクエストを受け取り，リクエストパラメータやヘッダなどの情報を取得する．
２．リクエストの処理
リクエストに基づいた特定の処理を実行する．データベースの操作，ビジネスロジックの実行，APIへのリクエスト送信なども含む．
３．レスポンスの生成
HTTPレスポンスを生成する．HTMLやXML，JSONなどのコンテンツ生成やJSPを利用して生成を行う．
４．レスポンスの送信
生成したレスポンスをクライアントに送信する．

# JSP
**JSPとは**
JSPは<font color="Green">J</font>ava<font color="Green">S</font>erver <font color="Green">P</font>ageの略で，動的なWebコンテンツを生成するため技術である．HTMLに独自のタグを利用することでJavaのコードを埋め込むことができ，動的なWebページを作ることができる．

**JSPの役割**
１．ビューの表示
先ほど説明した通り，JSPは動的なWebページを生成する．Javaコードを埋め込むことによって，条件分岐や繰り返し処理などの制御フローを記述することができる．
２．データの表示
JSPはサーバーサイド(Servlet)からのデータを受け取り，それをHTMLテンプレートに埋め込むことによって表示することができる．
３．ユーザーからの入力に対する処理
JSPはフォームを実装し，ユーザーからのフォーム入力を受け取る．入力データをサーバーサイド(Servlet)に送ることができる．

# JavaBeans
**JavaBeansとは**
Javaにおいて，データをひとつにまとめて格納するための部品化したクラスを作るための設計ルールのことである．クラスやライブラリとして提供されているものではなく，JavaBeansの設計ルールに従ってクラスを作成することで，**Bean**として扱うことができる．

**JavaBeansの役割**
１．データの保持
データを保持するためのフィールド(プロパティ)を提供する．ServletやJSPから受けとっらデータを一時的に格納することで，別のコンポーネントと共有することもできる．
２．データの変換処理
データの変換などを行うメソッドもJavaBeansで実装する．ServletやJSPからJavaBeansにデータを渡し，数値の計算，文字列の操作などの処理結果を返すことができる．
３．データのバリデーション
JavaBeansは受け取ったデータのバリデーションを行うことができる．ServletやJSPが受け取ったデータをJavaBeansに渡すことで，入力データが正しいかを検証することができる．


# 処理の流れ
クライアントからリクエストを受けると，Webサーバサイドでは以下のようなイメージで処理が行われる．

![スクリーンショット 2023-06-16 18.49.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3133563/1b9e95e8-046b-daec-c651-f1ef3b1c49d6.png)

１．HTTPリクエストを受け取り，リクエストパラメータなどの情報を取得する
２．取得したデータの保持や処理をJavaBeansに依頼する
３．保持しているデータやビジネスロジックなどの処理結果をServletに返す
４．ServletからJSPへデータを送り，動的なWebページを生成を依頼する
５．受け取ったデータとテンプレートから生成したwebページをServletに返す
６．HTTPレスポンスとしてクライアントに送信する

# それぞれについて
Servlet・JSP・JavaBeansの基本について以下のページにまとめた．

https://qiita.com/thirai67/items/7db0ccae7fa01eb95fb8

https://qiita.com/thirai67/items/7fcabde29b193ce25617

https://qiita.com/thirai67/items/0a1f56d496c84addfbf5
TripleDES暗号化： 開発者のための包括的なガイド

## TripleDES暗号化入門 

データセキュリティは、機密性の高いデータを扱う組織にとって最大の関心事である。暗号技術において、TripleDES または 3DES 暗号化は、DES (Data Encryption Standard) アルゴリズムを 3 回適用することにより、データのセキュリティを強化する一般的な技術である。この技術は、3つの異なる鍵を使用し、データを3段階で暗号化することで、単一のDESよりも安全な暗号化を実現します。

TripleDES暗号化は対称鍵アルゴリズムであり、送信者と受信者の両方が同じ秘密鍵を使用して暗号化および復号化を行うことを意味します。

## TripleDES 暗号化の仕組み

TripleDESは、DESアルゴリズムを用いて平文を3段階で暗号化します。このアルゴリズムは3つの鍵を使用し、最初のステージでは鍵1による暗号化を行い、次に鍵2による復号化を行い、鍵3による暗号化を行う。

TripleDES暗号化](/images/blog/screenshots/Tripledes%20Encryption.png)

TripleDESの動作は上の画像の通りです。第1段階では、平文を鍵1を使って暗号化し、暗号文を生成する。第2段階では、鍵2を用いて暗号文を復号化し、新たな暗号文を生成する。最後に、第3段階では、2番目の暗号文が鍵3を使って暗号化され、最終的にTripleDES暗号の結果である暗号文が生成されます。

または、He3 Toolbox の TripleDES Encryption ツール([https://t.he3app.com?t22y](https://t.he3app.com?t22y) )を利用することで、簡単に利用できます。

## TripleDES 暗号化の主な特徴

TripleDES暗号の主な特徴として、以下のようなものがあります：


| :------ | :---------- |
| セキュリティ｜TripleDES暗号は、データの保護を強化する非常に安全な技術です。|
| 対称鍵アルゴリズム｜TripleDES暗号は対称鍵アルゴリズムであるため、実装や使用が容易である。|
| DESを3回通過させることで、DES単体よりも安全な暗号化を実現します。|
| 複数の鍵｜TripleDESは、暗号化と復号化に3つの異なる鍵を使用し、安全性を高めています。|

## 開発者のためのTripleDES暗号化のシナリオ

TripleDES暗号は、データセキュリティの世界では様々な使用例があります。開発者は、金融アプリケーション、ヘルスケアアプリケーション、電子商取引アプリケーションなど、機密性の高いデータを扱うアプリケーションでデータを保護するためにこの技術を使用できます。

さらに、TripleDES は、安全でないネットワーク上での伝送やデータベースへの保存中のデータを保護するために使用することができます。開発者は、セキュアソケットレイヤー（SSL）またはトランスポートレイヤーセキュリティ（TLS）プロトコルを使用して、転送中のデータを保護するためにTripleDES暗号化を使用できます。

## TripleDES 暗号化に関する誤解

TripleDES暗号化には、いくつかの誤解があるので、それを解く必要があります。ここでは、そのうちのいくつかを紹介します：

### 誤解1：TripleDES暗号は時代遅れで安全でない。

TripleDES暗号は今でも広く使われており、暗号の分野では安全な技術だと考えられています。古い技術ではありますが、データを保護する上ではまだ適切で効果的です。

### 誤解2：TripleDES暗号は実装が複雑である。

TripleDES暗号は対称鍵アルゴリズムであり、実装が容易です。さらに、多くのプログラミング言語やライブラリでTripleDESアルゴリズムのサポートが組み込まれています。

## トリプルデス暗号化に関するFAQ

### Q1: TripleDES アルゴリズムはクラックされるのか？

TripleDESアルゴリズムは非常に安全であり、ブルートフォースやその他の類似の攻撃を除いて、暗号を解読することは困難です。

### Q2：TripleDESとAESの暗号化の主な違いは何ですか？

TripleDESとAESは、どちらも共通鍵暗号化アルゴリズムです。この2つのアルゴリズムの主な違いは、鍵の大きさです。AES は 128 ビットまたは 256 ビットの固定キーサイズを使用しますが、TripleDES は 128、192、256 ビットの可変キーサイズに対応しています。

## 結論

TripleDES 暗号化は、DES アルゴリズムを 3 回適用することで、データのセキュリティを強化する強力な技法です。機密性の高いデータを保護する必要がある様々なアプリケーションで広く使用されています。この記事では、TripleDES暗号化の概念と動作、主な特徴、使用シナリオ、誤解、およびFAQについて学びました。

参考文献
- TripleDES - Wikipedia](https://en.wikipedia.org/wiki/Triple_DES)
- TripleDES暗号の理解](https://www.geeksforgeeks.org/understanding-tripledes-encryption/)
- TripleDES暗号とは何か、どのように機能するのか](https://www.tutorialspoint.com/cryptography_with_python/cryptography_with_python_tripledes.htm)
メモ_アプリ開発に関する知識

・CRUD処理：
　データベースを使用して行う処理のこと。
　C...Create（作成）
　R...Read（読み取り）
　U...Update（更新）
　D...Delete（削除）

・MVCモデル
　アプリの機能を、Model、View、Controllerの3つに分割してそれぞれ処理を行うスタイル。
　MVCモデルを採用することで、役割分担をして開発を行うことができる。
　Model...データベースとやり取りをして処理を行う。
　View...ブラウザに表示する部分。
　Controller...Modelに行くかViewに行くか指示をする部分。
　ルーティング...指定したURLにアクセスした時にどんな処理をするか定義しておく。