OmniAICreator/Qiita-1.07M huggingface dataset:
robloxでassistant その124

# 概要
robloxでassistantやってみた。
練習問題やってみた。

# 練習問題
スクリプトだけで、ボタンでパーツを上下させよ。

# 手順
- ReplicatedFirstに、LocalScriptを追加。
- スクリプトを書く。

```

local Players = game:GetService("Players")
local Player = Players.LocalPlayer
local PlayerGui = Player:WaitForChild("PlayerGui")
local Gui = Instance.new("ScreenGui")
Gui.Parent = PlayerGui
local button0 = Instance.new("TextButton")
button0.AnchorPoint = Vector2.new(4, 0.9)
button0.Size = UDim2.new(0.05, 0, 0.1, 0)
button0.Position = UDim2.new(0.5, 0, 0.5, 0)
button0.Text = "up"
button0.Parent = Gui
local button1 = Instance.new("TextButton")
button1.AnchorPoint = Vector2.new(4, 0)
button1.Size = UDim2.new(0.05, 0, 0.1, 0)
button1.Position = UDim2.new(0.5, 0, 0.5, 0)
button1.Text = "down"
button1.Parent = Gui

wait(1)
local part = Instance.new("Part", workspace)
part.Anchored = false
part.Size = Vector3.new(1, 1, 1)
part.Position = Vector3.new(0, 5, 0)
local att = Instance.new("Attachment")
att.Parent = part
local LV = Instance.new("LinearVelocity")
LV.Attachment0 = att
LV.MaxForce = 10000
LV.VectorVelocity = Vector3.new(0, 0, 0)
LV.Parent = workspace

button0.MouseButton1Click:Connect(function()
	print("up")
	LV.VectorVelocity = Vector3.new(0, 1, 0)
end)
button1.MouseButton1Click:Connect(function()
	print("down")
	LV.VectorVelocity = Vector3.new(0, -1, 0)
end)




```



# 写真

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/ae58892a-9f26-de15-d759-1286282f8372.png)


以上。
【Docker Compose】複数の yaml ファイルをマージする

# はじめに
この記事では、Docker Compose で複数の yaml ファイルを利用する方法について記載します。

# 開発環境
開発環境は以下の通りです。

- Windows 11
- Docker Engine 26.1.1
- Docker Compose 2

# 複数ファイルの利用
`--file` オプションを使うと複数の yaml ファイルを利用することができます。

https://docs.docker.com/reference/cli/docker/compose/

## 上書き
以下のように複数の yaml ファイルが存在し、同一の定義がされている場合、後の yaml ファイルの定義が上書きされます。

```compose.yaml
services:
  app:
    environment:
      - DEBUG=true
    ports:
      - "${APP_HOST_MACHINE_PORT:-8000}:8000"
    volumes:
      - type: bind
        source: ./src
        target: /my-work
    build: ./docker/app
```

```compose-production.yaml
services:
  app:
    environment:
      - DEBUG=false
```

```powershell
docker compose --file compose.yaml --file compose-production.yaml config
```

`DBUG` のみ `compose-production.yaml` の定義通り `false` になり、それ以外は `compose.yaml` の定義になっています。

```powershell
services:
  app:
    build:
      context: C:\Users\ymori\Documents\GitHub\docker-mail-app\docker\app
      dockerfile: Dockerfile
    environment:
      DEBUG: "false"
    networks:
      default: null
    ports:
      - mode: ingress
        target: 8000
        published: "8000"
        protocol: tcp
    volumes:
      - type: bind
        source: C:\Users\ymori\Documents\GitHub\docker-mail-app\src
        target: /my-work
```

# 追記
定義の追記も可能です。

```compose.yaml
services:
  app:
    environment:
      - DEBUG=true
    ports:
      - "${APP_HOST_MACHINE_PORT:-8000}:8000"
    volumes:
      - type: bind
        source: ./src
        target: /my-work
    build: ./docker/app
```

```compose-ci.yam
services:
  proxy:
    image: 1.27.0
```

```powershell
docker compose --file compose.yaml --file compose-ci.yaml config
```

`compose.yaml` には含まれていない `proxy` サービスを確認できます。

```powershell
services:
  app:
    build:
      context: C:\Users\ymori\Documents\GitHub\docker-mail-app\docker\app
      dockerfile: Dockerfile
    environment:
      DEBUG: "true"
    networks:
      default: null
    ports:
      - mode: ingress
        target: 8000
        published: "8000"
        protocol: tcp
    volumes:
      - type: bind
        source: C:\Users\ymori\Documents\GitHub\docker-mail-app\src
        target: /my-work
  proxy:
    image: 1.27.0
    networks:
      default: null
```

