OmniAICreator/Qiita-1.07M huggingface dataset:
【読書メモ】「はじめて学ぶソフトウェアのテスト技法」(リー・コープランド)　セクション1 第三章

## 書籍情報
[はじめて学ぶソフトウェアのテスト技法(日経BP社)](https://bookplus.nikkei.com/atcl/catalog/05/P82510/)

## セクション1 ブラックボックステスト技法

### ブラックボックステストとは
- 要件と仕様書だけをよりどころにしたテスト戦略
- テスト対象ソフトウェアの内部パス、構造や実践に関する知識が不要

### ブラックボックステスト手順
1. 要件・仕様書を分析する
1. 仕様書をもとにして有効な入力値を選択する
無効値を検出して正しく処理することを確認するため、無効な入力値も選択する
1. それぞれの入力値に対して、期待する出力を決定する
1. 選択した入力値を使ったテストを作成する
1. テストを実行する
1. 実際の出力と期待する出力とを比較する
1. ソフトウェアが正常に機能しているかどうかを判定する

### ブラックボックステストの適用対象
- 単体テスト、統合テスト、システムテスト、受入テスト、すべてのレベルで適応可能
- ソフトウェアの規模が大きくなるほど、ブラックボックステストに頼らざるを得ない

### ブラックボックステストの難点
- テスト担当者はテスト対象ソフトウェア内部のどれだけの部分を網羅できたかを明確に知る術がない

### ブラックボックステストの利点
- テスト担当者が欠陥を見つけるための、有効かつ効率の高いテストのサブセット(下位集合)を選択できる。

　
## 第三章 同値クラステスト
### 同値クラステスト
- 十分なテストカバレッジを保ちながら、テストケースの数を管理可能な程度に減らすための技法
- 1つの条件を確かめるには、1つのテスト値だけでよい

<br>

- 条件範囲内の値を**同値**クラスと呼ぶ
    - 同値クラス内のあるテストケースで欠陥が検出された場合、同じ同値クラスの他のすべてのテストケースで同じ欠陥が検出される
    - 同値クラス内のあるテストケースで検出されない場合、同じ同値クラスの他のすべてのテストケースで同じ欠陥は検出されない
:::note warn
同値クラスの定義される仕様書が必要かつプログラマが適切なコードを書いていることが前提である
:::

### 無効な入力値についてのテストケースは必要か
- **場合による**
#### 契約による設計
- モジュールは事前条件および事後条件という用語を用いて定義される
- **事後条件** = モジュールが何をするか(数値計算、DBレコード更新、ファイルのオープンなど)
- **事前条件** = 事後条件を満たすためにモジュールに必要なものが何かを定義(ファイルが存在すること、ファイル名がわかること、ファイルの読み取りが可能なことなど)
- 事前条件が満足された状況でのテストケースしか作成しない
 
#### 防衛的設計** = モジュールはどんな入力でも受け付けるように設計される
- 正常な事前条件の場合には正常な事後条件を成立させる
- 異常な事前条件の場合にはエラーコードを返却or例外を発生させる
CORSってなぁに?

# 本記事の目的
本記事では、CORSについてザックリ理解することを目的としています。
CORSの必要性がわからない、初めてCORSという単語を見たという方は、本記事で理解を深めていただければ幸いです。
サンプルコードには、React、Expressなどを使用していますが、これらの技術を知らなくてもCORSの理解ができるように説明しています。

# CORSとは
まず、簡潔にCORSを説明すると**異なるオリジン間でデータを共有する仕組み**のことです。
では、オリジンとは何でしょうか?

## オリジンとは
オリジンとは、**実行したアプリのベースとなるURL**です。
例えば、プラットフォームによって以下のような初期オリジンが設定されます。
(※プラットフォームとは、アプリを実行する環境のことです)

| プラットフォーム | オリジン                             |
| -               | -                                    |
| ローカル環境     | http:\//localhost.3000               |
| Vercel          | https:\//myapp.vercel.app            |
| Render          | https:\//myapp.onrender.com          |
| AWS Amplify     | https:\//branch.myapp.amplifyapp.com |

## CORSの必要性
ブラウザは、このような異なるオリジン間でのデータの送受信を制限します。
この**制限を安全に緩和するためにCORSを使用**します。

# 実践
CORSの設定がどのように記述されるのか確認します。
確認には、クライアント/サーバ構成のアプリを用います。
ブラウザ画面のボタンを押下し、正常にサーバからのレスポンスを取得できたらブラウザ画面に「Success」と文字が表示されます。
ソースコード内のREDMEに環境構築方法を記載しています。
ソースコード: https://github.com/YutoOtake0015/cors-check
![demo.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1237378/201569ae-82e3-fbc7-eb69-3f4d4598b39a.gif)

## 構成
クライアント処理は**client**ディレクトリ、サーバ処理は**api**ディレクトリで管理します。
クライアント処理、サーバ処理は、別々に起動するため異なるオリジンを持ちます。
(※本記事内では、クライアント処理：http:\//localhost.3000、サーバ処理：http:\//localhost.5050)

```terminal
.
├── api
│   ├── package-lock.json
│   ├── package.json
│   └── server.js
└── client
    ├── package-lock.json
    ├── package.json
    ├── public
    │   └── index.html
    └── src
        ├── App.jsx
        └── index.js
```

## CORS未設定の処理を確認
CORSを未設定の場合の動作を確認します。
![err.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1237378/39c4d6d9-7057-4ece-22de-861d6e308bbe.gif)

値の取得に失敗し、エラーが表示されました。
この時のデベロッパーツールのコンソールパネルを確認してみましょう。
![err_dev_screen.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1237378/57bbc59f-0e76-8d3b-f07f-832498c727fb.png)
エラーが出力されており、`CORS`という文言を確認できます。

では、CORSの設定をして、サーバの値を取得できるようにします。

## CORSを設定
```server.js

import dotenv from "dotenv";
import express from "express";
import cors from "cors";

const app = express();
const PORT = process.env.PORT || 5050;

// 環境変数有効化
dotenv.config();

// CORS設定
const corsOptions = {
  origin: "http://localhost:3000",
};
// CORS設定を有効にする場合、以下1行のコメントアウトを解除してください
app.use(cors(corsOptions));

// 確認用エンドポイント
app.get("/check", (req, res) => {
  return res.send("Success");
});

// サーバ起動
app.listen(PORT, () => {
  console.log(`http://localhost:${PORT}`);
});
```

`app.use(cors(corsOptions));`によって異なるオリジンからのリクエストを受け付けています。
また、corsOptionsで受け付けるオリジンを明確に指定しています。
今回は、クライアントのオリジン`http://localhost:3000`を指定しています。
 (※実際のコーディングでは、オリジンなどの情報は環境変数に設定しましょう)

では、この時の動作を確認してみましょう。

![success.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1237378/58a39e68-5dae-0887-c22d-abfbbe96f46c.gif)

無事、サーバから値を取得できました！
【Linux】シェル環境

# シェル変数と環境変数の違い
## シェル変数
有効範囲はその変数を定義したシェルプロセスのみ。該当するシェルプロセスを終了すると，シェル変は失われる。**setコマンド**を実行すると表示。

## 環境変数
有効範囲は，その変数を定義したシェル上やそのシェルで実行されるプログラム上。シェル変数を**exportコマンド**でエクスポートすることで設定。
**envコマンド**や**printenvコマンド**，**setコマンド**を実行すると表示。

# シェルのオプション
| オプション | 説明 |
| ---- | ---- |
| allexport | 作成した変数を自動的にエクスポート |
| emacs | Emacs風のキーバインドにする |
| ignoreeof | Ctrl+Dでログアウトしないようにする |
| noclobber | 出力リダイレクトによる上書き禁止 |
| noglob | メタキャラクタを使用したファイル名展開を無効 |
| vi | vi風のキーバインドにする |

**set -o**でオプションを確認できる
```
User@User:~$ set -o
allexport       off
braceexpand     on
emacs           on
errexit         off
errtrace        off
functrace       off
hashall         on
histexpand      on
・・・
```

オプションを有効にする場合は次のようにする
```
User@User:~$ set -o noglob
```

逆に無効化する場合は次のようにする
```
User@User:~$ set +o noglob
```
Fungusの使い方　参考になるサイトのメモ【Unity】

## はじめに
Fungusの使い方
メモ


## 内容
導入

https://qiita.com/Kirikabu_ueda/items/bfc6e086d408b1cba34b

https://qiita.com/saba383810/items/2376e6d7602f197376af


より詳しく

https://qiita.com/Kirikabu_ueda/items/f1e53bdf8775bb146ce3

https://qiita.com/Jonny_dayo/items/0cad6a461dc7e15059b8

https://fineworks-fine.hatenablog.com/entry/2022/12/12/073000

https://kinokorori.hatenablog.com/entry/2019/08/24/000000
普段から使用しているオススメの機材紹介まとめ【モニター編】

# はじめに
普段は技術的な記事をメインに上げていますが、今回はお試しで普段から使用している機材をご紹介できたらと思います。
今回はモニターに限定してまとめていきますが、需要があれば他の機材類もご紹介していこうと思います。

# モニターその1: Dell U2720QM 27インチ

https://www.amazon.co.jp/gp/product/B085TWLMF9/ref=ppx_yo_dt_b_search_asin_title?ie=UTF8&psc=1

