OmniAICreator/Qiita-1.07M huggingface dataset:
[BigQuery API(V2)] JavaでBigQueryのジョブの実行結果を取得する

BigQuery API V2(Java)を使用して、
BigQueryのジョブの実行結果を取得する方法
についてご紹介します。

:::note info
APIを利用する環境の準備から始める場合や、コードを実行する際は、
[⧉[BigQuery API(V2)] JavaでBigQueryを使う](https://qiita.com/doran/items/8b7ba29672527426e88d)
を参照ください。
:::

|No||目次|
|---|---|---|
|1||[ジョブの実行結果を取得](#1-ジョブの実行結果を取得)|
||1|[スコープ](#11-スコープ)|
||2|[実行](#12-実行)|
||3|[レスポンスの内容](#13-レスポンスの内容)|

## 1. ジョブの実行結果を取得
ジョブの実行結果を取得します。
ジョブが未実行や実行エラーにより実行結果がない場合は例外が発生します。

### 1.1. スコープ
このAPIを実行するには、以下のいずれかのスコープを指定してください。
```
BigqueryScopes.BIGQUERY
BigqueryScopes.CLOUD_PLATFORM
BigqueryScopes.DEVSTORAGE_READ_ONLY
https://www.googleapis.com/auth/cloud-platform.read-only
```
[⧉[BigQuery API(V2)] JavaでBigQueryを使う(3.2. BigQueryインスタンスを取得)](https://qiita.com/doran/items/8b7ba29672527426e88d#32-bigqueryインスタンスを取得)
でスコープを指定してください。

### 1.2. 実行

```java
public static void main(String[] args) throws Exception{
    Bigquery bigquery = getBigquery();
    Bigquery.Jobs jobs = bigquery.jobs();
    
    Bigquery.Jobs.GetQueryResults result = jobs.getQueryResults("プロジェクトID","ジョブID");
    result.setLocation("ロケーションID");
    
    GetQueryResultsResponse res = result.execute();
    System.out.println(res);
}
```
#### 1.2.1. HTTPリクエスト
GET:　https:\//bigquery.googleapis.com/bigquery/v2/projects/{プロジェクトID}/queries/{ジョブID}
が実行されます。

#### 1.2.2. クエリパラメータ
Bigquery.Jobs.GetQueryResultsのsetメソッドにより、クエリパラメータを追加できます。

|メソッド|引数|説明|
|---|---|---|
|setLocation|String|【必須(US、EUマルチリージョンの場合は不要】<br>ロケーションID|
|setStartIndex|BigInteger|開始行のインデックス(0〜)
|setPageToken|String|次ページのトークン|
|setMaxResults|Integer|取得する最大行数|
|setTimeoutMs|Integer|クライアントがクエリの完了を待機する最大時間(ミリ秒)|
|setFormatOptions|[DataFormatOptions](#dataformatoptions)|出力フォーマットの調整|

#### DataFormatOptions
|メソッド|引数|説明|
|---|---|---|
|setUseInt64Timestamp|Boolean|タイムスタンプをusec int64として出力するか|

### 1.3. レスポンスの内容
#### QueryResponse
|メソッド|戻り値|説明|
|---|---|---|
|getKind|String|リソースの種類<br>固定文字列："bigquery#getQueryResultsResponse"|
|getPageToken|String|次ページのトークン|
|getEtag|String|ハッシュ値|
|getSchema|[⧉TableSchema](https://qiita.com/doran/items/57468203da657921fa2d#tableschema)|結果のスキーマ|
|getJobReference|[JobReference](#jobreference)|クエリを実行するために作成されたジョブへの参照|
|getTotalRows|BigInteger|クエリ結果セットの合計行数|
|getRows|List\<[TableRow](#tablerow)\>|クエリの実行結果|
|getTotalBytesProcessed|Long|処理された合計バイト数|
|getJobComplete|Boolean|クエリが完了したか|
|getErrors|List\<[ErrorProto](#errorproto)\>|ジョブの実行中に発生した最初のエラー|
|getCacheHit|Boolean|クエリ結果がクエリ キャッシュからフェッチされたか|
|getNumDmlAffectedRows|Long|DMLステートメントの影響を受ける行の数|

#### JobReference
|メソッド|戻り値|説明|
|---|---|---|
|getProjectId|String|プロジェクトID|
|getJobId|String|ジョブID|
|getLocation|String|ロケーション|

#### TableRow
|メソッド|戻り値|説明|
|---|---|---|
|get("フィールド名")|Object|引数で指定したフィールド名の値|

#### ErrorProto
|メソッド|戻り値|説明|
|---|---|---|
|getReason|String|エラーコード|
|getLocation|String|エラーが発生した場所|
|getDebugInfo|String|デバッグ情報|
|getMessage|String|エラーの説明|

<br>
<br>
おしまい。。
運動会で理解するデータベースのインデックス

## はじめに
データベースのインデックスについて運動会の玉入れで例えてみます。夢中で玉を投げた運動会を思い出しながらインデックスを理解しましょう。下記記事の第二弾です！

https://qiita.com/sauna1137/items/e93a3e96b994b80dbce6

※本記事はインデックスをイメージできることを目的としています。詳細なニュアンスや意味が本来と異なる場合があります

## インデックスとは
そもそも**インデックスとはDBから欲しいデータをより早く取得するため**の技術です。
最低限これだけ覚えておけば大丈夫です！

## 登場人物
カゴ (テーブル,コレクション)
玉 (レコード、ドキュメント)
玉を数える先生 (クエリ)

![スクリーンショット 2024-05-20 13.40.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1201315/7a0a3cc8-a509-eb87-67c1-6f396fc87a6a.png)

カゴ(テーブル、コレクション)は玉(レコード、ドキュメント)を集めておく場所です。
玉を数える先生(クエリ)によって取り出されます。

## 登場人物紹介
**カゴ(テーブル、コレクション)**
カゴの容量(ストレージサイズ)まで玉(レコード、ドキュメント)を入れることができます。あふれると大変です。

**玉(レコード、ドキュメント)**
固有の製造番号が割り振られ、重さや色、製造年月日など様々な情報が詰まっています。レコードのフィールドやドキュメントのパラメーターに該当します。

**先生(クエリ)**
皆が欲しい玉を取り出してくれます。指定玉メーカと一致や製造年月日順に取り出したりすることがあります。複雑な条件だと先生も人間なので時間がかかることもあります。

## 玉入れでインデックスを読み解く
インデックスを玉入れで解釈した場合、玉の色がインデックスに該当します。
無数の白い玉の中から指定したパラメータ(玉メーカーや製造年月日)の通りに取り出すのは大変です。そこで色(インデックス)があると見分けやすく、取り出しやすくなります。

先生も白い玉だけだと玉にあるパラメーターを一個一個読む必要がありますが色で判別できると素早く取れそうです。

## 赤って200色あんねん
同じ色に見えても実は200色あります。同じ色で取り出して製造年月日順に並べるときにグラデーションがあると並び替えやすいですよね。ソートも範囲指定もかんたんになると思います。

![スクリーンショット 2024-05-22 6.48.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1201315/535884d5-cd9d-73de-2a66-34bac5a15090.png)

![スクリーンショット 2024-05-22 6.49.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1201315/84e1003b-7378-1b99-2c62-fda49d4ee279.png)


## 色って何色もあんねん
運動会にはありませんが、カラフル玉(複合インデックス)という概念を紹介します。これまでは赤か白の単色でしたが一つの玉で複数色つけることもできます。カラフル玉によって複数の玉情報が視覚的にわかり複雑な情報を持つ玉でも取り出しやすくなります。

![スクリーンショット 2024-05-22 6.56.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1201315/322be3b0-c309-11bc-df9c-807498c29a71.png)



## 色(インデックス)のデメリット
**玉の挿入・更新・削除の遅延**
色の追加、カラフル玉の色の追加の作業によってCRUDのCUD(挿入、更新、削除)が遅くなります。ただしR（読み取り）の部分が早くなることで、ユーザー体験の向上に繋がるため、メリットの方が大きい場合が多いです。

**既存の莫大な玉に色を付与するのは時間がかかる**
すでにある莫大な玉に色をつけるのは大変そうですよね。

**色をつけると玉が大きくなる**
色をつければつけるほど玉が大きくなる現象が起きます。カゴのサイズに気をつける必要があります。インデックスにもデータがありストレージを使用します。

## まとめ
新しいこと、知らないことを理解する時はイメージできることが大切だと思っています。この記事がそんなイメージの一助になれば幸いです。

この概念は玉入れでは「xxx だよ！」といった提案お待ちしております。

## 最後に
私の働いている会社で経験の有無を問わず採用を行っています。
興味のある方は是非カジュアル面談から応募してみてください！

https://jambo-support.com/recruit_engineer/
【FastAPI×React×Nginx×Docker】フロントエンドコンテナとAPIコンテナでやり取りができないときにしたこと

:::note warn
追記（2024/5/23）: 記事の内容だとAPIコンテナのホスト側のポート番号を指定しなくてもいいようです。つまり開けるポートがフロントエンドのものだけで良くなります。逆に下の追記のやり方だと、APIサーバのポートも開けないと動きません。また時間があるときに記事の内容を変更します。
:::

:::note warn
追記（2024/5/22）: こんな難しいことをせずに`baseUrl = http://localhost:8000`でいけました。htmlファイルから見たAPIサーバの場所なのでホスト側のポート番号を打たないといけないっぽいです。
:::

# 背景
フロントエンドはReactで開発し、本番環境はNginxで配信、バックエンドはFastAPIでWebアプリケーションを開発していました。
これを全てDocker上で動かしています。
コンテナは以下の4つです。
| コンテナ名 | ホスト側ポート番号 | コンテナ側ポート番号 | 処理 |
|:-|:-|:-|:-|
| db | - | 5432 | PostgreSQLを動かしている |
| backend | - | - | バックグラウンドで非同期で処理を走らせている |
| api | 8000 | 8000 | FastAPIを動かしている |
| frontend | 3000 | 3000 | Reactのビルドをした後にNginxでそのビルドファイルを配信している |

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2906464/1284a168-95c6-b92b-049c-22695fbf4e0f.png)

# 実現したかったこと
jsファイルの中で、APIコンテナに対してaxiosを使ってデータを受け取りたかった。
具体的には、jsファイルの中で以下のような処理をしたかった。
```javascript
const baseUrl = '<APIのURL>';
const response = await axios.get(`${baseUrl}`)
```

# 問題解決までにしたこと
Docker側で名前解決してくれる（参考↓）ことを知っていたので、まずは

```javascript
baseUrl = `http://api:8000`
```
としてみたがFastAPI側にデータが届いていない。

https://qiita.com/negineri/items/793f7da3694f819b3b49

urlを間違えたのではないかと考え、フロントエンドコンテナから`ping api`と打つとちゃんと通信ができていた。
※pingがないと言われたときは以下の記事が参考になりました。

https://qiita.com/seigot/items/9e4d7a3e195fc50f56bb

また、フロントエンドコンテナから`curl http://api:8000`と打ってもうまく通信できていた。

そもそもデータが届いていないので違うとは思うが、CORS関係のエラーかもしれないと思い、FastAPI側で以下のように設定したがもちろんうまくいかず。
```python
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware

app = FastAPI()

# CORSの設定
app.add_middleware(
    CORSMiddleware,
    allow_origins=[`*`],  # リクエストを許可するオリジンのリスト
    allow_credentials=True,  # 認証情報の共有を許可
    allow_methods=["*"],    # すべてのHTTPメソッドを許可
    allow_headers=["*"],    # すべてのHTTPヘッダーを許可
)
```

ここで、ChatGPTに聞いて、Nginxのリバースプロキシというものがあり、それを使ってみることにした。

以下にNginxの設定ファイルを記載する。
```nginx
server {
    listen 3000;
    server_name localhost;

    location / {
        root /var/www/;
        index index.html;
    }

    location /api/ {
        proxy_pass http://api:8000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}
```

リバースプロキシについては以下が参考になる。

https://qiita.com/tomokitamaki/items/53361024711ce71c0324

https://cloudsmith.co.jp/blog/virtualhost/docker/2022/12/2241971.html

これにより、例えば`http://localhost:3000/api`に届いた通信を`http://api:8000`に渡してあげることができる。

また、jsファイルの方も

```javascript
baseUrl = `http://localhost:3000/api`
```

と変更した。

これでもう一度コンテナを再起動すると、無事にAPI通信ができるようになった。

# まとめ
フロントエンドコンテナとAPIコンテナでやり取りができないときにしたことをまとめた。
ReactでビルドしたファイルをNginxで配信しており、htmlファイルから見たときに`http://api:8000`がどこにあるかが分からないことが原因だった。
解決策として、Nginxのリバースプロキシの機能を使って`http://localhost:3000/api` -> `http://api:8000`にプロキシし、htmlファイルからAPIコンテナの場所を参照できるようにした。
【Typescript】ステートレスオブジェクトの理解と実装

## はじめに
ステートレスオブジェクトとは、内部に状態（ステート）を持たないオブジェクトのことです。ステートレスオブジェクトは、入力に依存して一貫した出力を提供する純粋な機能を持つため、予測可能で再利用可能です。

## ステートレスオブジェクトとは？

ステートレスオブジェクトは、内部に状態を保持せず、メソッドや関数が呼び出されるたびに同じ入力に対して同じ出力を返すオブジェクトです。これに対して、状態を持つオブジェクトは、内部にデータを保持し、そのデータに基づいて動作が変化します。

## ステートレスオブジェクトの利点

1. **予測可能性**: ステートレスオブジェクトは、入力に依存して一貫した結果を返すため、バグを見つけやすく、テストが簡単です。
2. **スレッドセーフ**: ステートレスオブジェクトは内部状態を持たないため、複数のスレッドから同時にアクセスしても競合が発生しません。
3. **再利用性**: ステートレスオブジェクトは、特定の状態に依存しないため、再利用が容易です。
4. **保守性**: ステートレスオブジェクトは、状態管理のコードが不要なため、保守が容易です。

## ステートレスオブジェクトの実装例

ここでは、TypeScriptでステートレスオブジェクトを実装する方法を示します。

### 例: ステートレスな計算クラス

以下は、数値の計算を行うステートレスな計算クラスの例です。

```typescript
class Calculator {
    // 2つの数値の合計を計算します
    public static add(a: number, b: number): number {
        return a + b;
    }

    // 2つの数値の差を計算します
    public static subtract(a: number, b: number): number {
        return a - b;
    }

    // 2つの数値の積を計算します
    public static multiply(a: number, b: number): number {
        return a * b;
    }

    // 2つの数値の商を計算します
    public static divide(a: number, b: number): number {
        if (b === 0) {
            throw new Error("Division by zero is not allowed.");
        }
        return a / b;
    }
}

// 使用例
console.log(Calculator.add(2, 3));       // 出力: 5
console.log(Calculator.subtract(5, 2));  // 出力: 3
console.log(Calculator.multiply(3, 4));  // 出力: 12
console.log(Calculator.divide(10, 2));   // 出力: 5
```

### 例: ステートレスな文字列操作クラス

次に、文字列操作を行うステートレスなクラスの例です。

```typescript
class StringUtils {
    // 文字列を大文字に変換します
    public static toUpperCase(str: string): string {
        return str.toUpperCase();
    }

    // 文字列を小文字に変換します
    public static toLowerCase(str: string): string {
        return str.toLowerCase();
    }

    // 文字列のスペースを削除します
    public static trim(str: string): string {
        return str.trim();
    }

    // 文字列が空かどうかをチェックします
    public static isEmpty(str: string): boolean {
        return str.length === 0;
    }
}

// 使用例
console.log(StringUtils.toUpperCase("hello")); // 出力: "HELLO"
console.log(StringUtils.toLowerCase("WORLD")); // 出力: "world"
console.log(StringUtils.trim("  hello  "));    // 出力: "hello"
console.log(StringUtils.isEmpty(""));          // 出力: true
```

## まとめ

ステートレスオブジェクトは、内部に状態を持たないため、予測可能で再利用可能なコードを提供します。これにより、バグを減らし、保守性を向上させることができます。TypeScriptでのステートレスオブジェクトの実装は、静的型付けの利点を活かしつつ、クリーンで管理しやすいコードを書くのに役立ちます。
初心者がJLCPCBで初めて基盤を発注してみた！！！

初めまして!!!ぐーちゃんです.
今回初心者ながら、初めてプリント基板の制作に挑戦してみました!
なので「これからプリント基盤づくりに挑戦してみたい！」と考えてる初心者の同士さんの助けになればと思ったので,
今回の基盤制作の話も踏まえて紹介したいと思いま～す!

## はじめに
今回制作に挑戦したのは...
**MD（モータードライバー）！！！**
回路や基盤制作に詳しい大先生たちの力をお借り...というか半分やってもらいながらなんとかCADデータを完成させました.

さて、CADデータも完成させて,あとは基盤を作るだけ♪
...ってよくよく考えたらどうやってあの基盤って作るの？あれ,私知らない.
てなわけでまた大先生に質問したところ...
**「んなもん,JLCPCB一択だろ. そうに決まってる.」**
と言われました.
## JLCPCBって何？
↓↓↓ 神！有能！天才！さいきょー！！！！！！！！！なJLCPCB様
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3598586/aa55130b-1d19-0225-3f2f-c7a30995a38e.png)
JLCPCBは一言でいうと,
**私たちが作りたい！と思った基盤を超格安＆高品質で作ってくれる神基盤発注業者** です!

詳しく言うと
* 基盤自体が安い！
* 注文の手順がめちゃ簡単で,初心者にもわかりやすい！
* 基盤が高品質＆すぐに届いた！
* 担当者様が個別で対応してくれるから,対応も早くて丁寧！
* （私の場合）途中で注文内容が変わっても返金対応してくれた！ 

神だね.言うまでもない.

とまあこんな感じの神業者さんを紹介してもらったおかげで、無事制作することができました!!!
![IMG_3659.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3598586/3c456354-0ecb-d273-cfe9-94b0f967ed8b.jpeg)

## 終わりに
もう一度言います。JLCPCBは神です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3598586/fc443c2e-b208-68c1-138f-7f8864916e9f.png)
しかも初めて利用する方はクーポンがもらえまーす!!!
⇩ここのリンクから是非チェックしてください～
https://jlcpcb.jp

それでは,バイバイーーー！
自動車衝突試験と不可能の証明

# 自動車衝突試験
かなり昔，海外の自動車メーカーが行う自動車衝突試験のCMがテレビで流れていました．これは，正面衝突時の安全性を示すために，時速80キロで自動車を頑丈な壁に衝突させるという内容でした．私はそのCMを数人で見ていたのですが，全員が「この衝突試験は自動車の正面衝突時速40キロ相当だから，あまり意味がない」と言っていました．相対速度を考えてのことだと思います．2つの自動車がそれぞれ時速80キロで正面衝突する場合，その相対速度は時速160キロになります．そのため，時速80キロの正面衝突時の安全性を示すのであれば，静止した壁に160キロで衝突させないとダメだという意見でした．彼らは理系の人たちで，一流大学の理学部物理学科で修士や博士を取得した人たちも含まれていました．

私は「いやいや，時速80キロの正面衝突の安全性試験には，時速80キロの壁への衝突実験で十分でしょ」と主張しましたが，彼らに「お前は情報出身だから，物理がよくわからないのだろう」と言われてしまいました．


# 計算機科学の視点から
私が「時速80キロの壁への衝突実験で十分でしょ」と思ったのは，物理の知識によらず，計算機科学でおこなわれる不可能の証明の観点からです．アルゴリズムや計算量の世界では，不可能の証明に「区別できない」という概念をよく用います．例えば，$n$個のデータを大小比較だけでソーティングする際，少なくとも$\Omega(n\log n)$回の比較が必要だという下界の証明があります．データの並びは$n!$通りありますが，1回の大小比較で得られる情報は1ビットだけです．$k$回の比較では，$k$ビットの情報が得られ，最大で$2^k$通りの状況を区別できます．この情報を使って$n!$通りの並びのうち1つを特定する必要があるため，少なくとも$2^k\geq n!$を満たす必要があります．つまり，$2^k < n!$である限り，区別できない並びが存在していることになります．したがって，$k \geq \log_2 n! = \Omega(n\log n)$の比較回数がソーティングを完了するための下限となります．

# 衝突する自動車の立場から
状況はかなり異なるのですが，この「区別できない」という考え方を利用します．
自分が衝突する自動車を運転していると想像します．正面にカーテンがあり，そのカーテンの向こう側には
 1. 頑丈な壁
 2. 同じスピード（時速80キロ）で走ってくる自動車

のいずれかがあります．運転している自動車はカーテンのところで壁または自動車と衝突し，その場で静止します．このとき、カーテンの向こう側が壁なのか自動車なのか，運転手は区別できません．この区別ができないという事実から，両方の衝突は本質的に同じであるという結論に至ります．
もちろん，理想的な衝突を想定しているため，実際には破壊の状況が一致しないでしょうから，ある程度の区別はつくでしょう．しかし，時速80キロでの壁への衝突が，時速40キロの正面衝突に近いのか、時速80キロの正面衝突に近いのかといえば，後者であると考えるのが妥当でしょう．

# 時速40キロの正面衝突に相当する壁への自動車衝突試験
ツルツルの床に自動車と同じ重さの壁が置かれていて，自動車が時速80キロで衝突した瞬間，壁と自動車がくっついてそのまま床を時速40キロで滑っていく，という状況であれば，時速40キロでの正面衝突に相当すると言えるでしょう．

# ChatGPTに聞いてみた
**ChatGPT:** 自動車が時速80キロで壁に衝突する場合と、時速80キロで互いに正面衝突する2つの自動車の衝突の場合について、破壊の程度はほぼ同じかどうかについて説明します。

まず、物理学の観点から見てみましょう。両方のシナリオでエネルギーを考えることが重要です。

**1. 時速80キロで壁に衝突する場合**
この場合、車両は停止した障害物にぶつかります。衝突エネルギーは車両の運動エネルギーに依存します。運動エネルギー $E$は次の式で表されます：
$$ E=\frac{1}{2} mv^2$$ ここで、$m$ は車両の質量、$v$は速度（80 km/h）です。

**2. 時速80キロの車両同士の正面衝突**
この場合、2つの車両が互いに向かって時速80キロで進んでいます。衝突時の相対速度は時速160キロになりますが、それぞれの車両にとっては相手車両が壁のように感じられます。各車両は自分の運動エネルギーだけを考慮すればよいため、1つの車両にとっては上記の壁に衝突する場合と同じ運動エネルギーになります。

**結論**
衝突のエネルギーの観点からは、どちらのシナリオでも各車両が経験するエネルギーは同じです。そのため、車両の破壊の程度もほぼ同じであると考えられます。

ただし、現実の世界では、車両の設計や材料、衝突の具体的な条件によって微細な違いが生じる可能性がありますが、基本的な物理法則に従えば、破壊の程度は同等であると判断できます。

# おわりに
区別できないという不可能な証明にソーティングの比較交換回数の例はあまり適切でないかもしれません．分散アルゴリズムで，対称性よりリーダー選択ができないという例や，チューリング機械のステップ数の下界の議論の方がより適切かもしれませんが，簡単な説明が思いつきませんでした．
クライアント側での添付ファイル読み込みとアップロード

VercelのNext.js/Reactアプリでファイルアップロードを実装しようとしましたが、アップロードする画像を保存したいわけではない（生成AIに画像ファイルの解釈をしてもらうだけなので処理後は破棄してOK）ので、簡易的な方法を探しました。

結果、クライアント側でBase64に変換してからサーバー側に送信することにしました。
デメリットとしては通信量が多くなります。

```TypeScript
<input type="file" id="attachedFile" accept="image/jpeg, image/png, image/gif, image/webp" 
  onChange={(evt) => {
      // Read the file content and convert to data URI in the client side
      const selectedFile = evt.target.files![0];
      if (!selectedFile) {
        setImageUrl('')
        return
      }
          
      const reader = new FileReader();
      reader.onload = () => {
        const dataImageUrl = reader.result as string
        setImageUrl(dataImageUrl);
      };
      reader.readAsDataURL(selectedFile);
}} />

<input type="text" value={imageUrl}
  onChange={(e)=>{setImageUrl(e.currentTarget.value)}}/>
```

`const [imageUrl, setImageUrl] = useState('')`となっている前提です。もともとinputは存在していて、
外部URLを指定することができていたので、これで良かったのかなと。

ボタンを押すとファイルを指定する場合はこんな感じ。

```HTML
<button className={'mx-1 ' + (fileSelected ? 'text-teal-700 active:text-teal-600' : '')} onClick={() => fileImageRef.current?.click()}>
    <PaperclipIcon className="h-5 w-5" />
    <span className="sr-only">Upload</span>
</button> 
```
【ChatGPT＋DALL-E3】GPTモデル切り替えについて、です


　どうも、カーブミラーです。

　今回は、GPTのモデル切り替えについて、書きました。

:::note info
本記事は、ChatGPT（有料版）
＋DALL-E3で行なっております。
画像はあります。　あしからず。
:::
　YouTuberのKEITOが
　　ChatGPTでのことを
　　　ポストしました。

　ChatGPTのGPT-4oが
　　Excelのファイルを
　　　アップロードすると、
　　　　表が作成されます。

　この表は
　　編集可能だとか。
[KEITOポスト](https://x.com/keitowebai/status/1792390569697910936?t=UFXkZYgwt_587vRek_s_3Q&s=03)
***
　では、本題です。

　モデル切り替えについて、です。

　切り替え方法は、ふたつ。
　❶上部のモデル切り替えをタップ
![Screenshot_20240522-104107.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457238/9c29f38e-d742-1fd2-0e04-8909af810e66.png)
　❷出力後の切り替えアイコンをタップ
![Screenshot_20240522-104221~2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457238/d2ca6c49-c374-79f9-3810-46d4216dee2a.png)

　問題は、
　　この切り替えの使い方です。

　私も使い方がわからず、
　　X-Twitter上でも
　　　誰もポストしていません。

　そこでやってみた結果が
　　今回の記事になります。
***
　まずは、❶の方です。

　こちらは単純ですね。

　セッションを
　　このモデルで
　　　継続するよ、というものです。

　セッションの対話をはじめる前に
　　変更しておけば、
　　　そのセッションは
　　　　指定されたモデルで
　　　　　行ないます。

　また、
　　セッション途中で
　　　切り替えることも
　　　　可能です。

　　ただし、
　　　セッションが
　　　　GPT-4/GPT-4oだった場合、
　　　　　GPT3.5への切り替えは
　　　　　　できません。
***
　次に、❷ですね。

　こちらは
　　ChatGPTからの返答に
　　　付随するアイコンで行なえます。

　役割はなんでしょうか？

　実際に選んでみると、
　　そのモデルでの
　　　再生成が行なわれます。

　セッションがGPT3.5だった場合、
　　GPT3.5も選択可能です。

　ただし、
　　これは、その一度だけで
　　　次の回答は、
　　　　❶で選択したモデルに
　　　　　戻ります。
***
　このふたつの使い分けですが、
　　❶をセッション全体
　　❷を一時的な切り替え
　　と、意識して使うことになります。

　画像生成での利用は
　　GPT-4/GPT-4oだけになります。

　しかし、
　　今のところ、
　　　切り替える意味を
　　　　見出だせていません。

　画像解析能力は、
　　どちらのモデルも
　　　違いがあるようには
　　　　思えません。

　画像生成も
　　違いを感じられません。

　また、
　　ラストナレッジカットオフは
　　　GPT-4は、2023年12月まで
　　　GPT-4oは、2023年10月まで
　　　　とGPT-4の方が最新情報を
　　　　　持っています。

　私が
　　利点を感じて
　　　使っている場面は、
　　　　生成された画像の
　　　　　Promptの書き出しと
　　　　　　その和訳ですね。

　やり方は、
　　その指示を送信する前に
　　　セッションのモデルを
　　　　GPT-4からGPT-4oに
　　　　　切り替えて、送信します。

　これにより、
　　高速に出力されます。

　生成画像のPromptは固定ですし、
　　和訳する分には
　　　どちらのモデルも
　　　　同じ出力をします。
　　　　　違いは速度だけ。

　もちろん、
　　モデルを戻す手間は必要ですが、
　　　私はGPT-4を使用します。

　　画像生成するだけなら
　　　GPT-4oを使う意味は
　　　　ありませんからね。

　みなさんの
　　作品制作の糧に
　　　なれば、幸いです。

　今回は、ここまで。
global object 【JavaScript】

# はじめに

global object とは、簡単に言えば「コードのどこからでもアクセスできるオブジェクト」です。
ホスト環境（Node.jsや各種ブラウザなど）によって実装が変わります。

※コメントいただきました。
`globalThis`を使用すればホスト環境に関係なくglobal objectにアクセスできるようです。
ただし、挙動が変化することはないようです。Node.jsの`globalThis`は`global`と同じ挙動をし、ブラウザの`window`もしくは`globalThis`とは違う挙動をします。

# ブラウザの場合：`window`

Chrome, Firefox, Safari, Edgeの各ブラウザはglobal objectとして`window`を使用します。
<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="dyEMWmM" data-pen-title="Qiita_global_window" data-user="Kohki-Takatama" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/Kohki-Takatama/pen/dyEMWmM">
  Qiita_global_window</a> by Kohki_Takatama (<a href="https://codepen.io/Kohki-Takatama">@Kohki-Takatama</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

※このボタンはブラウザのconsoleに情報を出力します。F12を押して、開発者ツールからconsoleを確認してください。

このデモは、以下の事項を示しています。
- `const`を使用した変数宣言は、`window.name`ではアクセスできない
- `var`を使用した変数宣言は、`window.name`でアクセスできる
- `console.log`と`window.console.log`は完全に等しい
- 関数宣言`function`を使用した場合、`window.name()`でアクセスできる
- 関数式の場合は、変数と同じく`const`ではアクセスできず、`var`ならアクセスできる

なお、`const`で宣言した変数・関数も`window.property = 変数 | 関数`と明示すればアクセス可能（推奨はされない）
# node.jsの場合：`global`

Node.js の場合は、各ファイルが独自のmoduleスコープを持っているようです。
global objectはファイルを超えてのアクセスが可能になるようです。

```main.js
global.sayHello = function(name) {
    console.log(`Hello, ${name}!`);
};

const moduleB = require('./moduleB');
moduleB.greetUser('Alice');
```

```moduleB.js
module.exports.greetUser = function(name) {
    // グローバル関数を呼び出す
    sayHello(name);
};
```

ブラウザの`window`と比較していきます。

## 変数・関数の挙動
```js
var hoge = "hoge"
console.log(global.hoge) //undefined
const fuga = "fuga"
console.log(global.fuga) //undefined
```

ブラウザの`window`と違い、`var`での宣言であっても`global.name`でのアクセスができません。

`global.property = variable`と明示することでアクセス可能なのは、`window`と同様です。
```js
// 先程の続き
global.hoge = hoge
global.fuga = fuga
console.log(global.hoge) // "hoge"
console.log(global.fuga) // "fuga"
```

関数も同様です。
## `console.log`と`global.console.log`

ブラウザの`window`と同様に、`console.log`と`global.console.log` は等しいです。

```js
console.log("normal console") // "normal console"
global.console.log("global console") // "global console"
console.log(console.log === global.console.log) // true
```

# おわりに

以上、global objectについてでした。

「ホスト環境によって違いがある」具体例として扱いました。
実際はより多くの差異・特徴があると思います。
43日目 SAAに挑んだ社畜S


## :checkered_flag:はじめに
どうも、社畜Sです。  
先週までの記事の通り、私たち社畜は
**「AWS Certified Solutions Architect - Associate（通称SAA）」**
に合格すべく学習に励んでいました。    

そしてついに、先週の土日に社畜3人ともSAAを受験してきました！
今回はそんな社畜Sの試験結果について話していこうと思います。  
気になるその結果は………！？
## :checkered_flag:結果発表<br> 
 **社畜S、無事合格できましたー！！！**
 ![pose_goukaku4_businessman.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3766505/e084a126-c493-b4bf-5410-ef5b94438908.png)
正直、わからない問題が多すぎて完全に落ちたと思っていましたが、残り1～2問間違えていたら不合格というラインでぎりぎり踏みとどまっていました！  
ぎりぎりですが合格は合格！  
今回学んだことを活かして他のAWS資格にも挑戦していこうと思います。  

不合格だった場合はここでこの記事は終わっていましたが、無事に合格しましたので、自分のような「AWSぜんぜんわからんけどSAA取らないといけない人」に向けて、私がどのように学習したかについて書いていこうと思います！
## :checkered_flag:こういう勉強してました
まずどういう勉強をしたかの前に、学習開始段階の社畜Sのスペックをどうぞ。  
> 所持資格➡基本情報取得済み、応用情報３連敗中
> AWSについての知識➡完全未経験。基本情報を取ったもののほぼ全部の単語が初見。  

はい。もう見るからに初心者ですね。  
あまりにも知識がなさ過ぎたので、まずは購入したテキストを流し読みしてざっくりと知識をつけることから始めました。  
テキストを軽く読んだ（理解したとは言ってない）あとはわからない単語をテキストで補完しつつ、全問暗記するくらいの気概でひたすら問題を解き続けました。　
今後のことを考えるとあまりよくないんですが、私が短期間で合格するにはこれしかありませんでした。  

  
学習サイトは
**[CloudTech](https://kws-cloud-tech.com/)**
を利用しました。  

問題数は230問（執筆時点）と少なめでしたが、その分問題の解説に図や動画などを多く使っていて、完全初心者の私でもわかりやすく学習をすることができました。  
最終的には230問全部暗記して試験に臨み、**合格点から3点差**で合格！  
CloudTech抜きでは合格は正直無理だったと思います。それくらいわかりやすかったです。  
### 皆さんもCloudTechを使いましょう！！！！！  
私は次回以降もお世話になろうと思います。
ちなみに最終的な学習期間は1か月と少しくらいでした。
## :checkered_flag:まとめ
ということで、今週は社畜Sの合格発表と、超初心者である社畜Sがどう学習したのかについてでした。  
最後あたりはCloudTechの回し者かと言わんばかりにCloudTechを激推ししていましたが、それくらいよかったんだろうなぁということで見逃してください。  
今回学習したことを活かして、次回以降のAWS認定の勉強も頑張っていこうと思います。  
次は目指せ**Developer - Associate**合格！！！
3連敗中の応用情報の勉強も並行してがんばります
macのシステムデータ容量がとんでもないことになっていた

## 事象
macのシステムデータが110GBを超えており、ストレージを逼迫していた際の対応を備忘として。
原因はXCodeのiOSシミュレータの定義ファイル?キャッシュファイル?的なもの。

## 対応

`Library/Developer/Coresimulator/Devices`

このフォルダが100GB以上を占めていたので、配下の不要なファイルを一括削除。フォルダ配下の構成は下記のような形式。

ハッシュ値で命名されたフォルダ
    └data
    └device.plist

おそらくiOSシミュレータの実行単位で保存されたデバイスのキャッシュ情報。
毎回一からビルドしなくていいように再実行の際はここを見て即立ち上げを行ったりしているのだろう。
AM変調をPythonでやってみた

こんにちは、無名です。
今回はAM変調をするコードをPythonで作っていこうと思います。
AM変調はラジオ放送（AMラジオ）や飛行機と地上との通信に使われています。
搬送波の振幅が入力信号によって変化します。

## AM変調の公式
AM変調の公式は搬送波をcos(2πfct)、入力信号をm(t)とした時、変調された信号s(t)は
$$s(t)=(Ac+m(t))⋅cos(2πfct) $$
になります。
これをPythonで書いていきます。

## コード
```
import numpy as np 
import matplotlib.pyplot as plt 
import math

#パラメーター設定
pi = math.pi
f_s = 44100 #サンプリングレート
t_fin = 1 #終了時間(秒)
dt = 1/ f_s #サンプリング周期
N = int(f_s * t_fin) #サンプル数
t = np.arange(0, t_fin, dt)
fre1 = 100 #搬送波の周波数
fre2 = 5 #入力信号の周波数
A_s = 2 #搬送波の振幅
A_m = 1 #入力信号の振幅
```
搬送波の周波数を100Hz 、入力信号の周波数を5Hzとして今回は変調します。

### 変調
搬送波と入力信号を生成し、変調します。
```
#搬送波生成
carrier = A_s * np.cos(2 * pi * fre1 * t) 

#入力波生成
modulator = A_m * np.sin(2 * pi * fre2 * t)

#AM変調
am_wave = (A_s + A_m * modulator) * carrier
```
### グラフの描画
生成したグラフを描画します。

#### 搬送波
![carrier.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3778844/2dfbd978-873d-60e7-38a1-5a9dd441da7a.png)

#### 入力信号
![modulator.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3778844/05861b75-9793-cbc5-1ae8-68bb615b3ed2.png)

#### AM変調波
![Ammodulation.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3778844/d2d4a92d-9b26-cfc3-77e8-18e4ac5842f4.png)

## まとめ
今回はAM変調をやってみました。
変調波のグラフですが、本来なら振幅は搬送波と入力信号の振幅の±で表されますが、なぜか値がオーバーしています。原因はわかりません。
気が向いたらPM変調やFM変調、デジタル変調もやろうかなと思っています。
sudoersファイルの編集時にnanoが立ち上がってブチ切れる前に！

Ubuntuで`sudoers`のファイルを編集時になにも設定してない場合はデフォルトの`nano`が立ち上がって操作がわからず、ブチ切れることがあるんだけど、、そんなことにならんように以下を備忘録。
もちろん個人の環境変数にに`EDITOR`を登録しておけばいいだけの話だけど、よく忘れるので。


* vim をエディタに使う場合

```bash
$ EDITOR=vim sudo -E visudo
```

* emacsをエディタに使う場合

```bash
$ EDITOR=emacs sudo -E visudo
```
QA-LoRA: QLoRAよりも高性能？高精度の量子化 LoRA

※ このページは「QA-LORA: QUANTIZATION-AWARE LOW-RANK ADAPTATION OF LARGE LANGUAGE MODELS」の要約になります。

## このページでわかること
- QA-LoRA（量子化対応低ランク適応）により、LLMの量子化と適応の自由度の不均衡をグループ単位の操作で解決し、微調整中に重みを量子化してメモリと時間を節約しつつ、精度も損わない
- 実験結果から、QA-LoRAは従来のQLoRAと同等以上の性能を示し、特に低ビット幅シナリオでの精度向上が確認

## 対象読者
- 自然言語処理（NLP）や機械学習の分野でLLMの効率的な適応と展開方法に関心を持つ人
- 特にリソース制約のある環境（例：エッジデバイス）でLLMを実装しようとしている人

## 従来手法の問題点
1. **計算負荷の問題**：
   - LLMは多くの言語理解タスクで強力な能力を持っていますが、その巨大な計算負荷とメモリ使用量が、特にエッジデバイスへの展開を妨げている

2. **パラメータ効率の高い微調整（PEFT）の限界**：
   - PEFT（パラメータ効率の高い微調整）アルゴリズムは、少数の学習可能なパラメータを追加してほとんどの事前学習済みパラメータを保持することでメモリ使用量を削減するが、大規模なベースモデルに対しては依然としてメモリ使用量が大きいという問題がある

3. **パラメータ量子化の限界**：
   - 量子化はモデルの計算負荷を軽減する手段だが、特に量子化ビット幅が小さい場合、精度低下が問題となる

4. **PEFTと量子化の統合の難しさ**：
   - PEFTと量子化を統合することが重要ですが、単純な統合では精度の低下が見られる。また、従来の手法では、微調整後に量子化特性を保持することが難しいという問題がある

## QA-LoRA
### QA-LoRA とは？

QA-LoRA（Quantization-Aware Low-Rank Adaptation）は、低ランク適応（LoRA）と量子化の自由度の不均衡を解決するために提案されたアルゴリズムです。従来のLoRAは、微調整時にモデルの重みを補完するために低ランク行列を用いますが、大規模言語モデルの微調整には依然として大量のメモリが必要です。QA-LoRAは、グループ単位の操作を導入することで、量子化と適応の自由度をバランスさせ、計算効率を向上させることを目指しています。

### QA-LoRA のメリット

1. **計算効率の向上**：
   - 微調整中にモデルの重みを低ビット整数（例：INT4）に量子化することで、メモリ使用量と計算時間を削減する
   - 従来のLoRAやQLoRAに比べて、微調整および推論段階での計算負荷が大幅に減少する

2. **精度の維持**：
   - 量子化後の精度低下を最小限に抑え、特に低ビット幅の量子化（INT3やINT2）でも高い精度を維持する
   - 微調整後に量子化モデルと補助重みを統合する際の精度損失を防ぐ

3. **実装の簡便性**：
   - 数行のコードで実装できるシンプルなアプローチで、幅広いシナリオに適用可能

### QA-LoRA の手順

1. **グループ単位の量子化**：
   - 重み行列をグループに分割し、各グループごとにスケーリングとゼロパラメータを計算する
   - これにより、グループごとに量子化が行われ、量子化誤差を低減する

2. **低ランク適応の適用**：
   - 入力ベクトルをグループごとに集計し、低ランク行列（AとB）を使用して補助的な適応パラメータを導入する
   - これにより、量子化された重み行列を補完し、精度を維持する

3. **微調整と統合**：
   - 微調整中にモデルの重みを量子化し、低ビット整数に変換する
   - 微調整後、量子化された重みと補助重みを統合し、精度を損なうことなく最終モデルを構築する

### QA-LoRA の性能

1. **実験結果**：
   - LLaMAおよびLLaMA2モデルファミリーにQA-LoRAを適用し、MMLUやコモンセンスQAベンチマークで評価を実施
   - 低ビット幅のシナリオ（例：INT3やINT2）でも、高い精度を維持し、従来のQLoRAよりも優れた性能を示した

2. **効率の向上**：
   - 微調整と推論段階の計算効率が大幅に向上し、特にQLoRAと比較して推論速度が50%以上速くなった
   - 微調整に必要な時間と学習可能なパラメータの数が大幅に削減された（例：LLaMA-7Bモデルでは学習時間が40時間から21.5時間に減少）

## まとめ
以上がQA-LoRAの要約でした。QLoRA と異なり、グループごとのスケーリングと量子化で性能を低下を抑えるというアプローチのようですね。

QLoRAよりも速くて性能もよいということなので（論文での発表なので、実際がどうなのかは気になりますが）、QLoRAよりも優先的に使ってみるとよさそうですね。

```plantuml
@startuml
<style>
root {
  Padding 0
  Margin 0
}
footer {
  FontColor black
  FontSize 17
}
</style>
footer  QLoRAとQA-LoRAの比較\n(出典：QA-LORA: QUANTIZATION-AWARE LOW-RANK ADAPTATION OF LARGE LANGUAGE MODELS)
title <img:https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/758571/0e90981a-9ca5-50f3-b9a4-cb00c288ab9d.png>
@enduml
```

おわり。
【Bootstrap5】左右を指定 → [start, end]

# Bootstrap5での左右指定には`start`と`end`を

[Bootstrap5](https://getbootstrap.jp/docs/5.3/getting-started/introduction/)から左右を指定する時に`left`や`right`を使わずに、`start`や`end`と使用するようになってるみたいです。

| Bootstrap v4 | Bootstrap v5以降 |
|:-:|:-:|
| left | start |
|  right| end |

実際には、省略して記載することになるのでms-4やpe-4のように記載します。
```html
<div class="ms-4 pe-4">
  左にmarginを、右にpaddingを指定
</div>
```

# なぜ仕様変更したのか
以前のバージョンでは、アラビア語などのRTL言語環境（右から左に記述される言語）と英語などのLTR言語環境（左から右に記述されれる言語）のどちらにも対応するスタイルを効率よく指定をすることができなかったためです。
RTL言語（アラビア語など）では右揃えにするとき`ml-auto`を使用しますが、その環境でLTR言語（日本語など）を記述すると右揃えにされた変な文章になってしまうので、LTR言語（日本語など）用に`mr-auto`を別で指定しないといけなくなります。
このスタイルの二重指定が面倒なので`start`と`end`を用いることでどちらの言語圏にも対応することができるようになったのです。

---

24卒未経験エンジニアによる備忘録です。
研修中に学んだことを少しずつ投稿しています。
ご指摘などありましたらお気軽にコメントください。
CSV をスクリプトで Excelファイル(*.xlsx)  に変換

次のページを参考にしました。
[UbuntuでGnumericを用いてCSVをXLSXに変換する方法](https://www.nemotos.net/?p=3596)

## ソフトのインストール

```bash
sudo apt install gnumeric nkf
```

## 変換

入力ファイル

```text:cities.csv
t1271,千葉,59178,2003-9-21
t1272,勝浦,47215,2003-10-15
t1273,市原,83654,2003-6-14
t1274,流山,74251,2003-9-9
t1275,八千代,42516,2003-8-4
t1276,我孫子,35987,2003-1-21
t1277,鴨川,81256,2003-7-23
t1278,銚子,29374,2003-10-26
t1279,市川,87613,2003-2-17
```

実行コマンド

```bash
ssconvert cities.csv cities.xlsx
```

出力ファイル
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/f01e9cf4-4881-bbbb-d17c-0f6ce2f86017.png)
WSL2 の自動終了についてのまとめ（転載・日本語訳）

## はじめに
WSL2 でシェルを抜けると数秒後に Ubuntu がシャットダウンしてしまい外から ssh できなくなってしまう問題を解消したく色々と調べていたところ、とても分かりやすい解説が GitHub に載っていたので自分のメモがてら抜粋の日本語意訳をここに載せておきます。

## 出典
https://github.com/microsoft/WSL/discussions/8659

## 抜粋・日本語意訳

WSL2 の [詳細設定のページ](https://learn.microsoft.com/en-us/windows/wsl/wsl-config#configuration-setting-for-wslconfig) に以下の記述があります。この説明は正しいのですが、紛らわしいです。
| key | value | default | notes |
|:-:|:-:|:-:|:-:|
| vmIdleTimeout | number* | 60000 | The number of milliseconds that a VM[^1] is idle, before it is shut down. Only available for Windows 11.|

[^1]:厳密には "a VM" は "the VM" であるべきでしょう。なぜなら WSL2 の VM は一つしか実行されないからです。

紛らわしい原因は、ここでいう「VM」が、WSL2 を動かしている VM それ自体を指しているという事実にあります。すなわち、この「VM」は WSL2 の distro（「コンテナ」「インスタンス」も同意）を指しているわけではありません。

本件に関して、２つのタイマーが存在します。

１つ目のタイマーは、distro のインスタンスがアイドルになってからどれだけの時間で終了するか、というものです。「アイドルになる」とは、たとえば `wsl --terminate <distro>` で `init` 以外に実行中のプロセスがなくなったと考えていただければよいでしょう。
このタイマーは設定不可能であり、私の知る限り 15 秒にハードコード[^2]されています。

[^2]: これを設定可能にしてほしいという issue が [Add the ability to change the timeout period of a WSL instance #6782 ](https://github.com/microsoft/WSL/issues/6782) で起票されています。

２つ目のタイマーは、WSL2 の VM に固有のものです。
WSL2 VM は 1 つの Windows につきただ一つしか実行されない共有 VM で、インスタンスが終了した後もこの VM は実行されつづけ、メモリを消費します。`wsl --shutdown` は、この VM を終了させるコマンドです。

:::note info
タスクマネージャーで以下のプロセスを見てみると、VM の起動と終了の様子が分かります。
- Vmmem: vmmem.exe
- 仮想マシンワーカープロセス： vmwp.exe

これらは最初に WSL2 インスタンスを実行すると現れます（インスタンス起動の前にまず VM が起動するので）。そして（`vmIdleTimeout` または `wsl --shutdown` によって）VM がシャットダウンされると消えます。

また、VM の起動と終了はイベントビューアーの Applications and Services Logs -> Microsoft -> Windows -> Hyper-V-Worker -> Admin でも確認ことができます。
:::
`vmIdleTimeout` はこの２つ目のタイマーの秒数です。すなわち、すべての WSL2 インスタンスが終了してから VM がシャットダウンするまでの時間を指定するものです。


まとめると、あなたが最後の WSL インスタンスから exit したとき（他にバックグラウンドでプロセスが実行されていないとして）に起きることは以下のとおりです。

1. 15秒のタイマーが始まり、その後にインスタンスが終了する
2. 最後のインスタンスが終了すると「アイドル状態」のタイマーが始まる。そして `vmIdleTimeout`（デフォルトは 60） 秒後に WSL2 VM がシャットダウンする
Qiita APIで特定ユーザーのQiitaの記事を検索する

以前、
[[Qiita記事を量産している人必見！]自分の記事を検索する](https://qiita.com/ELIXIR/items/ff7a9ce49476c6161ed0)
という記事で特定ユーザーの記事を検索するツールを公開しました。

https://elix.jp/app/tools/qiita_index.html

投稿した記事も200を超え、投稿したことすら忘れているような記事も見つけられるので個人的に重宝していますが、それ以外にも、自分が興味を持った記事を投稿したユーザーがどんなジャンルの記事が多いのかを調べたりするのにも使用しています。
そんなとき、上には上がいるもので、200どころか1000を超える記事を投稿していらっしゃる方もおります。
記事が多い場合、現状は記事を集めている間はフリーズしたような感じに見えてしまうので、
```処理中...```の表示を出すように改良しました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59911/b83a69af-d113-3464-f140-37b0fce420d9.png)

以上、使っていただける方がおりましたら幸いです。
SBOMツールについて

# はじめに
最近、SBOMツールについて調べる機会があったため、調べたことをまとめてみました。
# SBOMとは
ソフトウェアを構成する

- コンポーネント（ソフトウェアを構成する部品）
- ライセンス情報
- コンポーネント同士の相互関係

などの情報をリストにまとめたもの。
脆弱性やOSSのライセンス、ソフトウェアサプライチェーンのリスク管理等で利用される。

SBOMのイメージ
![SBOM.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3760632/c0b2c60e-134c-8f62-b590-7df4831a3d02.png)

# SBOMを構成するための最低限の要素
| カテゴリー　　　　　　　　| 概要 | 具体的な定義 |
| --------- | ---- | ----------- |
| データ<br>フィールド | 各コンポーネントの基本情報を明確化すること | サプライヤー名、コンポーネントの名前とバージョンなど、<br>各コンポーネントに関する基本情報をSBOMに含める |
| 自動化<br>サポート | SBOMの自動生成や可読性などの自動化をサポートすること | SBOMデータを機械判読および<br>相互運用が可能なフォーマットを<br>使用して作成する |
| プラクティスとプロセス | SBOMの要求、生成、利用に関する運用方法を定義すること | SBOMを利活用する組織は、<br>作成頻度、共有、アクセス管理などの項目に関して運用方法を定義する |

# フォーマット
内容や書き方、粒度などを統一するため、書き方のルールを定めたもの

| フォーマット名 | 特徴 |
|---------------|------|
| SPDX | ・幅広いソフトウェア部品タイプをサポートしている。<br>・ライセンスを個別に特定する識別子のリストが用意されている。 |
| CycloneDX | ・セキュリティ管理に重点を置いたフォーマット。<br>・既知の脆弱性だけでなく、その脆弱性の悪用可能性も記述できる。 |
| SWIDタグ | ・ソフトウェアのライフサイクルに沿ってSBOMを管理できる。<br>・ソフトウェアの識別だけでなく、コンポーネントのライセンスや<br>アップデートの情報、脆弱性・脅威に関する情報を含むことが可能。 |

# SBOMツールの基本機能
### 1.解析機能
- ソースコードなどを解析し、それに含まれるコンポーネントを特定する機能
- SBOMの基礎となる「コンポーネントの一覧」を作成するステップ

### 2.分析機能
- コンポーネントの一覧に基づき各コンポーネントのライセンスや脆弱性の有無などの<br>リスクを分析、評価する機能

### 3.レポート機能
- 解析および分析の結果を出力する機能
- SPDXやCycloneDXなどのフォーマット形式でSBOMを出力できる

# 導入のメリット
- ### 脆弱性管理のメリット
  - 脆弱性残留リスクの低減
  - 脆弱性対応時間の短縮
  - 脆弱性管理にかかるコストの低減

  ソフトウェアを利用する側からすれば「ソフトウェアに含まれるコンポーネントの脆弱性の可否を判断すること」は通常不可能なため、SBOMツールを使用しコンポーネントが可視化すれば脆弱性を発見しやすくなる。
　
- ### ライセンス管理のメリット
  - ライセンス違反リスクの低減
  - ライセンス管理にかかるコストの低減

  ソフトウェアに含まれるコンポーネントのライセンス情報が可視化され、自動管理される
　
- ### 開発の生産性向上のメリット
  - 開発遅延の阻止
  - 開発にかかるコストの低減
  - 開発期間の短縮

  コンポーネントに含まれる既知の脆弱性やライセンスの問題を事前に把握できる。
  ソフトウェアに生じた問題を早期に特定できる。

# おわりに
今回、SBOMツールについて紹介させていただきました。
実物を見たことがないためWebにある情報だけでなんとか記事を完成させました。
まだ理解できない部分があるため、実際に触れる機会があれば調べたことを生かしていきたいと思います。
最後まで読んでいただきありがとうございました。

# 参考にしたサイト

https://www.nri-secure.co.jp/glossary/sbom

https://www.lanscope.jp/blogs/cyber_attack_pfs_blog/20231102_16038/

https://www.freee.co.jp/kb/kb-trend/sbom-software-bill-of-materials/

https://mscompass.ms-ins.com/business-news/sbom-guidelines/
MetalLBとRTX1300によるBGPmode接続編

### 前置き
一応動いてるけど、ほんとにいいのこれで？というのがとても不安
というか経路情報をルータに送り込めてなくね…ということでip route書いてます…
けどstatic route書くとちゃんとルータ配下のPCからアクセスできるんよね…
なので一応OKかなと…

### FRRモードのMetalLB
```
kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.14.5/config/manifests/metallb-frr.yaml
```

### RTX1300側のconfig
```
ip route 192.168.101.0/24 gateway 192.168.100.150
bgp use on
bgp autonomous-system 64512
bgp neighbor 2 64513 192.168.100.150 ignore-capability=on
bgp router id 192.168.100.1
```

### MetalLB側のconfig
```
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
  name: default
  namespace: metallb-system
spec:
  addresses:
  - 192.168.101.0/24
  avoidBuggyIPs: true

---
apiVersion: metallb.io/v1beta1
kind: BGPAdvertisement
metadata:
  name: default
  namespace: metallb-system
spec:
  ipAddressPools:
  - default
  aggregationLength: 24

#---
#apiVersion: metallb.io/v1beta1
#kind: L2Advertisement
#metadata:
#  name: default
#  namespace: metallb-system
#spec:
#  ipAddressPools:
#  - default

---
apiVersion: metallb.io/v1beta1
kind: BFDProfile
metadata:
  name: default
  namespace: metallb-system
spec:
  receiveInterval: 380
  transmitInterval: 270

---
apiVersion: metallb.io/v1beta2
kind: BGPPeer
metadata:
  name: default
  namespace: metallb-system
spec:
  myASN: 64513
  peerASN: 64512
  peerAddress: 192.168.100.1
  peerPort: 179
  sourceAddress: 192.168.100.150
  routerID: 192.168.100.150
  bfdProfile: default
```

### 動作状況
```
# show status bgp neighbor
BGP neighbor is 192.168.100.150, remote AS 64513, local AS 64512, external link
  BGP version 4, remote router ID 192.168.100.150
  BGP state = Established, up for 00:00:50
  Last read 00:00:20, hold time is 90, keepalive interval is 30 seconds
  Received 2 messages, 0 notifications, 0 in queue
  Sent 5 messages, 0 notifications, 0 in queue
  Connection established 1; dropped 0
  Last reset never
Local host: 192.168.100.1, Local port: 179
Foreign host: 192.168.100.150, Foreign port: 39433
```
Discord.js v14 botの作り方【基礎・メッセージ編】 (2024/5/22現在)

# Discord.js とは
Discord.js (以下d.js) とは、discordのbotを開発するときに使用するパッケージの1つです。
同様に、Discord.pyというものがあります。これはpythonで開発する場合のパッケージになります。
詳しくは[こちら](https://qiita.com/minoru_kinugasa/items/e1bdee4ca016b2a38e2c)をごらんください！

# 今回の目標
メッセージの仕組みと、複数の送信方法を理解する。
いろんな種類があるので、できるだけわかりやすく簡単に説明します！

# メッセージについて
送信方法は大きく分けて3つあります。
1. チャンネルを探して、送信する
1. メッセージに対して、返信する
1. ユーザーを探して、ダイレクトメッセージ (DM) を送信する

それぞれ方法を簡単に説明します！

## チャンネルを探して、送信する
### チャンネルを探す とは
まず`探す`ってどういうことでしょうか？
Botは、複数のサーバーに導入されます。
また、チャンネルにはそれぞれ唯一無二のidが紐づけられています。

大量のサーバーの、大量のチャンネルの中から1つのチャンネルを探し出さなくては、どこに送信したらいいかわからないのです。
そのため、探してから送信しなければいけません。

### idの取得方法
チャンネルid以外にも、discordのありとあらゆるものにidがあります。
- ユーザーid
- サーバーid
- チャンネルid (カテゴリーid)
- ロールid
- メッセージid
- スレッドid
この様々なidを取得する方法は、以下のとおりです。

|手順|説明|備考|
|---|---|---|
|1|discordのユーザー設定に移動します。|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3794632/46263b9a-872f-4391-483c-76d55e7629d8.png)|
|2|左のメニューの下の方にある、「**詳細設定**」に移動します。|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3794632/696b3902-9648-6ef8-ffa2-19d53c65b0bd.png)|
|3|「**開発者モード**」を`on`にします。|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3794632/ac670931-2a09-575c-10b6-cd8552c42146.png)|
|4|右クリック (スマホの場合は長押し) でidをコピーすることができるようになります。|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3794632/dece970c-aaa1-aa8f-9ec4-a82818b6d318.png)|

### メソッド
```js:index.js
const channel = client.channels.cache.get("チャンネルid"); //チャンネルidからチャンネルを探す
if (!channel) return; //チャンネルが見つからなかった場合、処理を中止

await channel.send("チャンネルが見つかったので、メッセージを送信しました！"); //チャンネルに送信する
```
このメソッドを使用すれば、チャンネルにメッセージを送信することができます。

## メッセージに対して、返信する
メッセージに対して返信するには、メッセージイベントを受け取ったときに、返信する必要があります。
今回はイベントについての説明は省きますので、[こちら](https://qiita.com/minoru_kinugasa/items/37a8d20c6569c73f938a)をごらんください。

### メソッド
```js:index.js
const { Client, GatewayIntentBits } = require('discord.js');
const { token } = require('./config.json');
const client = new Client({
    intents: [
        GatewayIntentBits.Guilds,
        GatewayIntentBits.GuildMessages,
        GatewayIntentBits.MessageContent
    ]
});

client.on('messageCreate', async (message) => { //メッセージが送信されたとき
    if (message.author.bot) return;
    await message.reply("これは返信メッセージです！"); //返信メッセージを送信する
});
```
少し複雑ですが、メッセージが送信されたときに、そのメッセージに対して返信するようになっています。

## ユーザーを探して、ダイレクトメッセージを送信する
### メソッド
```js:index.js
    const guild = client.guilds.cache.get("サーバーのid"); //ユーザーが居るサーバーの取得
    if (!guild) return; //サーバーが見つからなかったら処理を中止

    const member = await guild.members.fetch("ユーザーのid"); //サーバーからユーザーの取得
    if (!member) return; //ユーザーが見つからなかったら処理を中止

    await member.send("ダイレクトメッセージを送信しました。");
```
これで、特定のユーザーにダイレクトメッセージを送信することができます。

# 終わりに
今回は、メッセージの送信方法についての説明をしました！
メッセージには、添付ファイルを送ったり、埋めこみというものを送信することができます。
また長くなってしまうので、それは別の記事に記載します！

- [埋め込みについて](https://qiita.com/minoru_kinugasa/items/297cef8531e81a50343f)
- [添付ファイルについて](https://qiita.com/minoru_kinugasa/items/a6ffc040e52fca8e04aa)
- [メンションについて](https://qiita.com/minoru_kinugasa/items/2b26f6d2006f9f105601)
ログインしている時間帯をカウントするレポート



+ [どの時間帯にログインしているかがわかるレポートを作成したい](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007eoTyw)


まず、以下のヘルプを参考にユーザのレポートを選択してください。 

 

ユーザーログインレポートを作成する (Lightning レポートビルダー)
1. 「レポート」 タブで、「新規レポート」をクリックします。
2. [レポート タイプの選択] ボックスで、  [ユーザー]レポート タイプを選択し、[続行]をクリックします。
3. 目的のフィールドをレポートにドラッグし、各列の上部にあるセレクターを使用して適切なグループを選択します。「ログイン日」フィールドを含めます。 

https://help.salesforce.com/s/articleView?id=000385621&type=1


続きとしてはログイン日時というカラムがあると思いますので、これを行レベル数式で使います。Case関数でhourで求めた時間で場合分けしていきます。

一度もログインしていないユーザはNULLになっているので、場合わけしておきます。

```
IF( ISBLANK(LOGIN_DATETIME),null,
CASE(HOUR(TIMEVALUE(LOGIN_DATETIME + 9/24)),
9,"09:00~12:00",
10,"09:00~12:00",
11,"09:00~12:00",
12,"09:00~12:00",
13,"13:00~15:00",
14,"13:00~15:00",
15,"13:00~15:00",
16,"16:00~18:00",
17,"16:00~18:00",
18,"16:00~18:00",
"18:00以降")
)
```

レポートは以下のような感じ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/6ef07992-e562-364d-69e0-60d8a126f5f1.png)

検索条件

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/d16b3035-a56b-9e57-6371-01236cf31b2d.png)


+ [月間のコミュニティユーザーログイン回数確認レポートを作成したい](https://trailhead.salesforce.com/trailblazer-community/feed/0D5KX00000PXE0k)
bokeh: `MultiChoice` widgetを使って、特定の折れ線を目立たせる

# 環境
* Python 3.12.1
* bokeh 3.4.2

# やりたいこと
bokehを使って、10本以上の折れ線を描画しています。

```python
import bokeh
import numpy
from bokeh.plotting import figure, output_file, save
import bokeh.palettes


x_data = numpy.arange(-20, 20, 0.1)
palette = bokeh.palettes.Category10[10]
fig = figure(x_axis_label="x", y_axis_label="y", width=600, height=400)

for i in range(10):
    legend_label = f"y=sin(x + {i})"
    fig.line(
        x_data,
        numpy.sin(x_data + i),
        color=palette[i],
        legend_label=legend_label,
    )

fig.legend.click_policy = "hide"
# 凡例をグラフの外に配置する
legend = fig.legend[0]
fig.add_layout(legend, "left")

output_file("graph1.html")
save(fig)
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/37903/b63afe3b-05cf-fc9d-a6b5-dc0afb78b7ca.png)

折れ線が重なり合っているので、たとえば `y=sin(x + 5)`の折れ線がどれなのか、ぱっと見分かりません。
なので、特定の折れ線を目立つように表示したいです。

# やったこと
[MultiChoice](https://docs.bokeh.org/en/3.0.0/docs/user_guide/interaction/widgets.html#multichoice) widgetを使って、折れ線を選択できるようにしました。
選択された折れ線は、線を太くして目立たせました。


```python
import bokeh
import numpy
from bokeh.plotting import figure, output_file, save
import bokeh.palettes
from bokeh.models import CustomJS
from bokeh.models.renderers.glyph_renderer import GlyphRenderer
from bokeh.models.widgets.inputs import MultiChoice
from typing import Final

DEFAULT_LINE_WIDTH: Final[int] = 1


def create_multi_choice_widget(line_glyphs: dict[str, GlyphRenderer]) -> MultiChoice:
    args = {"lineGlyphs": line_glyphs}
    SELECTED_LINE_WIDTH: Final[int] = 4

    code = f"""
    const selectedLegendLabel = this.value;
    for (let legendLabel in lineGlyphs) {{
        if (selectedLegendLabel.includes(legendLabel)) {{
            lineGlyphs[legendLabel].glyph.line_width = {SELECTED_LINE_WIDTH};
        }} else {{
            lineGlyphs[legendLabel].glyph.line_width = {DEFAULT_LINE_WIDTH};
        }}
    }}
    """

    options = list(line_glyphs.keys())
    multi_choice = MultiChoice(options=options, title="Find:", width=300)
    multi_choice.js_on_change(
        "value",
        CustomJS(code=code, args=args),
    )
    return multi_choice


x_data = numpy.arange(-20, 20, 0.1)
palette = bokeh.palettes.Category10[10]
fig = figure(x_axis_label="x", y_axis_label="y", width=600, height=400)

line_glyphs: dict[str, GlyphRenderer] = {}
for i in range(10):
    legend_label = f"y=sin(x + {i})"
    line_glyphs[legend_label] = fig.line(
        x_data,
        numpy.sin(x_data + i),
        color=palette[i],
        legend_label=legend_label,
        line_width=DEFAULT_LINE_WIDTH,
    )

fig.legend.click_policy = "hide"
# 凡例をグラフの外に配置する
legend = fig.legend[0]
fig.add_layout(legend, "left")

output_file("graph.html")
multi_choice_widget = create_multi_choice_widget(line_glyphs)
save([fig, multi_choice_widget])

```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/37903/b9b09779-e9cc-0cbc-0387-8048c96b288c.png)

折れ線を選択すると、線が太くなり目立つようになりました。また凡例に表示されている線も自動的に太くなりました。


# 関連するサイト
https://qiita.com/yuji38kwmt/items/3da82782c6f32f868720

https://qiita.com/yuji38kwmt/items/10a52f348dfb20ab4018
【一口メモ】:before :afterなどで指定したcontentが文字化けするときの対処法

# 困ったこと
beforeやafter疑似要素のcontentプロパティで，文字化けするとき（特に日本語）がある。
```html:index.html
<head>
    <!--いろいろ省略-->
	<meta charset="utf-8">
    <link rel="stylesheet" href="style.css">
    <!--いろいろ省略-->
</head>
<body>
    <div>100</div>
</body>
```
```css:style.css
div :after {
    content: "年";
}
```
#### 実行結果例
100蟷ｴ

# 解決策
linkタグにcharset="utf-8"を加える。
```html:index.htmlのうち変更部分
    <link rel="stylesheet" href="style.css" charset="utf-8">
```
#### 実行結果例
100年
【開発者向けQA用語解説】シフトレフト【Vol.1】

## はじめに
現在のソフトウェア開発において、開発とQAは密接な関係にあります。
それこそ、手を取り合ってプロジェクトを進めていくのが基本となりつつあります。
しかし、開発の専門性が高いようにQAも専門性が高く、用語や意図がわからない場面は多々あるでしょう。
そんな方のため、用語の解説を行っていくシリーズです。
また、本記事は私の独断と解釈によるまとめですので、一部事実と違う点があるかもしれませんが、その際はご指摘ください。

## 「シフトレフト」のざっくりとした解説
### 「シフトレフト」の概要
開発という「作る」という作業に対して、「確認する」という作業をより早い段階から実施することを指します。
この「確認する」という作業は「テスト」(Testing)だけでなく「レビュー」(Checking)なども含みます。

### 「シフトレフト」の主なメリット
「問題が見つかった時、修正にかかるコストの低減」がシフトレフトの主なメリットです。

### 「シフトレフト」のお試し方法
概要に記載している通り、レビューを今より早期に実施するだけでも効果があるので、QAを巻き込まなくとも開発チーム内で完結することができます。
チームを動かすのが難しくとも、個人単位なら、いつものレビューの実施前に「ちょっと先に確認させてください」と先輩などの詳しい人へ早めに聞くだけでも効果を発揮します。

## 「シフトレフト」の詳細な解説
### 品質関連書籍からの引用
まずは私自身の言葉で説明するよりも正確性を大事に、世に出ている公的な書籍から引用しようと思います。
今回は「シラバス2018対応JSTQBFoundation教科書＆問題集」より引用します。
> ソフトウェア開発ライフサイクルのなるべく早い時期にテストすること。
> 早い段階でテストを実施すればするほど、欠陥の数が少ないため、1つの欠陥が多くのコンポーネントに入り込むことを未然に防ぐことができ、大きなコスト削減につながる。

私も驚いたのですが、手元には何冊かQAの参考書があるのですが、シフトレフトについての記載はこの1冊だけでした。
QAQEよりQCの面が強く、QAの参考書では詳細に語られることが少ないのかもしれません。

### 何に対して「左」なのか
「シフトレフト」という言葉を聞いて、まずはその字面の意味のわからなさが大きいと思います。
「左に行く」ことはわかると思いますが、何を指して左方向なのかが不明瞭かと思うので、そこから解説します。

古くはウォーターフォールという開発手法が世の代表だった時に生まれました。
ウォーターフォール開発はその名の通り、一方通行で行ったっきりの開発フローです。
図で表すと以下のような流れです。

![ウォーターフォール開発手法.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3565882/2c442090-47b0-7154-121c-af61648442fb.png)

「ウォーターフォールって言うんだから左から右じゃなくて上から下だろう」「上流工程/下流工程と言うじゃないか」というツッコミは、私も本当にそう思います。
そう思いますが、シフトレフトと言うので左から右に描き直しました。

![ウォーターフォール開発横.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3565882/d2d6a8e7-abef-bc1a-6785-3f329ea3debd.png)
この図で見ればわかりますが、元の「テスト」のフェーズよりも左側でもテストを実施する、ということで「シフトレフト」と呼ばれています。

### 「シフトレフト」の詳細なメリット
ざっくりの方で「問題が見つかった時、修正にかかるコストの低減」と書きましたが、
そうなる理由は、開発フローのより早期にバグを発見できた方が、
バグの修正にかかるコストは基本的に低くなるためです。

バグの発見タイミングによるコストのかかり方は、引用を見るのが早いでしょう。
これはIPAの出している[先進的な設計・検証技術の適用事例報告書 2015 年度版PDF](https://www.ipa.go.jp/archive/files/000049404.pdf)の画像です。
> ![スクリーンショット 2024-04-10 183426.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3565882/f826d465-5f0b-99c2-8348-56b97eab14d9.png)

もしかしたら見たことがある方もいらっしゃるかもしれません。
要求仕様で誤りがあったことを見逃して、そのままリリースまで行ってしまった場合、一般的に修正にかかるコストは200倍になると言われています。
テストまでだったとしても20倍になります。

設計段階で気付いたら、要求仕様のミーティングの再設定と他設計の変更程度で済みますが、
遅くなるにつれて、それまでの作成にかけた工数が上乗せされて行きます。

納入で一気に跳ね上がるのは、
・不具合原因の調査
・修正までの間の一時対応の策定や実行
・修正を入れた再テスト
・修正の再リリース
と、リリースまでのコストがもう一度かかりつつ、
そもそも不具合がどこにあるのかの調査コストもさらにかかってくるからです。

そして画像に書いてある通り、200倍は修正コストに限った話です。
納入まで行ってしまった場合、修正コスト以外にも、
・お客様からの問い合わせを受けるサポートセンター等のフロント部門
・迷惑をかけたお客様への謝罪
・ものによっては会社の信用失墜
など、関わってくる人や領域、作業が莫大になりますので、
実質は200倍には留まらないでしょう。

そして、人や領域、作業が増え、通常とは違う手順を踏むということは、
それだけ別の問題や、新たなオペレーションミスを誘発することになり、
より延焼していく可能性すらあります。

ですので、同じバグであっても、見つけられるならより早期である方がよいのです。

### 「シフトレフト」の導入方法
別記事で他とセットで詳細を記載しようと思っていますが、
シフトレフトとは**導入しようと思って導入するものではありません**。
品質向上のため、不具合をより発見しやすくするため、修正コストを下げるため、
そういった問題を解決するための**手段の一つ**だからです。
何でもかんでも「シフトレフトだ！」で解決できるわけではないということまでを、
本記事ではご理解いただければ幸いです。


### 「シフトレフト」に纏わる小噺
「シフトレフトテスト」とも言います。
おそらくは、この言葉が生まれた時は「テストフェーズをシフトレフトする」ということで、「シフトレフトテスト」と言われたのではないでしょうか。
ただ、こう言ってしまうと「テスト(Testing)だけをシフトレフトすればOK」と
思われてしまいそうなので個人的には使いたくないです。
先述の通り「問題を解決するため、早期に実施する」ということが真髄ですので、
「シフトレフト」すべき対象はテスト(Testing)に限りません。

その他にも「テストって付いてるから、QAや品質管理側が全部やるんでしょ」と、
誤解を生みかねないため、やはり使いたくないです。
[T-DASH] APIのテストを混在したUIテスト自動化をする

# Outline

APIのテストを行う場合、SoapUIやPostManといった、APIに特化したテスト自動化ツールが存在する。
ただ、WebのUIと連携して、例えばデータ更新の結果をAPI経由で検証したいとき、APIを混在させてテストしたいケースもある。

https://www.postman.com/

T-DASHはUIのテストに強いテスト自動化ツールである。しかし、カスタム動作を用いることで、APIのテストを合わせて行うことが可能になる。

https://service.valtes.co.jp/t-dash/

# 技術的な情報

robot frameworkのAPIを用いたテストを行うライブラリとして、RESTinstanceがある。このkeywordを用いて値の取得や更新、そしてAPIで取得した結果（多くはXMLかJSON）を検証することができる。

https://asyrjasalo.github.io/RESTinstance/


主に使うkeywordとして以下のものがある

| 種類 | keyword | 内容 |
|:-----------|:------------|:------------|
| リクエスト       | GET        | get形式でAPIにリクエストする         |
| リクエスト       | POST        | post形式でAPIにリクエストする         |
| 検証       | Object        | APIの結果のJSONに関する検証する         |
| 検証       | Integer        | APIの結果で整数に関する検証する         |
| 検証       | String         | APIの結果で文字列に関する検証する        |

# テスト対象

楽天は、ユーザーが使えるウェブサービスとしてAPIを提供している。
今回、シンプルにトラベル施設検索の結果から検索結果数を変数として取り出し、テストケースにてつかうテストを想定する。
尚、楽天ウェブサービスを使う場合、menuのnew appから、application idを取得する必要がある。
APIでこのidが求められる。

https://webservice.rakuten.co.jp/documentation/simple-hotel-search

APIの結果、bodyに以下JSONが出力される。
このJSONから、recordCountの値、下図の例では72を取り出す。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/267085/0add2c8f-4007-e38c-2a84-ffbfa7fcc92b.png)


# T-DASH


## カスタム動作

API.yaml で、以下内容を保存する

```
ACT-CAT-CUSTOM-5ffd6219-579c-47d4-9325-75a203bc6888:
  action_category_name: API
  icon: ''
  color: '#b9d4b8'
  custom_data:
    file_name: API
    pip_list:
    - RESTinstance
    library_list:
    - REST
  actions:
    ACT-CUSTOM-1a0b0841-8c40-4242-9087-4fd06b2a065f:
      action_name: 楽天トラベル施設検索結果数
      action_type: operation
      action_format: 緯度,経度 =(「設定値1」,「設定値2」) 半径「設定値3」kmで検索
      action_note: ''
      action_args:
      - value1
      - value2
      - value3
      action_def:
      - - '${applicationId} = '
        - Set Variable
        - xxxxxxxxxx
      - - GET
        - https://app.rakuten.co.jp/services/api/Travel/SimpleHotelSearch/20170426?applicationId=${applicationId}&format=json&latitude=${value1}&longitude=${value2}&searchRadius=${value3}
      - - Integer
        - response status
        - '200'
      - - Object
        - response body
      - - ${json} =
        - Object
        - response body
        - required=["pagingInfo", "hotels"]
      - - '${recordCount} = '
        - Set Variable
        - ${json[0]['pagingInfo']['recordCount']}
      - - Log
        - search result count is ${recordCount}

```

次に、作成されたChromeOpti.yamlをT-DASHの動作定義 -> カスタム動作 -> カスタム動作をインポート にてインポートし、実際にインポートされた設定内容を開く


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/267085/9fcbe1fd-f1e9-8dde-df09-a59d2192972c.png)

## テストケース

カスタム動作を呼び出すと、APIをCALLし、検索結果数を取り出す。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/267085/d0000678-f257-792f-4151-c07c00c02d25.png)

カスタム動作の設定値１～３は以下のとおりである

| 引数 | 意味 | 
|:-----------|:------------|
| 設定値1       | 緯度        | 
| 設定値2       | 経度        | 
| 設定値3       | 半径 (km)        |
Bubble 1を0001みたいにnumberの桁数を揃えたtextにするやり方　ゼロパディング

1を0001とかにすることを　”zero padding”　”ゼロパディング”という

<img width="500" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/47236/e29f7cbf-bcfc-5e34-6c28-7d76b7bbf97f.png">

## やり方
1. numberを”formatted as”するとstrになる
. <img width="300" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/47236/2ab0b89b-dad5-bfb1-78f9-68a622b9a54c.png">

1. "find & replace"で先頭に0000を追加。表示したい桁数-1以上
 .<img width="300" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/47236/4c4ffbe7-a1d7-f7e3-8275-0c41fc9cec07.png">

1. "trancated from end to" で表示したい桁を設定