# 参考
- [docker compose](https://docs.docker.com/reference/cli/docker/compose/)
- [	鈴木亮「開発系エンジニアのためのDocker絵とき入門」秀和システム、2024](https://www.shuwasystem.co.jp/book/9784798071503.html)
Docker環境が動かないときの要チェック事項

環境構築時のエラーはググってもサイトごとに言っていることが違います
チェック事項と解決方法をまとめました

## Dockerのログを見る
エラーをググって上手くいくこともあれば、うまくいかないこともあります

## http か　httpsかどうか
key error発生時
環境によってはhttpsでは接続できないことがあります
httpに変更してみるとうまくいくかもしれません

## IPアドレスかlocalhostかどうか
key error発生時
ここも動かない可能性のあるポイントです
URLを確かめましょう

## 検証タブのネットワークを見てレスポンスが帰ってきているかどうか
レスポンスが帰ってきていない場合、必要なコンテナが動いていない場合があります
docker-compose.ymlを見て確認しましょう

## 発生しているのがフロントかバックか
フロントで発生しているかバックで発生しているのか確認しましょう

## permissiondeny
権限エラーです。必要なファイルかどうかを見極めましょう。表示されているものとは違ったファイルが対象のこともあります。
chmodで対応しましょう

## cors
origin="*"
ではダメで、明示的に許可しないとうまくいかない場合があります

## 環境変数
変更漏れがないか確認しましょう




以上です
詰まったら追記します
環境構築はうまくいかないことだらけだし推測やネットワークの知識が必要だったり方法が見つからなかったりして心が折れやすくて、本当につらいです
一緒に頑張っていきましょう
GitHubをもっと活用！Draft Pull Requestの使い方ガイド

## 概要
GitHubのPull Request（以降PR）には通常のPRに加え、Draftというものがあります
これはまだ完成していない段階で作成・公開するための機能です
これにより開発者はPRを「ドラフト（下書き）」としてマークすることでコードレビューの準備ができていないことを明確に示すことができます

## 利点
- 透明性の向上
    - チームメンバーに現在の進捗状況を共有しやすくなります
- フィードバックの早期取得
    - コード完成前にレビューやフィードバックを受けやすくなります
- リスクヘッジ
    - 完成前のコードをマージされるリスクを回避できます

## Draft Pull Requestの作成手順
1. 新しいブランチを作成
    - コード変更を行うための新しいブランチを作成します
1. 変更をコミット
    - 必要なコード変更を行い、コミットします
1. Pull Requestを開始
    - GitHubリポジトリのページにアクセスし、`Pull requests`タブをクリックします
    - `New pull request`ボタンをクリックします
1. ブランチの選択
    - 変更をマージしたいブランチを選択します
1. Draftとして作成
    - `Create pull request`ボタンの横にあるドロップダウンメニューから`Create draft pull request`を選択します
    - 必要なタイトルと説明を入力し、`Create draft pull request`をクリックします

下記画像が具体例です（Revertのためのコミットなのでわかりにくいかもですが...）
![スクリーンショット 2024-07-11 9.40.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/282722/ee726ad7-1116-bcdb-9385-ab9d0957b4b8.png)

## Draftと通常のPullRequestの違い
Draftと通常のPullRequestの違いは下記の通りです

| 特徴             | Draft PR                          | 通常のPR                           |
|------------------|-----------------------------------|------------------------------------|
| 作成目的         | 下書き、フィードバックの取得       | コードのレビューとマージの準備が完了 |
| 自動マージ       | されない                          | 状況によりマージされる              |
| コメント機能     | 利用可能                          | 利用可能                           |
| 変換             | 通常のPRに変換可能                | そのままマージ可能                 |

## Draftから通常のPullRequestへの変換手順
1. DraftPRを開く
    - Github上で該当のDraft PRページを開きます
1. 変換オプションを選択
    - `Ready for review`ボタンをクリックします
1. 通常のPRとして扱われる
    - これでPRは通常のレビューおよびマージのプロセスに進むことができます

![スクリーンショット 2024-07-11 9.54.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/282722/58075e18-26cf-4866-aead-93e3887d277d.png)


## まとめ
GitHubのDraft機能は未完成のコードを共有し、フィードバックを得ることができます
この機能を利用することで、チーム内での透明性を高め、早期の段階で意見を収集することができます
Draft PRは、コードが完成していない段階でも共有できるため、長期プロジェクトや中間成果物の確認、複数人での協力作業に役立つことでしょう
UFW（Uncomplicated Firewall）を使ってLinuxのファイアウォールを設定する方法

## UFWのインストール

多くのLinuxディストリビューションにはUFWがデフォルトでインストールされているけど、インストールされていない場合は以下のコマンドでインストールする。

### Ubuntuでのインストール

```sh
sudo apt update
sudo apt install ufw
```

## UFWの基本コマンド

### UFWのステータス確認

UFWが有効かどうかを確認するには、以下のコマンドを実行する。

```sh
sudo ufw status
```

### UFWの有効化

UFWを有効にするには、以下のコマンドを実行する。

```sh
sudo ufw enable
```

### UFWの無効化

UFWを無効にするには、以下のコマンドを実行する。

```sh
sudo ufw disable
```

## ルールの設定

### ポートの許可

特定のポートへのアクセスを許可するには、以下のコマンドを実行する。ここではSSH（ポート22）を許可する例を示す。

```sh
sudo ufw allow 22/tcp
```

### ポートの拒否

特定のポートへのアクセスを拒否するには、以下のコマンドを実行する。ここではHTTP（ポート80）を拒否する例を示す。

```sh
sudo ufw deny 80/tcp
```

### アプリケーションプロファイルを使用した許可

UFWには事前定義されたアプリケーションプロファイルがある。これを使うと設定が簡単になる。例えば、`Nginx Full`というプロファイルを許可するには、以下のコマンドを実行する。

```sh
sudo ufw allow 'Nginx Full'
```

### 設定されているルールの確認

現在設定されているルールを確認するには、以下のコマンドを実行する。

```sh
sudo ufw status numbered
```

### ルールの削除

特定のルールを削除するには、まずルール番号を確認し、以下のコマンドを実行する。

```sh
sudo ufw delete <ルール番号>
```

## UFWのログ

### ログの有効化

UFWのログを有効にするには、以下のコマンドを実行する。

```sh
sudo ufw logging on
```

### ログの無効化

UFWのログを無効にするには、以下のコマンドを実行する。

```sh
sudo ufw logging off
```

## よく使うコマンドまとめ

- **UFWのステータス確認**:
  ```sh
  sudo ufw status
  ```

- **UFWの有効化**:
  ```sh
  sudo ufw enable
  ```

- **UFWの無効化**:
  ```sh
  sudo ufw disable
  ```

- **ポートの許可**:
  ```sh
  sudo ufw allow 22/tcp
  ```

- **ポートの拒否**:
  ```sh
  sudo ufw deny 80/tcp
  ```

- **アプリケーションプロファイルを使用した許可**:
  ```sh
  sudo ufw allow 'Nginx Full'
  ```

- **設定されているルールの確認**:
  ```sh
  sudo ufw status numbered
  ```

- **ルールの削除**:
  ```sh
  sudo ufw delete <ルール番号>
  ```

- **ログの有効化**:
  ```sh
  sudo ufw logging on
  ```

- **ログの無効化**:
  ```sh
  sudo ufw logging off
  ```
【OutSystems】【Forge】FullCalendar ReactiveのAdvancedOptionsについて

## 対象者
- ローコード開発ツール「OutSystems」を使用されている方
- OutSystemsでGoogleカレンダーやOutLookのようなものを実装したい方

## 前提
 - ForgeであるFullCalendar Reactiveを利用して実装しています。

## Forge：FullCalendar Reactiveとは

 - OutSystemsでは、「Forge」という部品のようなものがあり、
開発時間を大幅に短縮できる。FullCalendar Reactiveはその中のひとつ。

![無題.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3794537/dbf6a83d-5a1f-0ef2-4e53-10082d05b6c0.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3794537/29b4d86f-04d6-cd95-c223-0be5b616fa76.png)

## 基本操作
引数やStructureの使用方法などの基本操作は、demoアプリケーションを触ってみると分かりやすいかと思いますので、まずは[こちら](https://www.outsystems.com/forge/component-overview/7696/fullcalendar-reactive-o11)からダウンロードしてみましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3794537/6d4d4768-ad15-991c-364f-be14567d7080.png)

## 痒いところに手が届く「Advanced Options」
Advanced Optionsの使用例をご紹介します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3794537/1424da52-c310-e207-6453-0cc252960126.png)

 -  日本語化
     - before（英語表記）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3794537/0c9406fd-7f8f-5bcd-8bd5-f7793000cbe8.png)
     - after（日本語表記）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3794537/54e6f6b7-b4c8-dbcb-2e9d-192dd867d184.png)
 

 ```
allDayText:'終日',
buttonText: {
    today: '今日',
    month: '月単位',
    week: '週単位',
    day: '日単位'
},
locale:ja
```

 - 初期表示を月単位から週単位にする
     - before（初期表示「月単位」）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3794537/520c9845-a19e-c5aa-0159-25261f14cfb2.png)
     - after（初期表示「週単位」）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3794537/39c8c82b-23d1-b236-1c32-0079bbb6b877.png)

```
InitialView:timeGridWeek
```

 - スケジュールの時間表記を消す
     - before（時間表記あり）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3794537/335255b5-ef64-4fa1-dfea-1019460afc23.png)
     - after（時間表記なし）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3794537/2313e6c0-c39d-a7cd-d9f5-6e60d104ef23.png)
```
displayEventTime: false
```

 - 業務時間以外を灰色にする
     - before（業務時間指定なし）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3794537/62cce16e-9d6a-0973-2278-f40629967d4e.png)
     - after（業務時間指定あり）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3794537/98f45d25-0627-e4ec-ad80-a717a9f876f5.png)
```
businessHours: {
  daysOfWeek: [ 1, 2, 3, 4 ], // 1：月曜日～4：木曜日
  startTime: '10:00', // 開始時間
  endTime: '18:00', // 終了時間
}
```

 - 予定を重複して表示させないようにする
     - before（重複して表示）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3794537/4fb12c1b-6062-74ac-d0ab-fef53378e07a.png)
     - after（重複しないで表示）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3794537/0c62e6b3-c102-23a9-8db2-8691b963b419.png)
```
slotEventOverlap:false
```
## おわりに
 - 他にもこんな便利な設定あるよって方がいらっしゃれば、追記するのでコメントで教えてください！

## 参考文献
 - https://www.outsystems.com/forge/component-overview/7696/fullcalendar-reactive-o11

 - https://fullcalendar.io/docs
type-challenges 初級編4: Includes, Push, Unshift

# type-challenges 初級編4: Includes, Push, Unshift

## はじめに type-challengesとは