まずはメインモニターのご紹介です。
これまで何台もモニターは試してきましたが、最終的にこのモニターに落ち着いています。
27インチと使いやすいサイズで、何より4Kモニターになります。

このモニターを使用する前は、文字サイズなど見づらくなりそうなどの理由により4Kモニターは避けていました。
ある時、たまたま寄ったショップで見たモニターが4Kモニターで試してみたところ、非常に見やすい印象であった為、こちらの4Kモニターへ切り替えました。
27インチの中でも丁度良いと感じる情報量を表示することができ、何より4Kという画質からデザイン関連の確認をする際にも重宝しています。
このモニターを使用してしまうとメインモニターはもうフルHDには戻れなくなります。

ちなみにAmazonのセールだと通常よりかなり安く購入ができるので、検討されている場合はセール中の購入を強くお勧めします。

# モニターその2: MSI Modern MD2412P

https://www.amazon.co.jp/gp/product/B0CKYP32GG/ref=ppx_yo_dt_b_search_asin_title?ie=UTF8&psc=1

こちらはサブモニターとして使用しているモニターです。
メインモニターであるDellの27インチより小さいサイズの23.8インチになります。
なぜ小さいサイズにしているかというと、縦に使用しているからになります。
縦に使用することで、メインモニターと高さがぴったり合い非常に収まりが良くおすすめです。
サイズ感も丁度良く、Webを参照する際やドキュメントを参照する際など一目で確認することができ、この一台があるか無いかで作業効率が大きく異なります。
また、こちらのモニターは値段もお手軽で尚且つTypeC接続が可能です。
Macを使用している環境と相性がよく接続の手間を簡略化できる点も好印象です。
付属のモニタースタンドも自由度が高くコスパが良い機種と言えると思います、オススメです！

# モニターその3: EVICIV モバイルモニター 13.3インチ

https://www.amazon.co.jp/gp/product/B07PZ59J8Y/ref=ppx_yo_dt_b_search_asin_title?ie=UTF8&psc=1

最後にモバイルモニターのご紹介です。
ただ持ち運んで使用しているわけではなく、こちらもサブモニターとして使用しています。
おすすめの理由としては、Visaマウントに対応している点になります。
こちらはSlackなどのコミュニケーションツール専用として使用しているのですが、コンパクトなサイズ感が丁度良く、モニターアームも使用できるのでデスクを圧迫させずに使用できるのが素晴らしいです。
接続方法もHDMIやTypeCなどに対応しており、環境問わず接続方法を選べるのも使い勝手が良いですね。
リモートワークだとちょっとしたコミュニケーションロスから不信感に繋がるリスクがあるかと思いますが、このモニターがあれば見逃しのリスクを最小限にすることができるのでその点に不安を抱えている方は是非試してみると良いと思います。

# 番外編：モニター回りで便利なグッズ
せっかくなのでモニター自体ではなく、その関連のアイテムもご紹介したいと思います。
どれも長い間重宝しているアイテムで使い勝手も良くオススメです！

①サンワダイレクト モニター裏 収納ポケット

https://www.amazon.co.jp/gp/product/B093PML5HV/ref=ppx_yo_dt_b_search_asin_title?ie=UTF8&th=1

デスクが散らかりがちな方にはこの収納ポケットがオススメです。
モニター裏のデッドスペースを活用でき、尚且つ見えないので文房具とか普段あまり使用しないような物をしまっておくとデスクがスッキリします。

②ダイソー モニター用小物テーブル

https://jp.daisonet.com/products/4965534149136

モニター上に物が置けるようになるテーブルです。
モニター上のテーブルだとこちら小ぶりの部類に入るのですが、アロマ系のちょっとしたものを置くくらいならこれで十分です。
それ以外にも緑飾ったりするのにも良いですね、もう少し大きいものが欲しければAmazonに大きめのも売っていますのでそちらもオススメです。

③サンコー 3軸式くねくねモニターアーム

https://www.amazon.co.jp/gp/product/B003LKJST0/ref=ppx_yo_dt_b_search_asin_title?ie=UTF8&psc=1

こちらの商品、10個以上は買ってます(笑)
グネグネ細かく動くやつも便利ですが、ほとんどの場合これで十分です。
あと安くて色々動くやつはモニターによってお辞儀しちゃったりするのですが、その点このモニターアームはかなりしっかりした作りなのでお辞儀してしまうようなこともなく、安心して使用できます。

# さいごに
作業環境にはかなりこだわりを持っている方ですが、皆さんの環境でオススメのガジェットなどはありますか？
もしオススメのモニターやガジェット類があるようでしたらコメントでご紹介いただけると大変嬉しいです！
WindowsにPostgreSQLをインストールする（備忘録）

# 参考1
https://www.postgresql.jp/
# 参考2
https://lets.postgresql.jp/documents/tutorial/windows/

参考1で紹介してあったインストールガイド（参考2）に沿ってインストールを進める（ガイドはver8.4だが、最新のver16.1をインストールする）。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/545173/78d643dd-ffa9-e0e2-e0b8-07c3546770f1.png)

インストーラを実行するとすぐに全体的に文字化けしているエラーが出たのでインストール出来ず。
管理者のユーザー名が日本語なのが原因の可能性があるらしいとのことなので、ユーザー名を変更するなどして再度インストーラを実行するとエラーは出なかった。
実際には
「C:\user\日本語ユーザー名\AppData」ではエラーとなる
「C:\user\英数字のみユーザー名\AppData」ではエラー出ない
だった。

# 参考3
https://qiita.com/tom-sato/items/037b8f8cb4b326710f71

参考2ではやはりバージョンが違うなどで、ちょっとわからなかったので参考3のページを参考にさせていただき、インストールは完了した。

# 課題
* DBとの接続確認は出来たが、中身は空である
* 自動起動から手動起動に変更する
* psqlとかあんまりわかってない
pandas.DataFrame.applyの翻訳

# 基本形
```
DataFrame.apply(func, axis=0, raw=False, result_type=None, args=(), by_row='compat', **kwargs)
```
# 概要
- for文を使わなくてもデータフレームの行ごと、もしくは列ごとに関数を適用できる
以下コードは公式からそのまま使ってます
```
# 使用するデータフレームの例
>>> df = pd.DataFrame([[4, 9]] * 3, columns=['A', 'B'])
>>> df
   A  B
0  4  9
1  4  9
2  4  9
```

# パラメータ
## func：関数
適用する関数
- そのまま関数名を置け、lambda式もおける
```
>>> df.apply(np.sqrt)
     A    B
0  2.0  3.0
1  2.0  3.0
2  2.0  3.0
```

## axis：(0 か 'index', 1 か 'columns')
関数を適用する方向
- デフォルト値：0
- 0 か 'index'：それぞれの列毎に適用。行方向。
- 1 か 'columns'：それぞれの行毎に適用。列方向。
```
>>> df.apply(np.sum, axis=0)
A    12
B    27
dtype: int64
```
```
>>> df.apply(np.sum, axis=1)
0    13
1    13
2    13
dtype: int64
```

## raw：bool
対象がシリーズ型かndarray型か
- デフォルト値：False
- False：各行か各列をシリーズ型で関数に渡す
- True：Numpyのndarray形式のオブジェクトを受け取る。Numpyの関数を使用する際高速になる

## result_type：(‘expand’, ‘reduce’, ‘broadcast’, None)
axis = 1の時のみ発動
- デフォルト値：None
- 'expand'：リストをシリーズ、データフレームに変更
- 'reduce'：シリーズをリストに変更
- 'broadcast'：元のインデックスや列を保持したデータフレーム型を返す
- None：戻り値は関数に依存。リスト型はシリーズ型で返されるが、関数がシリーズ型を返す場合列として返す
```
>>> df.apply(lambda x: [1, 2], axis=1)
0    [1, 2]
1    [1, 2]
2    [1, 2]
dtype: object
```
```
>>> df.apply(lambda x: [1, 2], axis=1, result_type='expand')
   0  1
0  1  2
1  1  2
2  1  2
```
```
>>> df.apply(lambda x: pd.Series([1, 2], index=['foo', 'bar']), axis=1)
   foo  bar
0    1    2
1    1    2
2    1    2
```
```
>>> df.apply(lambda x: [1, 2], axis=1, result_type='broadcast')
   A  B
0  1  2
1  1  2
2  1  2
```

## args：tuple
関数に渡す位置引数

## by_row：False か 'compat'
関数がリスト型や辞書型の時にのみ発動。
関数を各要素に対して適用するか、全体に一度に適用するかを決定
- デフォルト値：'compat'
- 'compat'：各要素に対して適用。一度関数をPandasのメソッドに変換を試みて、それが出来ない場合にapplyを再度呼び出し、それでもダメならFalseの処理
- False：全体に一度に適用

## **kwargs
関数に渡す追加のキーワード引数

# 戻り値
シリーズかデータフレーム

# ドキュメント
https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.apply.html
駄目グラフ005

Python/seaborn の swarmplot/stripplot であるが，データポイントが重ならないように「妙な小細工」をする。その小細工が「データに意味ありげな表現」をしてしまう。
グラフを見る人に，潜在的な歪みを強要する。

なんか，非対称だとか，全体的に（まるでクリスマスツリーみたいに）上向き傾向。