[GitHubのtype-challengesリポジトリ](https://github.com/type-challenges)は、TypeScript型システムの理解を深めるための型クイズ問題集です。高品質な型を作成することで、バグを減らし、プロジェクトの保守性を向上させることができます。今回も、初級編から3つの問題に挑戦します。

### 1. Includes

JavaScriptの`Array.includes`関数を型システムに実装します。この型は、2つの引数を受け取り、特定の要素が配列に含まれているかどうかを示す`true`または`false`を返します。

#### 例

```typescript
type isPillarMen = Includes<['Kars', 'Esidisi', 'Wamuu', 'Santana'], 'Dio'> // expected to be false
type isPillarMen2 = Includes<['Kars', 'Esidisi', 'Wamuu', 'Santana'], 'Wamuu'> // expected to be true
```

今回はこの問題の解き方が分からなかったため、答えを見ました。

```typescript
type Includes<T extends readonly any[], U> = T extends [infer First, ...infer Rest]
  ? Equal<First, U> extends true
    ? true
    : Includes<Rest, U>
  : false
```

#### 解説

- `T extends [infer First, ...infer Rest]` という条件型を使い、配列 `T` の最初の要素 `First` と残りの要素 `Rest` に分解します。
- `Equal<First, U> extends true` で `First` と `U` が等しいかどうかをチェックします。等しい場合は `true` を返し、そうでない場合は再帰的に `Includes<Rest, U>` を呼び出します。
- 配列が空になると `false` を返します。

この回答にrecommendedがついていました。再帰的に配列を探索していくこの処理、綺麗ですね

:::note warn
いや急に難しすぎるだろ...
:::


### 2. Push

`Array.push` の型バージョンを実装します。この型は、配列 `T` に要素 `U` を追加した新しい配列を返します。

#### 例

```typescript
type Result = Push<[1, 2], '3'> // expected to be [1, 2, '3']
```

#### 私の回答

```typescript
type Push<T extends Array<unknown>, U> = [...T, U]
```

#### 解き方

- `[...T, U]` というスプレッド構文を使い、配列 `T` の末尾に要素 `U` を追加します。

:::note info
簡単。
:::


### 3. Unshift

`Array.unshift` の型バージョンを実装します。この型は、配列 `T` の先頭に要素 `U` を追加した新しい配列を返します。

#### 例

```typescript
type Result = Unshift<[1, 2], 0> // expected to be [0, 1, 2]
```

#### 私の回答

```typescript
type Unshift<T extends Array<unknown>, U> = [U, ...T]
```

#### 解き方

- `[U, ...T]` というスプレッド構文を使い、配列 `T` の先頭に要素 `U` を追加します。

### まとめ

このように、TypeScriptの型システムを理解し、実際に型を実装することで、より安全で保守性の高いコードを書くことができます。特に、JavaScriptの標準的な配列操作を型システムで実装することで、より強力な型チェックを行うことができます。ぜひこれらの課題を解いて、型力UPしてみてください。

:::note info
今回はIncludesがレベチでした。
次回は中級編に入ります。
:::


### 参考記事

- [TypeScript公式ドキュメント](https://www.typescriptlang.org/docs/)
- [type-challenges GitHubリポジトリ](https://github.com/type-challenges/type-challenges)
【VBA】xlsxファイルを読み込むマクロ

指定したxlsxファイルを読み込み、その内容を「WORK」シートに貼り付けるVBAのコード例です。

```vba
Sub ImportExcelData()
    Dim ws As Worksheet
    Dim wbSource As Workbook
    Dim wsSource As Worksheet
    Dim lastRow As Long, lastCol As Long
    Dim sourceFilePath As String
    
    ' ソースファイルのパスを指定
    sourceFilePath = "C:\path\to\your\file.xlsx"
    
    ' ワークブックとシートの指定
    Set ws = ThisWorkbook.Sheets("WORK")
    
    ' ソースファイルを開く
    Set wbSource = Workbooks.Open(sourceFilePath)
    Set wsSource = wbSource.Sheets(1) ' 最初のシートを読み込む
    
    ' ソースシートの最終行と最終列を取得
    lastRow = wsSource.Cells(wsSource.Rows.Count, 1).End(xlUp).Row
    lastCol = wsSource.Cells(1, wsSource.Columns.Count).End(xlToLeft).Column
    
    ' ソースシートの内容をWORKシートにコピー
    wsSource.Range(wsSource.Cells(1, 1), wsSource.Cells(lastRow, lastCol)).Copy ws.Cells(1, 1)
    
    ' ソースファイルを閉じる
    wbSource.Close False
    
    MsgBox "データのインポートが完了しました。"
End Sub
```

このコードは、以下の手順で動作します。

1. ソースファイルのパスを指定します。
2. 現在のワークブックの「WORK」シートを指定します。
3. ソースファイルを開き、最初のシートを指定します。
4. ソースシートのデータ範囲を取得します（最終行と最終列を特定します）。
5. ソースシートの内容を「WORK」シートにコピーします。
6. ソースファイルを閉じます。
7. インポートが完了したことを知らせるメッセージボックスを表示します。

このコードをVBAエディタに貼り付けて実行することで、指定したxlsxファイルの内容を「WORK」シートに貼り付けることができます。
Agents for Amazon BedrockのMemory(Preview)を試してみた

最近Amazon Bedrockに入門してみました。
Agents for Amazon Bedrockを触っていたら、急にMemoryという項目が増えたので試してみました。

https://aws.amazon.com/jp/about-aws/whats-new/2024/07/agents-amazon-bedrock-retain-memory-preview/

# 説明
Bedrockはステートレスなので、もし以前の会話を利用したい場合はどこかにチャットの履歴を保有しておかなければなりません。AWSでは保存先としてDynamoDBがよく使われていると思います。
Agents for Amazon Bedrockでも同じように、履歴をどこかに保存しておかなければいけませんでした。
"Memory"機能は、クリック1つでとても簡単に履歴の保存(正確にはBedrockとやりとりの要約の保存)を実現できます。
これにより、使い方によっては保存先を用意する必要がなくなりました。

# Memoryを有効してみた
Memoryの有効化自体は非常に簡単です。Agents for Amazon Bedrockでエージェント作成する時に、"Enable memory"を"Enabled"にチェックを入れるだけです。
"Specify memory duration"は保存期間で1 - 30日の間で選択できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/519657/a346f9a4-808f-0715-f0b6-dd0a7822f103.png)


# 生成されたMemory
あとはいつも通り、プロンプトを入力するだけでOKです。
実際に作成されたMemoryは以下の右枠のようになっています(MemoryIdと Session IDは隠しています)。
日本語で入力しても英語で保存されるようです。
私が試した時には、コンソールに表示されるまで20分程度かかってしまっていました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/519657/d34267a1-f64b-ba4b-65b4-215b473a1e06.png)


マネジメントコンソールからプロンプトを入力するときは、今のところ"MemoryId"や"Session ID"を変更して、入力することはできないようです。マネジメントコンソールをリロードしても、"MemoryId"や"Session ID"が変更されることはなかったです。なので、間違えて別のページに飛んでしまってもMemoryは残ってくれます。
試す際には、適宜Memoryを削除しておかないと、入力したくない履歴も入り込んでしまうので注意が必要でしょう。

# Memoryがプロンプトに反映される仕組み
Traceを見る限り、Memoryで要約された内容は、自動でプロンプトに追加されるみたいです。
これにより、以前の内容を覚えている状態で、Bedrockと会話できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/519657/89d79534-308d-4915-835b-b59524543663.png)


マネジメントコンソールをリロードしてから要約をお願いすると、きちんと覚えていてくれました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/519657/032446c8-43d7-42bc-f0d8-9e9ada0a4cbc.png)


# boto3から呼び出し
今回は試していませんが、以下の記事を見る限り、boto3から呼び出せるようになっているようです。
boto3では、"memoryId"や"sessionId"を入力できるので、ユーザーごとに保存することが可能なようです。ユーザー数の上限などはドキュメントが見つからなかったですが、流石に今後制限が追加されるのはないでしょうか。

https://aws.amazon.com/jp/blogs/aws/agents-for-amazon-bedrock-now-support-memory-retention-and-code-interpretation-preview/


# まとめ
LangChainを用いて独自に実装していた部分が、Agents for Amazon Bedrockでフルマネージドサービスとして実現できるようになってきました。
Code Interpreterも相まって、Agents for Amazon Bedrockの使い勝手がかなり向上してきていると思います。
まだプレビューなので本番適用はできないですが、GAされた暁にはAgents for Amazon Bedrockも選択肢に入れて良いかもしれないと思いました。
循環importに関するエラー解決方法をまとめたけど、そもそも循環importするな

# 循環importとは

循環import（circular import）とは、2つ以上のモジュールが互いに依存し合っている状態を指します。
文字通り、関数とかをお互い参照し合うimportであるわけです。

例えば、モジュールAがモジュールBをインポートし、同時にモジュールBもモジュールAをインポートしているような場合です。

```python:module_a.py
from module_b import function_b

def function_a():
    print("Function A")
    function_b()
```
```py:module_b.py
from module_a import function_a

def function_b():
    print("Function B")
    function_a()
```

# なぜ循環importをしてはならないのか

一方のモジュールが完全に読み込まれる前に他方のモジュールが実行を開始してしまい、期待通りに動作しない場合があります。
これのせいでよくバグります。

また、コードの依存関係が複雑になって、コントリビューターがコードを理解したり保守するのが過酷になります。

# それでも循環importしなきゃいけない時がある

型注釈とかをする際にはよく陥りがちです。

# 循環importを無理やり解決する方法

どうしても循環importが必要な場合で、
かつエラーが発生する場合は以下の方法で何とかできます。

## 遅延インポート
関数内で必要な時にインポートを行います。

```python:module_a.py
def function_a():
    from module_b import function_b
    print("Function A")
    function_b()
```
```python:module_b.py
def function_b():
    from module_a import function_a
    print("Function B")
    function_a()
```

## モジュールの共通化
両方のモジュールが依存する共通のインターフェースを別のモジュールとして作成すれば循環はしないようになります。

## 再設計
そもそもアプリケーションの構造を見直して、循環依存がないようにします。

# 最後に

循環importは、極力しないべきです。
ウィンドウの切り替え・移動、ブラウザやExcelのタブ移動ショートカット

（自身の備忘録用です）
## ウィンドウの切り替え・移動
#### Windows
- 切り替え
`alt(押しながら)＋tab`
- 移動
    - 左右半分に移動
    `Windowsキー＋矢印の左右キー`
    - 全画面
    `Windowsキー＋矢印の上キー`
    - 最小化
    `Windowsキー＋矢印の下キー`

#### Mac
- 切り替え
`command(押しながら)＋tab`
    - 同アプリケーション内でウィンドウを切り替えたい場合
    `command(押しながら)＋tab`
    上記で任意のアプリケーションを選択した状態で矢印の上キー押下
    複数ウィンドウ表示されるので開きたいウィンドウを選択可能
- 移動
ショートカットはキーの割り当てが必要そう

## タブ移動
#### chrome(Windows)
`ctrl(押しながら)＋tab`
#### safari(mac)
`conrtol(押しながら)＋tab`
#### Excel(Windows)
`ctrl(押しながら)＋pgupキー/pgdnキー`
SAP UI5のFeed Inputと通常のinputの使い分けについて

## はじめに

担当する案件においてコミュニケーションを重視したコントロールを使用することとなり、適切なものを調査しました。
その結果、Feed Inputが最も適切であることが判明しました。この過程で、通常のinputとの使い分けとFeed Inputの実装について記述します。

## InputとFeed Inputの違い
|特徴|Input|Feed Input|
|:-:|:-:|:-:|
|用途|短いテキストや数値の入力に使用|ユーザー間の対話やコミュニケーションを促進するための入力フィールド|
|デザイン|シンプルで一般的なデザイン|ユーザー間のコミュニケーションに適したデザイン|
|組み合わせ|-|sap.m.FeedListItemなどのUI要素と組み合わせて使用することが多い|

## Feed Inputの実装の流れ

### 1.パネルの実装
まず、<Panel>コンポーネントを設定します。
```
<Panel id="任意のパネルID" expandable="true">
    <headerToolbar>
        <OverflowToolbar>
            <Title text="コメント"/>
        </OverflowToolbar>
    </headerToolbar>
    <VBox id="任意のVBoxID">
```
### 2.Feed Inputの追加
次に、コンポーネントを追加します。
postイベントを使ってコメントが投稿されたときの処理を設定します。
```
        <FeedInput 
            post="onFeedInputReqonPost"
            class="sapUiSmallMarginTopBottom"  
            showIcon="false"/>
```

### 3. コメントリストの設定
最後に、コメントを表示するためのコンポーネントを追加します。
以下では入力されたコメントをリスト形式で表示します。
```
        <List id="任意のListID" class="sapUiSmallMarginTop"/>
    </VBox>
</Panel>
```
上記の1～3を組み合わせると以下のようになります。
```
<Panel id="任意のパネルID" expandable="true">
    <headerToolbar>
        <OverflowToolbar>
            <Title text="コメント"/>
        </OverflowToolbar>
    </headerToolbar>
    <VBox id="任意のVBoxID">
        <FeedInput 
            post="onFeedInputReqonPost"
            class="sapUiSmallMarginTopBottom"  
            showIcon="false"/>
        <List id="任意のListID" class="sapUiSmallMarginTop"/>
    </VBox>
</Panel>
```

実装すると以下のようになります。

・コメント投稿前
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2623708/de00f096-a435-d3bb-821a-71b49490936a.png)

・コメント投稿後
![image (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2623708/d0a5da2d-9b58-b57e-9533-b840bbb431c5.png)

## 最後に
この調査を通じて、SAPUI5のInputコンポーネントに関する理解が深まりました。
Inputの使い分けやFeed Inputの実装方法に関して悩まれている際に、本記事が参考になれば幸いです。
ソリューションアーキテクトに求められる視点(7/14) Transit Gatewayでインスペクション用VPCに通信を集約する方法

## はじめに
ソリューションアーキテクトに求められる視点を整理してみました。

今回は、**Transit Gatewayでインスペクション用VPCに通信を集約する方法**です。実務や試験で、ご参考にして頂けましたら、幸いです。

## **アーキテクトに求められる視点**
複数のVPCを運用しています。**Transit Gatewayでインスペクション用VPCに通信を集約するには、どのようにすれば、可能となりますか？**

※インスペクション用VPC（Inspection VPC）は、ネットワークトラフィックの監視、分析、セキュリティ検査を行うために設計されたVPC（Virtual Private Cloud）です。このVPCは、通常、ファイアウォール、IDS/IPS（侵入検知システム/侵入防止システム）、プロキシサーバー、ログ収集システムなどのセキュリティアプライアンスをホストします。インスペクション用VPCを使用することで、ネットワークトラフィックを一元的に監視し、セキュリティポリシーを適用することができます。


## **ソリューション**
アプライアンスモードを有効にする。

AWS Transit Gatewayを使用してインスペクション用VPCに通信を集約することで、複数のVPCやオンプレミスネットワークからのトラフィックを一元的に監視し、セキュリティアプライアンスを通じて検査することができます。この方法により、ネットワークのセキュリティを強化し、異常なトラフィックや不正アクセスを迅速に検出することが可能になります。

### 構成概要
1. **Transit Gatewayの設定** 
Transit Gatewayを作成し、複数のVPCやオンプレミスネットワークを接続します。
2. **インスペクション用VPCの設定** 
インスペクション用VPCを作成し、セキュリティアプライアンス（例：ファイアウォール、IDS/IPS）を配置します。
3. **ルートテーブルの設定** 
Transit Gatewayのルートテーブルを設定し、トラフィックをインスペクション用VPCにルーティングします。


### ステップ1: Transit Gatewayの設定
1. **Transit Gatewayの作成**
AWS Management Consoleにログインし、VPCサービスに移動します。「Transit Gateways」セクションで「Create Transit Gateway」をクリックします。 必要な設定（名前、説明、ASNなど）を入力し、「Create Transit Gateway」をクリックします。

2. **Transit Gateway Attachmentsの作成**
Transit Gatewayに接続する各VPCやオンプレミスネットワークのアタッチメントを作成します。「Create Transit Gateway Attachment」をクリックし、接続するVPCやVPNを選択します。

### ステップ2: インスペクション用VPCの設定
1. **インスペクション用VPCの作成**
VPCサービスに移動し、「Create VPC」をクリックします。必要な設定（CIDRブロック、サブネットなど）を入力し、「Create VPC」をクリックします。

2. **セキュリティアプライアンスの配置**
インスペクション用VPC内にセキュリティアプライアンス（例：ファイアウォール、IDS/IPS）を配置します。必要に応じて、セキュリティグループやネットワークACLを設定します。

### ステップ3: ルートテーブルの設定
1. **Transit Gatewayのルートテーブルの設定**
Transit Gatewayの「Route Tables」セクションに移動し、ルートテーブルを作成します。
各VPCやオンプレミスネットワークからのトラフィックをインスペクション用VPCにルーティングするルートを追加します。

2. **インスペクション用VPCのルートテーブルの設定**
インスペクション用VPCのルートテーブルに、Transit Gatewayへのルートを追加します。
セキュリティアプライアンスからの戻りトラフィックが適切にルーティングされるように設定します。


:::note info
**アプライアンスはステートフルアプライアンスであるため、リクエストトラフィックとレスポンストラフィックの両方が検査されます。** 高可用性を実現するために、VPC C の各アベイラビリティーゾーンにアプライアンスがあります。
:::
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2920213/1fb61ce4-c16d-2139-2ddb-5c1669ed07e7.png)

:::note info
**アプライアンスモードが有効になっていない場合**

VPC B のアベイラビリティーゾーン 2 から発信されるレスポンストラフィックは、トランジットゲートウェイによって VPC C 内の**同じアベイラビリティーゾーンにルーティング**されます。したがって、アベイラビリティーゾーン 2 のアプライアンスは VPC A の送信元からの元の**リクエストを認識しないため、トラフィックはドロップ**されます。
:::

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2920213/fb338ff0-331d-4581-216b-adda5889b825.png)

参考サイト

https://docs.aws.amazon.com/ja_jp/vpc/latest/tgw/transit-gateway-appliance-scenario.html

https://dev.classmethod.jp/articles/routing-of-the-dedicated-transit-gateway-subnet/

https://docs.aws.amazon.com/ja_jp/vpc/latest/tgw/tgw-vpc-attachments.html

https://dev.classmethod.jp/articles/enable-appliance-mode-when-using-transit-gatewayto-aggregate-communication-to-vpc-for-inspection/


#### ソリューションは、あくまで、一例です。他の解決方法もあるので、参考程度にしてください。

#### 読んでいただき、ありがとうございました。
CloudFront + S3 静的Webホスティング環境構築

こんにちは。
株式会社クラスアクト インフラストラクチャ事業部の大塚です。

前回の記事でS3を使って静的なWebサイトをホスティングしました。

https://qiita.com/ohtsuka-shota/items/8846891eea0ccf8bcec6

この環境を拡張し、前面にCloudFrontを配置します。

# 環境イメージ

![20240620から-ページ25.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3219385/aae01f1b-b7d7-870e-7951-0f6f3ceac417.png)