![スクリーンショット 2024-01-21 21.33.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2611739/f41d6a8f-c006-e78e-792e-0dbe1f5cc720.png)

左右対称でないのは何らかの傾向が見えたり，横方向の散らばりは枠があるようで，もっとたくさんのデータがあると，グッチャリ固まるのは目に見えている。
![スクリーンショット 2024-01-21 21.34.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2611739/3415fa1e-c8af-6ec1-cfc0-4ec701cfd482.png)

データの表現は「ありのあま」というのが原理原則だと思うのだ...

これで，いいだろ?

![スクリーンショット 2024-01-21 21.33.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2611739/88860a2b-c260-7548-966d-b7973128ba35.png)

異論:「だって seaborn にあるんだからいいグラフなんじゃない?」

反論:「駄目グラフの典型と言われている円グラフだってあるでしょ。」
Macで擬似グローバルホットキー（VSCodeで写経中にプレビューのページをめくる）

常々MacはWindowsと違ってグローバルホットキーの設定が殆どなく不便だと感じていました。
特に困っていたのがVSCodeでPDF技術書の写経をしているときにページを捲るためにわざわざフォーカスをプレビューアプリに合わせてまたVSCodeに戻るという作業で、とても煩わしく感じていました。
それがBetterTouchTool(以降BTT)を使うことでほぼ解決できたので共有です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2380862/03ee956c-991d-d89c-011b-3a69ddf2f16f.png)

BTTの機能として別のappを起動するというものがあります。こちらを使って「プレビューアプリを選択→ページをめくる→VSCodeを選択」というマクロを登録してやることで擬似的にグローバルなホットキーを作ることができました。（特定のアプリにショートカットキーを送信といういかにもなコマンドもあるのですが、不具合なのか動作しませんでした。）
私はこのマクロを外付けの１０キーパッドに割り当てています。（StreamDecmとかの方が今時ですね。）

何かの参考になれば幸いです。

追記
BTTをアップデートしたら「特定のアプリにショートカットキーを送信」が使えるようになりました。v4.375
【Unity】テキストのスキップの実装

## 実装したもの
まず、今回実装したものの説明。

RPGとかのセリフでよくある文字が一文字ずつ表示されるあれを実装したのだがスキップできないのでテキストをいちいち待たないといけない。

そこで、タップしたときに表示を一気に終わらして早く進めるようにした。
![text.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3679145/1e82c5af-fdea-a799-b998-c6a0e05e05a8.gif)

## プログラム
### スキップ実装前のプログラム

まず、最初のスキップできないときのプログラムの確認。
```c#:実装前
for(int i = 0;i < tutorialTexts.Length;i++){
    fullText = tutorialTexts[i];
    for (int j = 0; j <= fullText.Length; j++){
        currentText = fullText.Substring(0, j);
        tutorialText.text = currentText;
        
        //文字の出現時間の間隔
        yield return new WaitForSeconds(0.1f);  
    }
    
    //マウスが押されるまで待機
    yield return new WaitUntil(() => Input.GetMouseButtonDown(0));
    
    callToClick.SetActive(false);
}
```
【解説】
まず補足としてコルーチンの中でこのfor文を動かしています。
tutorialTextにチュートリアルの文章を全文保存。
fullTextには一回に表示するテキストを保存。
currentTextは現在表示中のテキスト。
そこにfullTextから一文字ずつ取り出して更新。繰り返しの最後に0.1秒待機して一文字ずつ表示されるテキストにする。

＊callToClickは右下のTap>>>のオブジェクト、表示・非表示をプログラム内で管理。
＊Input.GetMouseButtonDown(0)は右クリックされているかのプログラムだが、スマホではタップに対応

### スキップ実装後のプログラム
実装後のプログラムがこちら
```c#:実装後コルーチン内
for(int i = 0;i < tutorialTexts.Length;i++){
      fullText = tutorialTexts[i];
      for (int j = 0; j <= fullText.Length; j++){
        currentText = fullText.Substring(0, j);
        tutorialText.text = currentText;
        
        //以下を追記
        if(skipText){
          break;
        }
        
        //文字の出現時間の間隔
        yield return new WaitForSeconds(0.1f);  
    }
    
    tutorialText.text = fullText; //追記
    
    callToClick.SetActive(true);
    //マウスが押されるまで待機
    yield return new WaitUntil(() => Input.GetMouseButtonDown(0));

    //以下を追記
    skipText = false;
    yield return new WaitForSeconds(0.01f);
    
    callToClick.SetActive(false);
}
```
```c#:実装後コルーチン外
void Update(){
  if(game.instance.isTutorial){
    if(Input.GetMouseButtonDown(0)){
      skipText = true;
    }
  }
}
```
【解説】
bool型のskipTextを追加し、テキストをスキップするかループ毎に判定。
タップされたかの判定だが、for文内では0.1秒待機の間判定されないので、コルーチン外で毎フレーム確認。
タップを確認したら、break文でforループを抜け出しfullTextを表示させる。
もう一度タップされたら次のテキストに変え、skipTextをfalseに戻す。

## まとめ
今回コルーチン内でforループをbreakで抜け出すという処理を扱った。コルーチンはプログラムの一時停止、再開を実現させるものらしく、そのため待機中はコルーチンが止まる。

今回のような処理途中の判定はコルーチン外で書いて、bool型で送るのが良さそう。
【Azure】Windows ServerのGUIが表示されない時の対処法

## 起きたこと
 - Azure上でWindowsサーバを新規作成したが、作成したサーバにRDPした際にCLIでしか操作できなかった。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/992240/3af7d786-249b-53ed-dd9b-6f99f5d77b01.png)
```
WARNING: To stop SConfig from launching at sign-in, type "Set-SConfig -AutoLaunch $false"

  ================================================================================
                      Welcome to Windows Server 2022 Datacenter
  ================================================================================

    1)  Domain/workgroup:                   Workgroup: WORKGROUP
    2)  Computer name:                      AD01
    3)  Add local administrator
    4)  Remote management:                  Enabled

    5)  Update setting:                     Manual
    6)  Install updates
    7)  Remote desktop:                     Enabled (more secure clients)

    8)  Network settings
    9)  Date and time
    10) Telemetry setting:                  Required
    11) Windows activation

    12) Log off user
    13) Restart server
    14) Shut down server
    15) Exit to command line (PowerShell)

  Enter number to select an option: 
```
 - 調べたところ、GUIのあるサーバを作成するためには、「デスクトップエクスペリエンス」と記載のあるOSでサーバを作成する必要があるとのこと

 ## 対応
  - 「デスクトップエクスペリエンス」に対応したOSでVMを作成する。
      - Windows (Windows Server 2022 Datacenter Azure Edition)
 - 無事GUIが表示された
 - ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/992240/9e8053ae-76e2-f67b-f70f-36c64d9f609f.png)
DWHの王様「BigQuery」について

![Bigquery.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1180499/65cc84ba-4405-6e53-8644-649e6665aebc.jpeg)


## 概要
データ活用に必須となるインフラであるデータ基盤

使いたいデータを素早く取得できることはデータ分析プロジェクトの成功となる基本

今回はそんなインフラであるデータの貯蔵庫となるDWHで圧倒的なパフォーマンスを発揮しているBigqueryを改めて紹介したい。

## BigQueryのルーツ

2004年：MapReduceに関する分散処理の論文発表

社内でのストレージとして利用していたのが、GoogleFileSystemだが、分散ファイルシステムを用いて、数千にもなる共有ファイルに同時にアクセスできるように設計された。

2010年SQLを利用して分析可能となり、ユーザーのデータ分析を可能にすることで、BigQueryの提供開始した。

## マルチテナント方式を採用している

BigQuery：マルチテナント方式

Googleが事前にプロビジョニング（事前予測準備）して管理するリージョンレベルの大規模プールに対して、動的クエリに必要なリソースを割り当てる

プロビジョニングおよびクラスタを保持することによるコストは発生しない

データの保持：ストレージ側

クエリの実行：コンピュート側

、完全に独立してスケーリングすることが可能


## なぜ障害に強く高速なのか

Bigqueryの強さの源泉である耐久性と高速性である。

### 高速の理由＝分散処理ではないから
分散処理を実行する場合には余分性が生まれるが
#### 「分散インメモリシャッフル」
を導入することにより高速になり
障害が発生しても別ワーカーに割り振れるので障害に強いのである。

#### データスキャンが高速になる理由

#### 一般的なデータベースと違って列指向だから

データの列指向のファイルフォーマットにデータ圧縮している
（Capacitorファイル）
一般的な行指向データベースに比べ、高速にデータのスキャンが可能なのである。

## 料金について

契約形態が「クエリ実行データのスキャン量で課金されるオンデマンド分析方式」
と「スロットを事前購入する定期料金」が存在

23年7月料金改定があり
#### 現在はクエリ(オンデマンド)$6.00 (約830円) / TB
毎月 1TBまで無料


行指向型(RDBMS). 列指向型(BigQuery)
• データは列ごとに格納されるため
必要な列のみの読み取りが可能
• クエリ内で不用意にSELECT*FROMを利用しない
BigQueryは読み込むデータ量に対して課金が行われる


## 最大のネックとなる料金対策について