# 構築
## CloudFrontデプロイ
CloudFrontの管理画面を開きます。
ディストリビューションを作成を押下します。
![Untitled (10).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3219385/29232d4b-3348-d89c-fcad-de66bba43c06.png)
次の内容で作成しました。
まず、Origin domainで作成したS3ホスティングのドメインを選択します。選択すると以下のような表示がポップアップしますが、Webサイトのエンドポイントを使用ボタンを押下するとCloudFrontの設定の一部が自動で設定されていきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3219385/71581305-0e1d-051e-fef9-a51013e51392.png)
料金クラスはとりあえず全てのエッジロケーションを使用するを選択。
デフォルトルートオブジェクトはindex.htmlを記入しました。ここにindex.htmlと記載をしておくことでCloudFront作成後に自動で払い出されるディストリビューションドメイン名の後にファイル名等を指定しないでアクセスすると、自動でindex.htmlにアクセスをしに行きます。
![screencapture-us-east-1-console-aws-amazon-cloudfront-v4-home-2024-07-11-08_02_38 (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3219385/1e8c24cf-b82a-852e-de2c-cb9515946557.png)
作成が出来ると以下のような画面に自動で遷移します。
暫く待機すると最終更新日がデプロイから、日時に変わります。日時に切り替わりましたらディストリビューションドメイン名をコピーします。
![Untitled (11).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3219385/2d7d69a1-6a98-2730-b047-e6be627a0567.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3219385/4dad31b6-c2b2-40b3-6ded-e1c549f972b8.png)
オリジンタブやビヘイビアタブを核にするとS3バケットに紐づいていることが確認出来ます。
![Untitled (12).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3219385/414d4fde-7d65-925b-b92e-1f7a5fbaee54.png)
![Untitled (13).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3219385/4f676114-f9ec-785b-f927-29aeb4d69cbb.png)

## 確認
先程控えたディストリビューションドメイン名に対してWebブラウジングしてみます。
S3バケットに格納しているindex.htmlが表示されることを確認します。
![Untitled (14).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3219385/c553327c-52a3-e616-4551-e1f2770c3f21.png)
またディストリビューションドメイン名/hogehogeとしてerror.htmlを意図的に出してみます。
これも問題なさそうですね。
![Untitled (15).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3219385/7b05b482-7c9b-c9b1-c010-2145aae53648.png)
これで完璧！PEP8スタイルガイドラインを習得するためのクイズ10問

## はじめに
Pythonはそのシンプルさと可読性の高さで知られるプログラミング言語です。しかし、その可読性を最大限に引き出すためには、コードスタイルガイドラインであるPEP8（Python Enhancement Proposal 8）を遵守することが重要です。PEP8は、Pythonコードの一貫性と可読性を向上させるためのベストプラクティスを提供します。

この記事では、PEP8に準拠したコーディングスタイルと、そうでないスタイルを比較するための10問のクイズを紹介します。このクイズを通じて、PEP8の基本的なルールを学び、実践的な知識を深めることができます。初心者から経験者まで、すべてのPythonプログラマーに役立つ内容となっているので、ぜひ挑戦してみてください。

## PEP8スタイルガイドラインを習得するためのクイズ10問

### 問題1

```python
# コードA
def add(a, b):
    return a+b

# コードB
def add(a, b):
    return a + b
```

#### 解答: コードB

#### 解説:
PEP8では、演算子の前後にはスペースを入れることを推奨しています。したがって、`return a + b`が正しいスタイルです。

### 問題2

```python
# コードA
for i in range(10):
    print(i)

# コードB
for i in range(10):
 print(i)
```

#### 解答: コードA

#### 解説:
PEP8では、インデントにはスペース4つを使用することを推奨しています。コードBはインデントが不適切です。

### 問題3

```python
# コードA
class MyClass:
    def __init__(self, value):
        self.value=value

# コードB
class MyClass:
    def __init__(self, value):
        self.value = value
```

#### 解答: コードB

#### 解説:
PEP8では、代入演算子の前後にはスペースを入れることを推奨しています。したがって、`self.value = value`が正しいスタイルです。

### 問題4

```python
# コードA
def func(x,y):
    return x * y

# コードB
def func(x, y):
    return x * y
```

#### 解答: コードB

#### 解説:
PEP8では、引数リストの各引数の間にスペースを入れることを推奨しています。したがって、`def func(x, y):`が正しいスタイルです。

### 問題5

```python
# コードA
def long_function_name(
        var_one, var_two, var_three,
        var_four):
    print(var_one)

# コードB
def long_function_name(
    var_one, var_two, var_three,
    var_four):
    print(var_one)
```

#### 解答: コードA

#### 解説:
PEP8では、継続行のインデントには追加のレベル（通常は4つのスペース）を入れることを推奨しています。したがって、`var_one, var_two, var_three, var_four`の行は追加のインデントが必要です。

### 問題6

```python
# コードA
x = { 'a':37,'b':42,
'c':927}

# コードB
x = {'a': 37, 'b': 42, 'c': 927}
```

#### 解答: コードB

#### 解説:
PEP8では、辞書のエントリの間にはスペースを入れることを推奨しています。また、複数行にわたる辞書のエントリは適切にインデントする必要があります。したがって、コードBが正しいスタイルです。

### 問題7

```python
# コードA
if x>5:
    print("x is greater than 5")

# コードB
if x > 5:
    print("x is greater than 5")
```

#### 解答: コードB

#### 解説:
PEP8では、比較演算子の前後にはスペースを入れることを推奨しています。したがって、`if x > 5:`が正しいスタイルです。

### 問題8

```python
# コードA
def foo():
    return (0,1,2,3)

# コードB
def foo():
    return (0, 1, 2, 3)
```

#### 解答: コードB

#### 解説:
PEP8では、リストやタプルの要素の間にはスペースを入れることを推奨しています。したがって、`return (0, 1, 2, 3)`が正しいスタイルです。

### 問題9

```python
# コードA
my_list = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
```

```python
# コードB
my_list = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, ]
```

#### 解答: コードA

#### 解説:
PEP8では、リストの最後の要素の後には余分なカンマを入れないことを推奨しています。したがって、`my_list = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]`が正しいスタイルです。

### 問題10

```python
# コードA
import os, sys

# コードB
import os
import sys
```

#### 解答: コードB

#### 解説:
PEP8では、標準ライブラリの各インポートは個別の行に書くことを推奨しています。したがって、`import os`と`import sys`を個別の行に書くコードBが正しいスタイルです。


## 参考文献

https://peps.python.org/pep-0008/

https://pep8-ja.readthedocs.io/ja/latest/

https://qiita.com/simonritchie/items/bb06a7521ae6560738a7

https://qiita.com/sergicalsix/items/0c3f3e6a8a26770a84be
【Broadcom】購入されたVMwareライセンスはいずこへ・・・？

# 【経緯】
VMwareがBroadcomに買収された後、エンドユーザーのお客様が新たに新規でVMwareライセンスを購入した。お客様にはVMwareから「VMware Support and Subscription - Order# xxxx」の件名で購入したライセンスの確認情報が届いたようだが、そこには契約番号の記載はあったがVMwareライセンスキーの記載/添付はなかった。またどこでライセンスキーを取得する記載もなかったらしい。そこでVMwareライセンスの捜索が始まった。

※VMwareからのライセンス確認メール以外からは特に何もきていなかったとのこと。
　本来であれば、BrodcomからSiteIDなどのメールが送信されそうなのだが。


# 【捜索】
ライセンスに紐づくSiteIDも不明だっため、直接Broadcomサポートに電話でお問い合わせを行った。サポートによると購入したライセンスはエンドユーザー様のBroadcomサポートポータルアカウントに紐づいており、そこでライセンスキーを取得できるとのことだった。

エンドユーザー様はBrodcomのアカウントを持っていないと仰られていたがどういうことだ？となったがBrodcomサポートによるとアカウントをお持ちでないお客様は、Brodcom製品を購入すると購入時にご提示いただいたメールアドレス（技術担当者？）で自動的にアカウントが作成されるとのことだった。

この後はBrodcomサポートの指示のもと下記対応をエンドユーザー様に実施いただき、VMwareライセンスキーを取得することができた。

##### 1. Brodcom サポートポータルアカウントのセットアップ（アクティブ化）
アカウントの初期設定ができていなかったため、下記を実施する必要があった。

① [**パスワードの（再）設定**](https://knowledge.broadcom.com/external/article?articleId=225617)
② [**多要素認証設定**](https://knowledge.broadcom.com/external/article?articleId=228198)

##### 2. サイトIDへの招待 
エンドユーザー様のVMwareライセンスに紐づくサイトIDに弊社のBroadcomアカウントからアクセスできるようにするため、サイトIDへの招待が必要だった。

① [**サイトIDにユーザアカウントを招待する**](https://knowledge.broadcom.com/external/article/271176)

##### 3. ライセンスの操作権限の付与 
サイトIDへの招待だけではサイトIDへのアクセスとサイトIDに紐づく製品のサポートリクエストの起票が可能になるだけのため、ライセンスの操作権限を付与していただくために必要だった。

① [**招待したユーザーアカウントにライセンスの操作権限を付与する**](https://knowledge.broadcom.com/external/article?articleNumber=366880)


:::note info 
SiteIDとは：
Broadcom製品のサポートや管理に使用される一意の番号のこと。
Broadcom製品を購入した際などに発行される。
Broadcom Software Deliveryからメールで技術担当者に送信される。
:::

:::note info 
お問い合わせ先：
電話窓口 03-6634-4963 (日本語対応可能時間 平日 9:00 – 17:30)
 → ものすごくつながりにくい。日本語に対応するエージェントがいない場合は、英語対応のエージェントに回される。また事前のケース番号やサイトIDが必要になるというアナウンスが流れるが、なくてもお問い合わせはできる。（電話内で新規ケースを挙げることができる。）
 
[**リクエストフォームでのお問合せ**](https://broadcomcms-software.wolkenservicedesk.com/web-form?_ga=2.14936502.1605509527.1571349386-1693839706.1571349386)
 → 返信が返ってこない・・・。（私だけか？）
 
[**チャットサポートでのお問合せ**](https://knowledge.broadcom.com/external/article?articleId=202775)
:::

# 【参考にしたサイト】

・[**ウェビナー資料とサポートポータル FAQ を掲載しました**](https://blogs.vmware.com/vmware-japan/2024/05/webinar-presentation-fqa.html)
・[**旧VMware製品における、サポート問合せ先**](https://licensecounter.jp/vmware/information/notice/2024/05/011983.html)
・[**Broadcomサポートポータルに関するリンク集**](https://licensecounter.jp/vmware/information/notice/2024/05/011974.html)
・[**サポートへのお問い合わせ - Broadcom ソフトウェア**](https://support.broadcom.com/web/ecx/software-contact-support)
・[**Broadcom サポートポータル ご利用リンク集とお問合せ**](https://blogs.vmware.com/vmware-japan/2024/05/broadcom-support-portal-links.html)

# 【その他サイト】
・[**Broadcom サポートポータルとコミュニティにアカウントを登録する**](https://knowledge.broadcom.com/external/article?articleId=226420)
・[**サイト ID を追加してアカウントをアップグレードする**](https://knowledge.broadcom.com/external/article?articleId=224972)
・[**サポートポータルの既存のプロファイルにサイト ID を追加する**](https://knowledge.broadcom.com/external/article/225292/site-id.html)
・[**Broadcomサポートポータル移行について**](https://licensecounter.jp/vmware/dl/pdf/BSP-SR_240424.pdf)
・[**Site ID紐づけ手順(初回以降)**](https://sbcssupport.zendesk.com/hc/article_attachments/8975939963023)
type-challenges 初級編3: Awaited, If, Concat

# type-challenges 初級編3: Awaited, If, Concat

## はじめに type-challengesとは

[GitHubのtype-challengesリポジトリ](https://github.com/type-challenges)は、TypeScript型システムの理解を深めるための型クイズ問題集です。高品質な型を作成することで、バグを減らし、プロジェクトの保守性を向上させることができます。今回も、初級編から3つの問題に挑戦します。

### 1. Awaited

Promise ライクな型が内包する型をどのように取得すればよいでしょうか。

例えば：`Promise<ExampleType>`という型がある場合、どのようにして `ExampleType` を取得すればよいでしょうか。

#### 例

```typescript
type ExampleType = Promise<string>
type Result = MyAwaited<ExampleType> // expected to be string
```

#### 私の回答

```typescript
type MyAwaited<T> = T extends PromiseLike<infer U> ? MyAwaited<U> : T
```

もしPromiseLikeな型であれば取り外して、そうでなければ `T` をそのまま返す、という型定義にしました。


今回の問題のテストケースには

```typescript
type Z1 = Promise<Promise<Promise<string | boolean>>>
type Result = MyAwaited<Z1> // expected to be string | boolean
```

のようなケースにより、再帰的に型を取り出すことが必要になったのでこのような回答になっています。

### 2. If

条件値 `C`、`C`が truthy である場合の戻り値の型 `T`、`C`が falsy である場合の戻り値の型 `F` を受け取る `If` を実装します。 条件値 `C` は true か false のどちらかであることが期待されますが、`T` と `F` は任意の型をとることができます。

#### 例

```typescript
type A = If<true, 'a', 'b'> // expected to be 'a'
type B = If<false, 'a', 'b'> // expected to be 'b'
```

#### 私の回答

```typescript
type If<C, T, F> = C extends true ? T : F
```

これは簡単ですね。extends を使って判定してあげるだけです。

:::note info
急に簡単になった。笑
:::


### 3. Concat

JavaScript の `Array.concat` 関数を型システムに実装します。この型は 2 つの引数を受け取り、受け取ったイテレータの要素を順に含む新しい配列を返します。

#### 例

```typescript
type Result = Concat<[1], [2]> // expected to be [1, 2]
```

#### 私の回答

```typescript
type Concat<T extends Readonly<Array< unknown>>, U extends  Readonly<Array<unknown>>> = [...T,...U]
```

今回も単純でしたね。`[...T,...U]` で配列を展開して新たな配列を作るだけでした。

:::note info
もしかして強くなってる..?
:::

Readonlyをつけている理由ですが

```typescript
const tuple = [1] as const
type Test = Concat<typeof tuple, typeof tuple> // expected to be [1, 1]
```

このテストケースでジェネリクスの引数に入れられなくなってしまっていたのでこのような書き方にしています。

### まとめ

このように、TypeScriptの型システムを理解し、実際に型を実装することで、より安全で保守性の高いコードを書くことができます。ぜひこれらの課題を解いて、型力UPしてみてください。

### 参考記事

- [TypeScript公式ドキュメント](https://www.typescriptlang.org/docs/)
- [type-challenges GitHubリポジトリ](https://github.com/type-challenges/type-challenges)
ICFPC 2024 Lambdaman で乱択解法が動くことを大雑把に理解する

# Lambdaman

詳しくは[公式](https://github.com/icfpcontest2024/icfpc2024/blob/main/static/lambdaman/lambdaman.md) を参照

2次元グリッド上のマップが与えられる。あるマスにパックマンがいて、それ以外の壁でないマスにはすべてエサがおいてある。パックマンの動き (U/R/D/L からなる文字列) の指示を *生成するプログラム* を与えて、その動きに従ったパックマンがエサをすべて食べるようにせよ。生成される文字列の長さは 100万以下でなければならず、プログラムは短いほどよい。壁にぶつかるような動きを指示してもよく、その場合パックマンは動かない。

# 乱択解法

この問題に対する上位解法は乱択によるものだった。つまり、シード `x` に基づきランダムな長さ100万の文字列 `M(x)` を生成するプログラム `M` を固定したとき、`M(s)` が問題の解になっているような `s` を総当たりで探す試みが現実的な時間で終了するということである。

このことが自分の直感に反していたので、この記事ではこれを大雑把に理解することを目指す。具体的には、ランダムなシード `x` に対して `M(x)` が解になる確率を、ある問題を例にして大雑把に下からおさえる。

# 問題 16

[問題16](https://github.com/icfpcontest2024/icfpc2024/blob/main/static/lambdaman/lambdaman16.txt) のマップは長い一本のパスである。図形の特徴から、偶数歩目は直前と同じ動きをするようにプログラムを固定し、64 * 64 = 2^12 個のセルからなるパスを、50万歩でわたり切る問題と捉える。壁にぶつかる確率は約1/2なので、求める確率はだいたい以下の確率と同じである。

* 公平なコインを25万回投げ、表なら前に進み、裏なら下がるとしたとき、2^12 歩先にあるゴールへたどり着く確率

この定式化だとマイナスの座標にいく可能性もあるが、その場合は損しかしないので、確率を下から抑える目的には問題ない。

ゴールにたどり着くためには、表が裏より 2^12 回多くでれば十分である。よって、上記の確率は以下で下から抑えられる。

* 公平なコインを25万回投げ、表が (25万/2) + 2048 回以上出る確率

さて、コインを投げ続けたときに表がでる回数の確率分布は [Binomial distribution] とよばれ、これは試行回数が多いとき正規分布で近似できる ([Normal approximation]) ことが知られている。上記のコイン投げの確率分布は、平均 25万/2, 分散 $\sigma^2=$ 25万/4 の正規分布とだいたい同じ。つまり $\sigma = 250$ であり、求めたいのはだいたい $8\sigma$ くらいの外れ値を引く確率だとわかる。

[68–95–99.7 rule](https://en.wikipedia.org/wiki/68%E2%80%9395%E2%80%9399.7_rule
) というページを見ると、正規分布の外れ値を引くのがどれくらいの確率かを示す表があって、$8\sigma$ は $10^{-15}$ くらいの確率とある。つまり少なくとも 0.1京 回に一回はあたりがある。

[Binomial distribution]: https://en.wikipedia.org/wiki/Binomial_distribution
[Normal approximation]: https://en.wikipedia.org/wiki/Binomial_distribution#Normal_approximation

# 結論

ちょっとした計算で、1/0.1京 という確率の下限を与えることができた。この確率は自分の直感よりずっと大きいものだった。今後は乱択に関して自分の直感を信じず、実験するかラフな確率計算をすることを心がけたい。
Figmaのコメントで @メンション 先が出てこない場合

# 問題

- `@` アットマークを書いても特定の人しか候補に出てこない
- シェアしていないはずの相手が候補に出てくる

<img width="283" alt="image" src="https://github.com/YumaInaura/YumaInaura/assets/13635059/727d8d3b-257f-43a1-82c6-d53c9a7c4ec0">

( 実際にはこの画像の下に数名のメンション候補が表示されているものとする )

# 解決

- `@` アットマークを書いただけでは、全メンバーをリストから選択することは出来ないようだ。これはあくまで候補機能。
- `@` アットマークに続いてアカウント名を入力すると、初期候補にないメンバーもサジェストしてくれるようだ


<img width="280" alt="image" src="https://github.com/YumaInaura/YumaInaura/assets/13635059/a55ac70b-278b-44b2-b00b-c108ab553bb5">

- Figmaのメンション先検索が前方一致的にしかヒットしない場合もあるようなので、注意。たとえば `yuma_inaura` を探すには `@inaura` と入力してもヒットせず `@yuma` から探さなければいけない (おそらくアンダースコア `_` で繋がれたアカウント名は1単語として扱われていそう )


# 公式

https://help.figma.com/hc/ja/articles/1500004290941-FigJam%E5%86%85%E3%81%AE%E3%82%B3%E3%83%A1%E3%83%B3%E3%83%88


# チャットメンバー募集


何か質問、悩み事、相談などあればLINEオープンチャットもご利用ください。

https://line.me/ti/g2/eEPltQ6Tzh3pYAZV8JXKZqc7PJ6L0rpm573dcQ


# プロフィール・経歴

https://github.com/YumaInaura/YumaInaura
商品スケジュールの一括作成の検討

+ [商品スケジュールの設定方法](https://daigirin.com/forecasts/)

+ [消費スケジュールのリレーション](https://help.salesforce.com/s/articleView?id=sf.cpq_consumption_rate_relationships.htm&type=5)

商品スケジュールは以下のように、商品を１つずつ開いて設定していかなくてはけないUIです。
一括で設定できれば便利になりそう

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/781bd0ad-ea36-f03f-d397-0dc78e0295f0.png)


画面フローを使って、商談にひもついている商談商品のなかで、

+ まだスケジュールされていない商談商品
+ スケジュールの設定が可能な商品を選択している商談商品

だけを画面に表示して選択できるところまでをまずは作ってみました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/8cb96afd-f126-90d8-cadd-19dac5035a7f.png)

# フローからこのスケジュールのオブジェクトがアクセスできるかをまずは確認

調べてみると[OpportunityLineItemSchedule](https://developer.salesforce.com/docs/atlas.ja-jp.object_reference.meta/object_reference/sforce_api_objects_opportunitylineitemschedule.htm)というオブジェクトが作られるようです。

フローの中からもOpportunityLineItemScheduleは作成可能です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/d050d1b7-f983-5711-f367-400490f28709.png)

# フローの考え方


画面フローを使って、商談にひもついている商談商品のなかで、

+ まだスケジュールされていない商談商品
+ スケジュールの設定が可能な商品を選択している商談商品

だけを画面に表示するフローの考え方

1\. 商談のID(recordIdというテキスト型の変数に格納)を使って、商談商品を取得する

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/34d6d8ea-bdf8-0b0f-8773-bea5561df649.png)


2\. ループの中でHasScheduleという項目がfalse(まだスケジュールされていない)レコードの商品IdをProduct2Ids_textというテキスト型のコレクション変数に保存します。

本当だったら、1の商談商品を取得するの条件にHasScheduleがfalseと指定してもいいのですが、既に主家ジュールされたレコードも処理をする時のために、今回はわざわざ決定要素を使いました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/67af3812-ebae-c0b2-00be-b7884e6bc23b.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/4af0c1e9-5e10-2105-368c-2f098e9874a3.png)


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/05fee54a-5830-86d9-1266-2e88936c4054.png)

3\. Product2Ids_textというテキスト型のコレクション変数のIdが含まれている、
CanUseQuantityScheduleまたはCanUseRevenueScheduleがtrueの商品を選ぶことで、対象の商品を取得します。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/f0ab3983-64e6-37d0-63f3-556ed30bb52f.png)

4\. ループを使って、Product2Ids_text2というテキスト型のコレクション変数に商品のIdを格納します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/d57520a0-fc4b-b6f4-620c-297f91fe7b39.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/0289fc65-e222-b712-a6eb-56cc3c1a561c.png)

5\. 必要な商談商品を再取得します。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/b1d54503-2e6a-16a5-1fa9-f6b24ab2b4f4.png)

6\. データテーブルに取得した商談商品を表示します

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/3bb353e3-67dd-4703-68e8-99968d4b1413.png)

7\. 画面で選択した商談商品のIdは以下のように取得できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/f7ff2559-f202-41bf-8865-725e9e327f2b.png)

実際にスケジュールを作成するために、商談商品のIdをテキスト型のコレクション変数に格納しておきます。

ここからどうやってスケジュールを作るのかは悩み中。

いかのように標準の設定画面のようにパラメータを入力して一括作成をどうするか...

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/1f18eed0-30c4-ed9f-a3c9-de169ef0b83a.png)
ssh接続できるけどgithubにpushできない

# sshコマンドで接続は可能

「.ssh/config」にgithubへの接続設定を記載し、githubに公開鍵を登録しました。


```config:.ssh/config
Host github
    HostName github.com 
    identityFile ~/.ssh/<Keyファイル名>
    IdentitiesOnly yes 
    TCPKeepAlive yes
    AddKeysToAgent yes 
    User git 
```

テストコマンドで接続も確認。

```sh
ssh -T github
Hi <ユーザー名>! You've successfully authenticated, but GitHub does not provide shell access.
```

実は、「.ssh/config」にあるミスがあります。
ssh単体のテスト接続は確認できるので、ここで問題には気づけませんでした。

もう、気付いた人もいると思います。実は、最初に「.ssh/config」を作成したとき、このミスをしていませんでした。いろいろと調査しているときに変更して、その修正を忘れていました。

# gitへのpushができない

上記の状態で、gitへpushします。
すると、許可されていないというエラーメッセージが表示されて、pushできません。

```sh
git push origin staging:staging
git@github.com: Permission denied (publickey).
fatal: Could not read from remote repository.

Please make sure you have the correct access rights
```

いつもならpushできるのにおかしいなと思いました。
今回はorganizationのリポジトリへpushしようとしてたので、権限かなあと思ってそのあたりも見直しました。でも、それも問題なさそうでした。

とにかく、gitのリモートリポジトリを確認しようと思いました。

```sh
git remote -v
origin  git@github.com:<組織名>/<リポジトリ名>.git (fetch)
origin  git@github.com:<組織名>/<リポジトリ名>.git (push)
```

想定どおりのリモート先。
ただ、これをみてるときに、sshのホスト指定とgitのホスト指定をリンクさせるのはドメイン名だから、そこに違いがあるんだろうなと思いました。

# .ssh/configのHost名と.git/configのリモートドメインの不一致

冒頭の「.ssh/config」の設定で気付いた人がいると思います。問題の原因は、Host名に「.com」が抜けていることでした。「.ssh/config」のHost名とリモート先のドメイン名が一致していなかったので、gitのコマンドがssh接続の設定情報を取得できず、エラーになっていました。

```config:.ssh/config
Host github ← ここに「.com」がない
    ...
```

上記を以下のように修正しました。

```config:.ssh/config
Host github.com ← 「.com」を追加
    ...
```

再度、gitでpushコマンドを実行します。

```sh
git push origin staging:staging
Everything up-to-date
```

今度はエラーなくpushができました。

# 問題調査の為の変更が問題を引き起こす

今回、新しい構成でやってみていて、いろいろと問題が起こりました。設定を変更しながら原因追及していました。その際に、「.ssh/config」のHost名を変更しました。「.ssh/config」のHost名は単なる設定名称なのでドメイン名でなくても接続情報を取得できるのを確認していました。確かに、sshの接続だけなら想定通り接続できました。

この変更を修正せずに、別の仕事をし、変更したことをすっかり忘れていました。
そして、いざgit pushすると接続できず、かなりハマりました。

こうした個人のうっかりミスに関するエラーはなかなかネットにないことがあります。これは、自力でなんとかしないといけません。まさに、探偵になったつもりで原因調査しました。

気づいたら大したことない原因で、自分がまいた問題なんですが、解決するとめっちゃうれしかったりします。
個人的な低レベルなミステリーでした。

もし、同じような原因の人の助けになれば幸いです。
ソリューションアーキテクトプロフェッショナルに求められる視点(6/14) データベースアクティビティストリームを使って監査ログを S3 に永続化する方法

## はじめに
ソリューションアーキテクトプロフェッショナルに求められる視点を整理してみました。

今回は、**データベースアクティビティストリームを使って監査ログを S3 に永続化する方法**です。実務や試験で、ご参考にして頂けましたら、幸いです。

## **アーキテクトに求められる視点**
Amazon Aurora PostgreSQL DBクラスターを使用しています。すべてのデータベース上のすべてのデータアクティビティを監視する必要があります。監査ログを S3 へ永続的に保存したいと考えています。

## **ソリューション**
Aurora DBクラスターでデータベースアクティビティストリームを起動して、アクティビティストリームをAmazon Kinesisデータストリームにプッシュします。Kinesisデータストリームを消費し、さらなる分析のためにAmazon S3にデータを配信するようにAmazon Kinesis Data Firehoseを設定します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2920213/33285431-7fa2-4388-abdd-1a4a3b98bc1e.png)

※ https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/DBActivityStreams.Overview.html から引用

関連サイト

https://dev.classmethod.jp/articles/aurora-postgresql-audit-with-data-activity-stream/

### データベースアクティビティストリームの要件と制限
Aurora では、データベースアクティビティストリームに、次の**要件と制限**があります。

**データベースアクティビティストリーミングには、Amazon Kinesis が必要です。**

**常に暗号化されているため、アクティビティストリーミングには AWS Key Management Service (AWS KMS) が必要**です。


https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/AuroraUserGuide/DBActivityStreams.Overview.html


#### ソリューションは、あくまで、一例です。他の解決方法もあるので、参考程度にしてください。

#### 読んでいただき、ありがとうございました。
type-challenges 初級編2: First of Array, Length of Tuple, Exclude

# type-challenges 初級編2: First of Array, Length of Tuple, Exclude

## はじめに type-challengesとは

[GitHubのtype-challengesリポジトリ](https://github.com/type-challenges)は、TypeScript型システムの理解を深めるための型クイズ問題集です。高品質な型を作成することで、バグを減らし、プロジェクトの保守性を向上させることができます。今回も、初級編から3つの問題に挑戦します。

### 1. First of Array

配列 `T` を受け取り、その最初の要素の型を返す `First<T>` を実装します。

#### 例

```typescript
type arr1 = ['a', 'b', 'c']
type arr2 = [3, 2, 1]

type head1 = First<arr1> // expected to be 'a'
type head2 = First<arr2> // expected to be 3
```

#### 私の回答

```typescript
type First<T extends any[]> = T extends [infer first, ...Array<unknown>] ? first : never
```

#### 解き方

- `T extends [infer first, ...Array<unknown>]` という条件型を使い、配列 `T` の最初の要素の型を `first` として推定します。
- `first` が存在する場合、その型を返します。
- 配列が空の場合は `never` を返します。

#### 他の回答

他の人の回答も見てみましょう。

```typescript
type First<T extends any[]> = T extends [] ? never : T[0]
```

この解法では、配列が空かどうかをチェックし、空でなければ最初の要素の型を返しています。

```typescript
type First<T extends any[]> = T['length'] extends 0 ? never : T[0]
```

この解法も同様に、配列の長さを使って空かどうかを判定し、最初の要素の型を返しています。

### 2. Length of Tuple

タプル `T` を受け取り、そのタプルの長さを返す型 `Length<T>` を実装します。

#### 例

```typescript
type tesla = ['tesla', 'model 3', 'model X', 'model Y']
type spaceX = ['FALCON 9', 'FALCON HEAVY', 'DRAGON', 'STARSHIP', 'HUMAN SPACEFLIGHT']

type teslaLength = Length<tesla>  // expected 4
type spaceXLength = Length<spaceX> // expected 5
```


今回の問題は解き方がわからなかったので答えを見ちゃいました。

:::note warn
実務でtsを書いているだけなので筆者は全然強くないです。ご了承ください。
:::


```typescript
type Length<T extends readonly any[]> = T['length']
```

#### 解き方

- タプル型 `T` に対して `T['length']` を使うと、そのタプルの長さを取得できます。

:::note info
こんな解き方があるんですね、
:::


### 3. Exclude

組み込みの型ユーティリティ `Exclude<T, U>` を使用せず、`U` に割り当て可能な型を `T` から除外する型を実装します。

#### 例

```typescript
type Result = MyExclude<'a' | 'b' | 'c', 'a'> // 'b' | 'c'
```

また解き方がわからなかったので答えを見ちゃいました。


```typescript
type MyExclude<T, U> = T extends U ? never : T;
```
:::note info
普通に難しい。
:::

#### 解き方

- `T extends U ? never : T` という条件型を使い、`T` の各要素が `U` に割り当て可能かどうかをチェックします。
- `T` の要素が `U` に割り当て可能であれば、その要素は `never` になります。
- そうでなければ、その要素はそのまま残ります。

:::note info
これもこんな書き方できるの知りませんでした。
:::


### まとめ

このように、TypeScriptの型システムを理解し、実際に型を実装することで、より安全で保守性の高いコードを書くことができます。ぜひこれらの課題を解いて、型力UPしてみてください。

### 参考記事

- [TypeScript公式ドキュメント](https://www.typescriptlang.org/docs/)
- [type-challenges GitHubリポジトリ](https://github.com/type-challenges/type-challenges)
ソリューションアーキテクトに求められる視点(10/14)　AWS Elastic Disaster Recovery

## はじめに
ソリューションアーキテクトに求められる視点を整理してみました。

今回は、**AWS Elastic Disaster Recovery**です。実務や試験で、ご参考にして頂けましたら、幸いです。

**AWS Elastic Disaster Recoveryとは？**
災害対策を必要最低限の手間とコストで、行う事が出来るサービスです。
AWS DRSを使用すれば、アイドル状態のディザスタリカバリサイトのリソースとメンテナンスを削除してコストを削減し、訓練や復旧のために必要なときだけ完全復旧サイトの料金を支払うことができます。

**AWS DRSを使用して何ができますか?**
プライマリIT環境に障害が発生した場合、AWS DRS を使用して、AWS上のアプリケーションを最新の状態、または選択した以前の時点から素早く復旧させることができます。

## **アーキテクトに求められる視点**
オンプレミスアプリケーションの災害復旧にAWSを使用したいと考えています。
対象サーバのOSは、Windowsです。
災害対策を必要最低限の手間とコストで行いたいと考えています。

## **ソリューション**
AWS Elastic Disaster Recoveryを使用して、オンプレミスサーバーを複製します。AWS DataSyncを使用して、Amazon FSx for Windows File Serverファイルシステムにデータを複製します。ファイルシステムをAWSサーバーにマウントします。災害時には、Elastic Disaster Recoveryを使用して、オンプレミスのサーバーをAWSにフェールオーバーします。災害が落ち着いたら、フェイルバックします。




## AWS Elastic Disaster Recoveryまとめ

| 特徴                                    | 説明                                                                                       |
|-----------------------------------------|------------------------------------------------------------------------------------------|
| 簡単なセットアップ                      | AWS DRSは、シンプルなインストールプロセスと自動化された設定を提供し、迅速にディザスタリカバリを開始できます。 |
| 継続的なレプリケーション                | データの継続的なレプリケーションを行い、最新の状態を維持します。これにより、データ損失を最小限に抑えます。 |
| 迅速なリカバリ                          | 数分以内にアプリケーションをAWS上で復旧できるため、ダウンタイムを最小限に抑えます。 |
| コスト効率                               | 必要なリソースのみを使用し、オンデマンドでスケールするため、コスト効率が高いです。 |
| 柔軟なリカバリオプション                | フルリカバリ、部分リカバリ、テストリカバリなど、さまざまなリカバリオプションを提供します。 |
| セキュリティとコンプライアンス           | AWSのセキュリティ機能とコンプライアンス基準に準拠しており、安全にデータを保護します。 |
| 自動化とオーケストレーション             | リカバリプロセスを自動化し、オーケストレーションすることで、手動操作を減らし、エラーを防ぎます。 |
| マルチプラットフォームサポート           | オンプレミス、AWS、他のクラウドプロバイダーなど、さまざまな環境からのリカバリをサポートします。 |

AWS Elastic Disaster Recovery FAQs

https://aws.amazon.com/jp/disaster-recovery/faqs/

:::note info
Q: AWS Elastic Disaster Recoveryとは？
A: 従来のオンプレミス型デザスタリカバリでは、ほとんどの時間**アイドル状態になっている重複したリカバリーサイトの維持**に高いコストがかかりますが、 Elastic Disaster Recovery ではコスト効率の良いAWSリソースを使用して、ソースサーバーの最新コピーをAWS上に維持することができます。AWS DRSを使用すれば、**アイドル状態のディザスタリカバリサイトのリソースとメンテナンスを削除してコストを削減し、訓練や復旧のために必要なときだけ完全復旧サイトの料金を支払う**ことができます。

Q: なぜAWSをディザスタリカバリサイトとして利用するのですか？
A：AWSのインフラは伸縮性に富んでいるため、ディザスタリカバリサイトをより迅速に拡張することができ、**使用した分だけ支払えばよい**のです。プライマリ環境から AWS にレプリケートするソースサーバーを追加・削除することができます。AWSをディザスタリカバリサイトとして利用することで、俊敏性、コスト削減、グローバルインフラ、セキュリティとコンプライアンスツールなど、クラウドの利点を利用することもできます。
:::
#### ソリューションは、あくまで、一例です。他の解決方法もあるので、参考程度にしてください。

#### 読んでいただき、ありがとうございました。