• 全件取得となるSELECT * を避ける
先ほど記載した通り、BQはカラムナストレージなので、列単位でフルスキャンが実行され
そのため集計に必要なカラムのみを明示的に記載する必要あり

• テーブルのパーティション・クラスタ化
日付カラム等をパーティション化することで、フルスキャンを割けて必要なデータのみを読み混み可能
ただし、パーティションは最大4000までしか分割できませんクラスタ化テーブルの概要テーブル内の1つ以上のカラムを利用して、データを並び替えることが可能
フィルタとしてクラスタリング列を利用することで、余計なデータのスキャンを省略可能

• 一時テーブルの利用
BQには2種類のテーブルがある(一時と宛先テーブル)一時テーブル通常のDBでいうクエリキャッシュにあたり、最大24時間まで補完される

### 参考
[Google Cloud Platform 実践 ビッグデータ分析基盤開発ストーリーで学ぶGoogle BigQuery](https://www.amazon.co.jp/Google-Cloud-Platform-%E3%83%93%E3%83%83%E3%82%B0%E3%83%87%E3%83%BC%E3%82%BF%E5%88%86%E6%9E%90%E5%9F%BA%E7%9B%A4%E9%96%8B%E7%99%BA%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AA%E3%83%BC%E3%81%A7%E5%AD%A6%E3%81%B6Google-BigQuery-ebook/dp/B0824F8ZZD/ref=sr_1_1_sspa?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&crid=1WBAPHRHP665L&keywords=bigquery&qid=1705839350&s=books&sprefix=bigquery%2Cstripbooks%2C234&sr=1-1-spons&sp_csd=d2lkZ2V0TmFtZT1zcF9hdGY&psc=1)
[GCPの教科書](https://www.amazon.co.jp/GCP%E3%81%AE%E6%95%99%E7%A7%91%E6%9B%B8-%E3%82%AF%E3%83%A9%E3%82%A6%E3%83%89%E3%82%A8%E3%83%BC%E3%82%B9%E6%A0%AA%E5%BC%8F%E4%BC%9A%E7%A4%BE-%E5%90%89%E7%A9%8D-%E7%A4%BC%E6%95%8F%E3%83%BB%E4%BB%96/dp/4865941959/ref=sr_1_20?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&crid=1WBAPHRHP665L&keywords=bigquery&qid=1705839350&s=books&sprefix=bigquery%2Cstripbooks%2C234&sr=1-20)
ros2のsetup.pyで入れ子（ネスト）のディレクトリもshareディレクトリに追加する方法

お疲れ様です。秋並です。<br>
今回は、ros2でpython用のパッケージを作成する際にsetup.pyの記述で詰まったところがあったので、その解決方法について解説します。<br>

### 前提
ros2のワークスペースでpython用パッケージを作成する手順が分かっている。
### 実行環境
ubuntu22.04
ros2 humble

---

setup.pyでshareディレクトリにデータを追加する際に
`meshes/dae`のような入れ子構造になったディレクトリを追加したい時があると思います。
```plaintext
package_name
|
---meshes
    |
    ---dae
        |--- OOO.dae
        |--- ***.dae
```

<br>
<br>

デフォルトのsetup.pyに従って以下のように記述するとエラーが発生します。

例えば、以下のように `meshes/dae`以下のファイルを指定した場合 `error: can't copy 'meshes/dae': doesn't exist or not a regular file`というエラーが発生します。

```python
from setuptools import setup
import os
from glob import glob

package_name = 'package_name'

setup(
    name=package_name,
    version='0.0.0',
    packages=[package_name],
    data_files=[
        ('share/ament_index/resource_index/packages',
            ['resource/' + package_name]),
        ('share/' + package_name, ['package.xml']),
        (os.path.join('share', package_name, 'launch'), glob('launch/*.launch.py')),
        (os.path.join('share', package_name, 'urdf'), glob('urdf/*')),
        (os.path.join('share', package_name, 'meshes'), glob('meshes/*')),
        (os.path.join('share', package_name, 'meshes/dae'), glob('meshes/dae/*')), # この箇所が上手く反映されず「error: can't copy 'meshes/dae': doesn't exist or not a regular file」とエラーが発生する
        (os.path.join('share', package_name,
    ],
    install_requires=['setuptools'],
    zip_safe=True,
    maintainer='author',
    maintainer_email='todo@todo.com',
    description='The ' + package_name + ' package',
    license='TODO: License declaration',
    tests_require=['pytest'],
    entry_points={
        'console_scripts': [
        ],
    },
)
```

<br>

これを改善するには、以下のように記述するとよいです。
```python
from setuptools import setup
import os
from glob import glob

package_name = 'package_name'

data_files = []
data_files.append(("share/ament_index/resource_index/packages", ["resource/" + package_name]))
data_files.append(("share/" + package_name, ["package.xml"]))

def package_files(directory, data_files):
    for (path, directories, filenames) in os.walk(directory):
        for filename in filenames:
            data_files.append(("share/" + package_name + "/" + path, glob(path + "/**/*.*", recursive=True)))
    return data_files

data_files = package_files('launch/', data_files)
data_files = package_files('urdf/', data_files)
data_files = package_files('meshes/', data_files)
data_files = package_files('meshes/dae', data_files) # これの場合、エラーが出ない


setup(
    name=package_name,
    version='0.0.0',
    packages=[package_name],
    data_files=data_files,
    install_requires=['setuptools'],
    zip_safe=True,
    maintainer='author',
    maintainer_email='todo@todo.com',
    description='The ' + package_name + ' package',
    license='TODO: License declaration',
    tests_require=['pytest'],
    entry_points={
        'console_scripts': [
        ],
    },
)
```

# 参考サイト
[ROS 2 : Pythonでパッケージ作成するときのチップス](https://zenn.dev/tasada038/articles/f2f5b500cdc36a)
【Android】Mathクラスについてpart３【Kotlin】

# はじめに
以前Mathクラスについての記事を書いたのですが、今回また別のものを使ったので
忘れないために記事にしておきます。

https://qiita.com/Tsubasa12/items/709cbd01b1abbfe8e209

https://qiita.com/Tsubasa12/items/11ca4b2243a89abefd26

# toRadians()
```
toRadians(30.0)   // 0.5235987755982988
```
角度を指定するとラジアン単位に変換する

# toDegrees()
```
toDegrees(0.52)   // 29.79380534680281
```

# 参考
https://www.dainippon-tosho.co.jp/unit/list/radian.html
【学びメモ】async letを用いた並列処理でタスク結果の取得タイミングを変えたい時の実装方法

# 本記事について

Swift Concurrencyを用いた並列処理において、曖昧な理解で実装していたのでメモとして残します。

`async let`を用いて並列処理を行う際、実装方法によってタスク結果の取得タイミングを変えることが可能です。

# 具体例

以下、2パターンの挙動の実現が可能になります。

- パターン1：両方のタスクが完了するまで待機してから、両方の結果を同時に取得
- パターン2：各タスクの結果が利用可能になるとすぐにそれを取得し、次の結果の取得を待つ


もう少しイメージしやすいように、イメージ図とコードを示します。

## パターン1

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3368292/15a6452e-e48e-5c23-8936-c001bae55804.png" width=400>

```Pattern1.swift
async let response1 = fetch1()
async let response2 = fetch2()

let results = await (response1, response2)
```

## パターン2


<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3368292/96ea8ec4-2bf4-37cb-fca9-2702cd69880c.png" width=400>

```Pattern2.swift
async let response1 = fetch1()
async let response2 = fetch2()

let result1 = await response1
let result2 = await response2
```



# 実装内容

Playgroundでコピペで動きます。

※ エラーハンドリングは無視しています。

```ParallelProcessingSample.swift

func fetch1() async -> String {
    // 1秒のdelay
    try? await Task.sleep(nanoseconds: 1 * 1_000_000_000)
    return "Result from fetch1"
}

func fetch2() async -> String {
    // 2秒のdelay
    try? await Task.sleep(nanoseconds: 2 * 1_000_000_000)
    return "Result from fetch2"
}

// パターン1のテスト
func testPattern1() async {
    async let response1 = fetch1()
    async let response2 = fetch2()

    // response1, 2両方の結果が利用可能になるまで待機
    let results = await (response1, response2)
    print(results)
}

// パターン2のテスト
func testPattern2() async {
    async let response1 = fetch1()
    async let response2 = fetch2()

    let result1 = await response1
    let result2 = await response2

    // response1の結果が利用可能になるまで待機し、
    // その後、response2の結果が利用可能になるまで待機
    // resuponse1の結果が先に利用可能になればresult1の代入が行われ、response2の結果を待つ
    print(result1, result2)
}

// 非同期関数を実行
Task {
    await testPattern1()
    await testPattern2()
}

```


以上です。

## 参考文献

- [Swift の「async let ...」と「TaskGroup」の使い分け早見表](https://zenn.dev/dena/articles/0c4f7a8232e64b#async-let-...-%E3%81%AE%E5%9F%BA%E6%9C%AC)
【Unity】ゲーム画面の大きさについて

Unityの実装で難しかったところのメモ
## 今回の問題点
ゲーム画面を壁で囲ったのだがゲームオブジェクトだと画面サイズの変化に対応できない。

![スクリーンショット 2023-04-12 124531.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3679145/37197d30-5876-4841-6ee6-487c9d3fabfb.png)

UIにすれば解決するのだが、今回はブロック崩しを作りたいので壁に当たり判定も欲しい、UIにcolliderをつけてもゲーム画面の比率が変わったときに変わるのは見た目だけでcolliderの大きさは変わらない。

そこで解決策としてスクリーンサイズを取得し、それに合わせてオブジェクトの大きさを変える方法を考えた。

## 解決した方法
スクリーンサイズを取得し、カメラやオブジェクトの大きさを調整する。（これが最善かはわからない）
### 1. スクリーンサイズの取得
スクリーンサイズは以下のプログラムで取得可能
```c#
float w = Screen.width;
float h = Screen.height;
```
非常に簡単。これを用意した変数に入れれば自由に値を使える。

＊備考＊
上記の方法で入手できる値はゲーム画面のサイズなので、実行しているデバイスの画面サイズを取得したい場合はScreen.CurrentResolution.width, heightで取得できる。
### 2. 開発画面と画面サイズとの比率を求める
まず、開発画面の画面サイズを変数に入れる。

![スクリーンショット 2023-04-12 124531_edited.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3679145/4759d4bb-6922-8c86-7525-a6f724c87c5a.jpeg)

この例ではこんな感じ
```c#
const float defaultWidth = 2960;
const float defaultHeight = 1440;
```
開発画面のサイズは変更される予定がないのでconstで定数としておく。

次に実際に比率の計算
```c#
//開発画面のアスペクト比
float defaultAspect = defaultWidth / defaultHeight;

//実機でのアスペクト比
float realAspect = Screen.width / Screen.height;

//実機と開発画面の比率
float ratio = defaultAspect / realAspect;
```
あとはこの求めた比率を用いてオブジェクトやカメラのサイズをいじって、画面に合うようにしてあげればよい。

### 3. 実装
値を取得し計算ができたので実装したいのだがここで一つ問題がある。画面に合わせてオブジェクトのサイズを変更するとブロック崩しのボールが動くことができる領域の大きさも変わってしまう、これではデバイスによって挙動が変わってしまうのでよくない。

この解決策として壁のオブジェクトの大きさは変えずカメラを操作することで画面を調整する方法がよさそう。

今回のゲームは横持ちを想定しているので縦の幅がどのデバイスでも一致するようにカメラを調整する。そのため横の余白の広さはデバイスによって変わる。

この方法の注意点は余白が少なすぎると様々な画面サイズに対応できないという点である。

その対応としてUIでプレイヤーが操作するボタンやスティックを余白部分に設置しスペースの無駄をなくす。（画面の余白が少ない時にUIがボールが動く領域にはみ出さないように注意する必要はある）
GitHub ActionsをArtifacts v4にアップデートメモ


https://docs.github.com/en/actions/using-workflows/storing-workflow-data-as-artifacts

https://dev.classmethod.jp/articles/github-actions-artifacts-v4-now-generally-available/

自分用に使ってたものを更新したメモです。

特に問題なく動作

## actions/checkout@v3 -> actions/checkout@v4

https://github.com/actions/checkout

```yml
      - name: Code Checkout
        uses: actions/checkout@v4
```

## actions/setup-node@v3 -> actions/setup-node@v4

Node.js周り

https://github.com/actions/setup-node

```yml
      - name: Set up Node.js version
        uses: actions/setup-node@v4
        with:
          node-version: '20.x'
```

## actions/cache@v3 -> actions/cache@v4

```yml
      - uses: actions/cache@v4
        id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
        with:
          path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
          key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
          restore-keys: |
            ${{ runner.os }}-yarn-
```

## actions/upload-artifact@v3 -> actions/upload-artifact@v4

```yml
      - name: Upload artifact for deployment job
        uses: actions/upload-artifact@v4
        with:
          name: node-app
          path: release.zip
```
 

## actions/download-artifact@v3 -> actions/download-artifact@v4

```yml
    steps:
      - name: Download artifact from build job
        uses: actions/download-artifact@v4
        with:
          name: node-app
```

## azure/webapps-deploy@v2 -> azure/webapps-deploy@v3

https://github.com/Azure/webapps-deploy/tree/v3 ここはv4ではなくv3が最新ぽい

```yml
      - name: 'Deploy to Azure Web App'
        id: deploy-to-webapp
        uses: azure/webapps-deploy@v3
        with:
          app-name: 'prototoout-bot'
          slot-name: 'Production'
          publish-profile: ${{ secrets.AZUREAPPSERVICE_PUBLISHPROFILE_0F5266BBB77546048B43894ED5F1A357 }}
          package: release.zip

```
Docker上に uWSGIを使ったFlask環境を構築し、Apache経由で接続する

# はじめに
図のような構成です。

![uwisgi.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/541739/fe444389-e26b-8086-3cf4-dc4f21794389.png)


①uWSGIを使ってFlask環境を構築
②Apache経由で接続する(`http://host/api` で接続)
で書き進めます。


# 確認環境
- WSL2(Ubuntu22.04.3 LTS)
- Docker (24.0.6)
- Docker Compose (2.4.1)
- Python 3.12.1 
- Apache 2.4.58 

# ①uWSGIを使ってFlask環境を構築

## フォルダ構成

```
[projectfolder]
 ├─ Dockerfile
 ├─ compose.yml
 └─ api
      ├─ main.py
      └─ uwsgi.ini
```

## 各コード
```Dockerfile:Dockerfile
# ビルドイメージ
FROM python:3.12-slim-bookworm

# パッケージ更新
RUN apt-get -y update
RUN apt-get -y install \
    gcc 

# Flaskとuwsgiをpipで取得
RUN python -m pip install Flask uwsgi

```

```yaml:compose.yml
services:
  app:
    build:
      context: .
    volumes:
      - ./api:/usr/local/src/api
    ports:
      - "8000:8000"
    tty: true
    entrypoint: >
      sh -c "
        cd /usr/local/src/api &&
        uwsgi --ini uwsgi.ini
      "
```

```python:api/main.py
from flask import Flask, jsonify

app = Flask(__name__)

@app.route("/hello")
def hello():
    return jsonify({
        "message": "Hello World!"
    })
```

```ini:api/uwsgi.ini
[uwsgi]
# ソケット設定
socket=0.0.0.0:8000

# HTTPで実行もできる
# http=0.0.0.0:8000

# 実行するuswgiファイル
wsgi-file=./main.py
# wsgi-fileで実行するアプリケーション
callable=app

# マスターモード指定
master=true
```

## コンテナ立ち上げ
```shell:bash実行
cd [projectfolder]
docker compose up -d --build
```

## ざっくり解説
- pythonが3.13.X になると、uwsgiがインストールできない
    ※ 3.11.7 でもインストール可能なことは確認済み
- gccを入れないとpipでuwsgiがインストールできない


# ②Apache経由で接続する
## フォルダ構成
[こちら](https://qiita.com/naozo-se/items/2d7d0135c97081eb114e)を参照


## 各設定ファイル（上記リンク先からの修正分のみ）

```yaml:compose.yml ※同一端末内想定
    extra_hosts:
      - host.docker.internal:host-gateway 
```


```conf:conf/httpd.conf ※以下をコメントアウトして、モジュール追加
LoadModule proxy_html_module modules/mod_proxy_html.so
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_uwsgi_module modules/mod_proxy_uwsgi.so
```

```conf:conf/extra/proxy-html.conf ※リバースプロキシ追加設定
<Location /api/>
	ProxyPass uwsgi://host.docker.internal:8000/
    ProxyPassReverse uwsgi://host.docker.internal:8000/
</Location>
```

## 確認
`http://localhost/api/hello` にブラウザで接続して、リクエストしてください。

# 最後に
Apacheの情報少ない…


# 参考
https://qiita.com/hiren/items/4ed438303659125490b5

https://roy-n-roy.nyan-co.page/Docker/%E3%82%B3%E3%83%B3%E3%83%86%E3%83%8A%E5%8C%96/Django/
Azure WebAppsでのNode.jsのバージョンを上げる


Azure WebAppsにアプリケーションデプロイしてると無限に見る以下のエラー。バージョンアップ時におきました。

> :( Application Error
> If you are the application administrator, you can access the diagnostic resources.

> ![スクリーンショット 2024-01-21 20.43.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35387/da055a52-7e5e-5953-32c8-3be94d6c492b.png "スクリーンショット 2024-01-21 20.43.47.png")

Node.jsのバージョンを上げたいなと思ってpackage.jsonの指定を上げたところ発生しました。

GitHub Actions経由でWebAppsにデプロイしているアプリケーションですが、GitHub Actionsでの指定では関係ないみたいですね。

## ログストームで確認

ログストリームをみたら以下のようなエラーがでてました。

> ![スクリーンショット 2024-01-21 20.44.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35387/44ad043f-e935-2f7a-da69-cb2bea1dabb1.png "スクリーンショット 2024-01-21 20.44.42.png")

```
error protoout-discord-bot@0.2.1: The engine "node" is incompatible with this module. Expected version ">=20.0.0". Got "18.17.1"
```

## 構成 -> 全般設定から変更

package.jsonやGitHub Actionsでの指定だけではなく、ここでも設定が必要です。

> ![スクリーンショット 2024-01-21 20.43.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35387/0b96d1ca-a0ab-0d6e-6597-3e9ad87cc3c4.png "スクリーンショット 2024-01-21 20.43.29.png")

確かにもともとAzureポータルだと`Node - 18-lts`の表示だったけど`Node - 20-lts`に更新されました。

> ![スクリーンショット 2024-01-21 20.49.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35387/95c0e8fd-176e-f185-012d-4656a7238067.png "スクリーンショット 2024-01-21 20.49.16.png")

↓

> ![スクリーンショット 2024-01-21 20.55.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35387/486a6050-4956-1173-7ed6-66d0c03d101c.png "スクリーンショット 2024-01-21 20.55.44.png")
値型と参照型

値型と参照型について説明します。

## 値型
値型の変数はデータを直接格納します。
構造体、列挙型が値型になります。

```swift
var a = "apple"

//変数bにaを代入する
var b = a
```

:::note info

ゲームのヒィールド上にaという名前でりんごが召喚される(インスタンス化)
りんごが複製されて、bという名前でヒィールド上に召喚される
ヒィールド上にりんごが2個置かれている状態
:::

ヒィールド上に実体化した🍎がそれぞれ存在しているので、**どちらかの値を変化させても影響しないのが値型の特徴**です。代入の際に値がコピーされるのが値型になります。

```swift
var a = "apple"
var b = a
//変数aにbananaを代入する
b = "banana"

print(("a:\(a)")
print("b:\(b)")

- - - - - - - - - - - - - - - - - - - - -
a:apple //b = bananaによって影響は受けない
b:banana
```






## 参照型
参照型の変数はデータ (オブジェクト) への参照を格納します。
クラスが参照型になります。


```swift
// フルーツクラス作成する
class Fruit {
    var name: String
    
    init(name: String) {
        self.name = name
    }
}

var a = Fruit(name: "apple")
// bにaを代入
var b = a

// 変数aのインスタンスのnameプロパティをbananaに変更する
a.name = "banana"

print("a: \(a.name)")
print("b: \(b.name)")

- - - - - - - - - - - - - - - - - - - - -
a:banana //b = bananaによって変更されている
b:banana
```
:::note info

ゲームのヒィールド上にaという名前でりんごが召喚される(インスタンス化)
りんご自体は複製されず、りんごが召喚された座標がコピーされる
ヒィールド上にりんごが1個置かれている状態
:::
**代入の際に値ではなく、データ自体への参照先を渡すのが参照型**。
変数aの参照先が変数bにコピーされているため、`a.name = "banana"`で変数aの値を変えた場合でも変数bが参照している座標は同じであるため、値の変更に影響を受けてしまう。

※ここでの参照とはデータ自体が保存されているメモリ上の領域のアドレスのことを指す。

## まとめ
変数、定数をコピーしたときに値型と参照型に違いがある。

**値型：インスタンスがコピーされる**
**参照型：参照先がコピーされる**
Modernizing Drupal 10 Theme Developmentを読んで


2023年に発売されたDrupal書籍の中から [packt](https://www.packtpub.com/) から発売された「[Modernizing Drupal 10 Theme Development](https://www.packtpub.com/product/modernizing-drupal-10-theme-development/9781803238098) 」のレビューします。

Drupal テーマ関連は2016年に発売した「Drupal 8 Theming with Twig」　以降、新作はなくDrupal 10で待望の書籍です。

# 対象者
Drupal のフロントエンドとバックエンド向け。

# 構成
書籍は15章構成で以下のとおりです（和訳済み）。
1. ローカル環境のセットアップ
2. 新しいテーマの作成とビルドプロセスのセットアップ
3. Drupal が HTML ページをレンダリングする方法
4. デザインを Drupal コンポーネントにマッピングする
5. ヘッダーとフッターのスタイルを設定する
6. コンテンツのスタイル設定
7. フォームのスタイリング
8. ビューのスタイリング
9. スタイリングブロック
10. スタイルのメンテナンス、分類法、検索結果、および 403/404 ページ
11. 単一ディレクトリコンポーネント
12. カスタム Twig 関数とフィルターの作成
13. テーマを構成可能にする
14. パフォーマンスとアクセシビリティの向上
15. 分離されたフロントエンドの構築

### 1. ローカル環境のセットアップ
Drupal をDocker、DDEV、Visual Studio Codeなどを使い、ローカル環境で動かす方法を説明しています。
デモサイトをGithubからクローンして、settings.phpの詳細な説明がされています。
[Modernizing-Drupal-10-Theme-Development
](https://github.com/PacktPublishing/Modernizing-Drupal-10-Theme-Development)

### 2. 新しいテーマの作成とビルドプロセスのセットアップ
デフォルトテーマ、コントリビュート、購入したテーマ、カスタムした際のメリット・デメリットの指摘しています。Drupal 10　の新しいスターターキットの導入方法や Tailwind CSS や webpack、browsersync、BackstopJSやコーディング標準や継続的統合パイプラインなども学ぶことができます。

### 3. Drupal が HTML ページをレンダリングする方法
Drupal のレンダリングについて説明しています。テンプレートとは、レンダー配列、フック、CSSやJavaScriptの挿入方法、現状のjQueryの扱い、コントローラーのアクションについて学ぶことができます。

### 4. デザインを Drupal コンポーネントにマッピングする
グラフィックレイアウトからDrupalのコンポーネントに落とし込んでモックアップを作っていくかを説明しています。デザインシステム、デザイントークン、アトミックデザイン、Storybookなど内容は充実です。

### 5. ヘッダーとフッターのスタイルを設定する
前章からの続きでデモサイトのヘッダとフッターのスタイルを説明します。リージョン、ブロック、Twig の自動エスケープ
、テンプレートのオーバーライドや *.themeからテンプレートの前処理まで学ぶことができます。

### 6. コンテンツのスタイル設定
この章ではエンティティ、バンドル、フィールド、表示の管理、画像スタイル、メディア、分類法について説明しています。また、CKEditor 5 や WYSIWYG エディターをカスタマイズする方法、Paragraphモジュールのコンテンツ構築や管理を学べます。

### 7. フォームのスタイリング
Drupal のログインページのフォームからWebProfilerモジュールからコントローラーの確認、フォームの動きや構造、レンダリング配列、スタイル設定方法からログインページのカスタムについて学ぶことができます。

### 8. ビューのスタイリング
Viewsモジュールの説明に注視し、フォーマット、フィールド、フィルター、ページャー、テンプレートWebProfilerでテンプレートがどのようにレンダリングされるか学ぶことができます。

### 9. スタイリングブロック
Githubのサンプルコードから編集ブロックやテーマに適用される新しいブロックの対応、テンプレートに挿入、フィールド値の抽出、モジュールで定義されたブロック、テンプレートのオーバーライドを学ぶことができます。

### 10. スタイルのメンテナンス、分類法、検索結果、および 403/404 ページ
この章ではタイトル通りの内容でスタイル設定などを説明しています。検索についてはSearch API を使うことを勧めています。

### 11. 単一ディレクトリコンポーネント
Single Directory Components（SDC） モジュールについて説明しています。SDCのメリット、コンポーネント作成、オーバーライド、メタデータ、Storybookと統合することのメリット・デメリットの指摘などが学ぶことができます。

### 12. カスタム Twig 関数とフィルターの作成
Twig の新しいカスタム関数とフィルター定義の方法、テーマレイヤーでビジネスロジックの扱いを学ぶことができます。

### 13. テーマを構成可能にする
再利用性の向上にさせるテーマ構成管理、テーマ設定フォーム作成、サブテーマ作成、ライブラリの拡張・オーバーライドが学ぶことができます。

### 14. パフォーマンスとアクセシビリティの向上
Google Lighthouseで数値の改善、レスポンシブ画像などでサイトのパフォーマンス、アクセシビリティに改善方法を学ぶことができます。

### 15. 分離されたフロントエンドの構築
デモサイトをDrupalのAPI（RESTful Web Services、JSON:API）を利用し、Next.jsでノード・メディアの取得・表示するまで説明しています。

# おわりに
久しぶりのDrupalのテーマ書籍でしたが、章によっては内容も充実して、新しい知見も得られました。
Drupalテーマを扱う方には、自身の構築方法がベストプラクティスなのか、またテーマ開発を考察する上で読んでおいていいでしょう。
Githubの使い方　(初期設定からSSH接続)

前提条件
* Mac使用
* GitHubのアカウント作成済み
### 1. Gitのバージョン確認
```sh
git --version
```

### 2. Gitの設定
ユーザーネーム、メールドレスを指定
```sh
# gitにユーザーを設定する
git config --global user.name “githubユーザーネーム”

# gitにメールアドレスを設定する
git config --global user.email Githubに登録したEmailアドレス
# 成功していれば何も表示されない
```
gitの設定を確認する
```sh
git config user.name
git config user.email
git config --list
# 自分のGithubのアカウント情報が表示されていれば問題なくOK。
```
### 2. GitHubにSSHで接続する
GitHubのリポジトリにプッシュするには、SSHで接続する必要がある。公開鍵認証と呼ばれる方式で認証をする。
以下の流れで進める。
1. 公開鍵の作成
1. 公開鍵をGitHubに登録
1. 接続確認

#### 以下のコマンドで公開鍵を作る
```sh
ssh-keygen -t rsa -C mail@sample.jp
```
`mail@sample.jp`の部分はGithubに登録した自分のメールアドレス
```sh
Generating public/private rsa key pair.
Enter file in which to save the key (/home/ec2-user/.ssh/id_rsa): 
```
上記のコマンドで`.sshディレクトリ`に`id_rsa`というファイル名に自動で設定される。指定のディレクトリと指定のファイル名を使いたい場合は指定する。
```sh
Enter passphrase (empty for no passphrase): 
```
公開鍵にパスワードを設定する。画面には表示されないけれど入力はできている
```sh
Enter same passphrase again: 
```
確認のため同じパスワードを2回入力する。
以下のような表示がされたら完了！
```sh
Your identification has been saved in /home/ec2-user/.ssh/id_rsa.
Your public key has been saved in /home/ec2-user/.ssh/id_rsa.pub.
The key fingerprint is:
SHA256:■■■■■■■■■■■■■■■■■ mail@sample.jp
The key's randomart image is:
+---[RSA 2048]----+
|   xxxx          |
|xxxxxxxxxxx      |
| x x x xxx  xxx  |
|        xx  x    |
|     xx x        |
|       x x       |
|        x x      |
|         x       |
|          x      |
+----[SHA256]-----+
```
`id_rsa`と`id_rsa.pub`の2つのファイルが.sshディレクトリに作成されていることをlsコマンドで確認。
```sh
ls ~/.ssh
```
以下のように表示されたらOK
```sh
authorized_keys  id_rsa  id_rsa.pub
```
#### 公開鍵をGithubに登録
`cat ~/.ssh/id_rsa.pub`で`id_rsa.pub`の中身を表示させる。
以下のように表示されるので冒頭から全てコピー。
```sh
ssh-rsa ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
■■■■■■■■■■■■■■■■■■■■■■■■ mail@sample.jp
```
Githubに移動。
アイコンを押下して、Settingsを押下。
![スクリーンショット 2024-01-22 8.35.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3570384/7e8823ac-6995-dae0-4a15-b5633af9b456.png)


`SSH and GPG keys`を押下。任意の名前と、先ほどコピーした情報とを貼り付けて最後に`New SSH key`を押下。
![スクリーンショット 2024-01-22 8.37.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3570384/e7ce9d8f-96ab-a86c-1fea-f678b6379572.png)


#### SSH接続の確認
Terminalで以下のコマンドを入力。
```sh
ssh -T git@github.com
```
初めての接続の際は以下のようなコメントが出るので、`yes`で。
```sh
The authenticity of host 'github.com (13.114.40.48)' can't be established.
RSA key fingerprint is SHA256:nThbg6kXUpJWGl7E1IGOCspRomTxdCARLviKw6E5SY8.
RSA key fingerprint is MD5:16:27:ac:a5:76:28:2d:36:63:1b:56:4d:eb:df:a6:48.
Are you sure you want to continue connecting (yes/no)? 
```
以下のように表示されたら、設定したパスワードを入力
```sh
Warning: Permanently added 'github.com,13.114.40.48' (RSA) to the list of known hosts.
Enter passphrase for key '/home/ec2-user/.ssh/id_rsa': 
```
以下のように表示されたら成功！！
```sh
Hi ユーザー名 You've successfully authenticated, but GitHub does not provide shell access.
```
`but GitHub does not provide shell acc`と出るから不安になるけど大丈夫みたいです。

これでリモートリポジトリにプッシュができるようになりました！！
GitHub Pagesでwebサイトを公開しよう

## はじめに
今回はGithubPagesでのWEBサイト公開方法について紹介します。
リポジトリの作成〜プッシュまでは終わったと想定します。

:::note warn
注意
リモートリポジトリを作成する際は`Public`を選択してください。
Privateリポジトリの公開はできないためです。
:::

## GitHub Pagesでページの公開をする
### ①リポジトリ画面から設定画面へと遷移
リポジトリ画面右上のSettingsをクリックして、設定画面へと遷移します。

![スクリーンショット_2024-01-21_18_56_04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1003708/018ee633-4b85-6825-a539-8dc152d8f53e.png)

### ②設定画面でPagesを選択
設定画面に遷移したら、左側のメニューにある`Pages`を選択します。

![スクリーンショット_2024-01-21_19_11_36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1003708/593b001e-2ab7-279b-ce14-3e7c9af00c3f.png)

### ③公開したいブランチを選択する
公開したいブランチ、今回は`main`を選択してSaveボタンをクリックします。
ブランチ選択の横のフォルダアイコンは公開元フォルダです。`/docs`に公開したいフォルダ・ファイルを格納した場合は、こちらを変更してください。

![スクリーンショット_2024-01-21_19_19_01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1003708/77a25f47-9289-4029-ad73-53b1c2a7d832.png)

### ④サイトの描画を確認する
画面をリロードすることで、赤枠の表示が出ます。
URLをクリック or `Visit Siteボタン`をクリックすると、作成したWEBページに遷移します。
描画にはラグがありますので、描画されないといった場合は少し待ってから再度お試しください。

![スクリーンショット_2024-01-21_19_22_17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1003708/dcb962ca-bda9-106f-9ae3-08f0056b3149.png)

### 注意点
私が詰まった点ですが、`index.html`を`dist/index.html`のようにdist配下に格納しておりトップ画面には違うページが表示されているということがありました。
`index.html`はルート直下、もしくは/docsに格納する必要があるようです。

## さいごに
無事正しく描画されていることが確認できました。

![スクリーンショット 2024-01-21 20.43.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1003708/54b61447-e168-627c-01c0-da0f27522ca7.png)

## 参考文献

 https://prog-8.com/docs/github-pages
マルチモーダルのRAGを試してみました（GPT-4v+Llamaindex）

最近LlamaindexがマルチモーダルのRAG方法を公開しました。（MultiModalVectorStoreIndex)

私も昨日試してみました。
このRAGの中身は、画像データとテキストデータをそれぞれベクトルストアを作成し、マルチモーダルモデルで両方から情報を取って、回答を生成する仕組みです。（イメージとしては以下のような感じです。langchainのMultiVectorRetrieverとほぼ一緒です。）

![001.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3556459/400547fa-5938-621f-70f4-d97bcdcacdb6.jpeg)

今回の試しでは、GPT-4Vと、Qdrant（テキストベクトルストア用）、CLIP（画像ベクトルストア用）を使いました。


## 1.GPT-4Vテスト

まずはGPT-4Vが画像をどの程度理解できるかを試してみました。
テストに使用したのは、トヨタの"アルファード"というモデルの車の写真です。外装、内装、あとスペックの写真をホームページから取って、モデルに入れてみました。

![1-21-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3556459/30cd9fd0-261b-a7bf-5ebe-5fc57bc96c89.png)

それで、モデルに"画像の内容を簡単な日本語で説明してください。"という質問を試しました。
回答としては特に問題ないですね。

![1-21-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3556459/f4e8b9c3-42a5-7ac0-1e84-194bb16066e9.png)

## 2.マルチモーダルベクトルストアの作成

次に、RAGで使用するためのベクトルストアを作成します。
今回試したい質問は"アルファード"に関する質問なので、
画像のデータはwikipediaのAPI経由で"トヨタ・アルファード"の車写真を取ってきました。（ダウンロードする写真枚数が多くて、APIリクエストの制限を超えてしまい、途中で切れましたが、30枚ほどはダウンロードできました。）
テキストの情報はwikipediaの内容＋ホームページの概要pdfです。

## 3.性能検証

色々試してベクトルストアができました。さっそく、"アルファードの内装特徴教えて"という質問を聞いてました。（回答は以下）

![1-21-4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3556459/b61de7bc-7d7b-8e66-5c27-775e38b357a0.png)



回答のテキスト部分はpdfの情報を使って、特に問題なかったですが、画像の部分では、"提供された画像にはアルファードの内装の特徴に関する情報は含まれていません。"となっていました。確かに、返された写真を見ると、内装の写真ではないため、該当する情報がないという回答は間違いないですが、なぜ内装の写真をうまく検索できないのはわからなかったです。画像のRetrieverモデルはそこまで性能低いかなと思いました。
そこで、質問の仕方を何度も変えて試しましたが、内装の写真はずっと出てこなくて、もしかしてwikipediaにはアルファードの内装の写真がないのではないかと疑い、実際にWikipediaで確認したところ、本当に内装の写真は掲載されていませんでした。そもそもベクトルストア内には内装の写真ないので、いくら調べても内装の写真は出てこないですね。

そこで、手動で数枚程度アルファードの内装写真をダウンロードしてベクトルストアに読み込ませました。
再度同じ質問投げてみたら、やっと内装の写真が返してくれました。（右側の画像は内装かどうかちょっと微妙なんですが、）
テキストの部分も、"提供された画像にアルファードの内装の特徴に関する情報は含まれていません"という回答はなく、正常に回答が生成されました。

![1-21-5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3556459/315716b4-fb49-9f1b-80e3-dcaff7a2c190.png)

今度はOSSのマルチモーダルモデル（llavaとか）で試してみたいと思います。



参考:

https://blog.llamaindex.ai/multimodal-rag-pipeline-with-llamaindex-and-neo4j-a2c542eb0206

https://docs.llamaindex.ai/en/stable/examples/multi_modal/gpt4v_multi_modal_retrieval.html
Nuxt3 + Vuetify3 でエラーページ作ってみる

# はじめに
Webアプリを作成して忘れてはいけないものは・・・・
出てはいけないですがエラーのフォローです。
Nuxtのオリジナルもかっこいいですが、やはりカスタマイズしたいところです。

## どんなの作ったの
とりあえず完成形は [こちら](https://web.ynetlabo.net/foo) です。
![スクリーンショット 2024-01-21 20.10.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/273836/794ce09b-0178-077d-a478-4e10bd149270.png)

https://github.com/yuuint/ynetlabo/blob/main/ynetlabo-app/error.vue

## Nuxt2からNuxt3へ
Nuxt2の時はlayout/error.vueを作成することでできてましたが、Nuxt3では/error.vueに移動したみたいです。

[公式 Nuxt2の場合](https://v2.nuxt.com/ja/docs/concepts/views/#エラーページ) ⇨  [公式 Nuxt3の場合](https://nuxt.com/docs/getting-started/error-handling#error-page)

シンプルに昔作ったソースを移植すると・・・
layoutが使用できなくなってる・・・
どうやら、Nuxt3からはerror.vueで
定義済みのlayout使用できないみたいです。

### /error.vueを新規作成
ステータスーコードとメッセージは以下で取得できる模様
```vue:/error.vue
<script lang="ts" setup>
interface Props {
  error: Error;
}
const props = defineProps<Props>();
</script>

<template>
    <div>
        <div>ステータスコード:{{ props.error.statusCode }} </div>
        <div>メッセージ:{{ props.error }} </div>
    </div>
</template>

```

layoutは利用できないっぽいので、移植してきて・・・
（詳細はソース参照ください）

👏動いた！
Githubを2つのアカウントで利用する方法

## 概要
会社と個人など、別々のgitアカウントを1台のPCで利用する方法メモ

gitのアカウントをglobalに適当に設定して利用すると、会社のリモートリポジトリに間違えて個人のgitアカウントでpushしたりして事故ることがあるのでそれを回避したい

今回は、新しいPCに2つのPJを`git clone`することを目的としています

## 結論
gitの設定をglobalにせずに、プロジェクト毎にlocal設定する

## 参考
- [複数のGitアカウントを手動切替不要で運用する
](https://qiita.com/KeyAmam/items/f9291bb125ee94b52b78)
   - 詳しく書いてあるのでちゃんと理解したい人向け
   - おまけで必須ではないが、便利になるスクリプトやオプション設定もあり
- [複数 git アカウントを1台のPCで使い分ける方法](https://qiita.com/naohikowatanabe/items/fb913ea6617848cd9c17)
   - 上記の方は少々上級者向けだが、こちらの方は少し優し目
   - 上記の方と手法が微妙に違うため別の角度からの参考
- [お前らのSSH Keysの作り方は間違っている
](https://qiita.com/suthio/items/2760e4cff0e185fe2db9)
   - sshキーの作り方詳細

## 手順
### ざっくりとした手順
1. [local] .sshディレクトリを作成
2. [local] ssh keyをローカルで生成
3. [local] .ssh/configにHost情報を設定記述
4. [web] ssh keyを登録
5. [local] git clone
6. [local] local config設定

※ [local]と書いてるのは、lcoalで作業を行い、[web]と書いてるのはgithubの公式サイトにログインして作業を行うという意味

### 詳細手順
#### 1. [local] ssh keyをローカルで生成
まずは、.sshファイルをユーザーディレクトリ直下に作成して移動
```shell
cd && mkdir .ssh && cd ~/.ssh
```

#### 2. [local] ssh keyをローカルで生成
雛形は下記で、"メールアドレス"と"sshkeyを識別するID"は任意で入力
```shell
ssh-keygen -t ed25519 -C "{メールアドレス}" -f {sshkeyを識別するID}
```
実際の例
```shell
ssh-keygen -t ed25519 -C "boku-doraemon@gmail.com" -f id_ed25519_github_pj_dora
```

#### 3. [local] .ssh/configにHost情報を設定記述
configファイルを生成して、Host情報を記述
```shell
touch config && vi config
```
```bash
Host {任意のホスト名}
HostName github.com
User git
IdentityFile ~/.ssh/{手順2で作成したsshkeyの名前}
IdentitiesOnly yes
UseKeychain yes
AddKeysToAgent yes
```
実際の例
```bash
Host github_pj_dora
HostName github.com
User git
IdentityFile ~/.ssh/id_ed25519_github_pj_dora
IdentitiesOnly yes
UseKeychain yes
AddKeysToAgent yes
```

上記を記入したら、エスケープ押して`:wq`でvimを閉じる。　viみたいなのがよう分からん人は下記参考
- [Vim / Vi を終了させる方法](https://qiita.com/kon_yu/items/b8864ff566b8b67a9810)
- [【初心者必見】最強エディタVimの使い方/コマンド30種まとめ](https://www.sejuku.net/blog/5570)


#### 4. [web] ssh keyを登録
githubの公式サイトへいってローカルでこしらえたsshkeyを登録
下記でsshkeyをクリップボードへコピー
```shell
pbcopy < ~/.ssh/id_ed25519_github_pj_dora.pub
```

1. githubにログインして、アカウントの[設定ページ](https://github.com/settings/keys)アクセス
1. 左側メニューの"SSH and GPG keys"をクリック
1. 右上の"New SSH key"をクリック
1. keyにさっきコピーしたssh keyを貼り付け
![スクリーンショット 2024-01-21 20.06.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3121605/53545e83-2d3e-f876-2ff5-e1609710dc41.png)
1. "Add SHH key"で完了

※ 名前はいい感じに自動で生成される

#### 5. [local] git clone
![スクリーンショット 2024-01-21 20.12.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3121605/b9c61529-97bf-c8cd-6d07-29507b1bef04.png)

githubプロジェクトのsshのcloneリンクをコピーして、ローカルのプロジェクトを管理したいディレクトリに行ってcloneするが、`git@github.com`を`github_pj_dora`のように`~/.ssh/config`で設定したhost名に変更する(<font color="Red">ココ地味だけど、重要でここを間違えてると一生パーミッションデニードの刑に処される</font>)

```shell
# NG
git clone git@github.com:dora.inc/pj-dora.git

# 正しい例
git clone github_pj_dora:dora.inc/pj-dora.git
```

#### 6. [local] local config設定
最後にcloneしたローカルPJに移動して、local設定を行う。
```shell
cd cloned_project

git config --local user.name "gitのアカウント名"
git config --local user.email "gitに登録しているメールアドレス"
# 参考にしている方がしていたのでとりあえずw
git config --local url."github_pj_dora".insteadOf "git@github.com"
```
Salesforceで効率よくメール送信を行おう～メールテンプレートを作成してメール送信をする方法

こんにちは
本橋孝昭です

今回はSalesforceでメール送信を行うために「クイックテキスト」を使用してメールテンプレートを作成し送信する方法をお伝えします

なお、メール送信について、
メール一括送信方法については過去にまとめましたので下記をご確認ください

https://qiita.com/Takaa/items/56dd2de9776764098628


## そもそもクイックテキストってなんだ？
クイックテキストはこちらのヘルプをご確認ください
要は、メールに送るべき定型文などがある場合、あらかじめ文章を作成しておけばメール送信が容易になります


>クイックテキストは、ユーザーの時間を節約して管理者が会社のメッセージを標準化するのに役立ちます。クイックテキストを使用すると、挨拶、よくある質問への回答、短いメモなど、定義済みのメッセージを挿入できます。クイックテキストはメール、チャット、行動、ToDo、ナレッジ記事などに挿入できます。

https://help.salesforce.com/s/articleView?id=sf.quick_text_setting_up.htm&type=5


なお、後述しますがクイックテキストの設定により、レコードごとにメール文章を変更することが可能です

「例」クイックテキストを
 {!Contact.LastName}  {!Contact.FirstName}  さま
に設定した場合、

田中太郎　データでは
田中　太郎　さま

「佐藤一郎」データでは
佐藤　一郎　さま
とデータごとにメール内容の変更が可能です


では、さっそく設定についてみていきましょう


## クイックテキスト　設定１　「クイックテキストを有効化」をオンにしよう

まずはクイックテキストがオンになっているか確認してください

![クイックテキスト設定.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/ab66827d-25b7-d1fa-6973-eb72ee197012.png)

## クイックテキスト　設定2 オブジェクト「クイックテキスト」を検索しよう

オブジェクト一覧から「クイックテキスト」を選択し「新規クイックテキスト」をクリックしましょう

![新規クイックテキスト.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/df670f08-2e73-9307-3db4-56cdebe651d2.png)

## 新規クイックテキストを作成しよう

あとは定型文を作成します。なお、レコードの項目を定型文に加えることも可能です

![新規クイックテキスト２.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/82806e38-da42-bc97-a4a3-27ac85916233.png)


こうすることにより、
![テンプレート1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/941233c3-dee8-edbc-3103-8c8e99ef121e.png)

レコードのメール画面から上記→部分をクリックすることにより

先ほど作成したクイックテキスト（メールテンプレート）を選択、表示させることが可能です

![テンプレート2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/98b0ea12-35a2-f4e3-2730-0654ccb33744.png)